11.1. The Linux CIFS Filesystem
We'll begin by exploring the new CIFS filesystem included in the Linux 2.6 kernel. A patch for 2.4 kernels is available from the project's web site at http://linux-cifs.samba.org. Here you will also find the latest released source code, which may not have been integrated into the mainline kernel tree yet. We won't go into the details of compiling a Linux kernel. If you require details about how to do this, Running Linux, by Matt Welsh et al., or Linux Kernel in a Nutshell, by Greg Kroah-Hartman (O'Reilly) are good places to find out more.
Linux's original SMB/CIFS filesystem client, named smbfs , was written by Volker Lendecke, an active Samba developer. The cifs kernel VFS module has since superseded smbfs. However, there is still some confusion among Linux users and admins alike which one should be used. The smbfs kernel module and user space tools (smbmount, smbumount, and smbmnt) will likely continue to be included in Linux and Samba for some time, but none of these pieces has an active maintainer. Therefore any reported bugs will very likely not be fixed. If you have Linux systems that are currently set up to use smbfs, now is a good time to begin thinking about migrating them to use the cifs module instead.
The primary difference between the cifs and smbfs kernel modules is that cifs was originally written to work only against servers running Windows NT 4.0 or later (as well as Samba servers). In the 2.6.15 Linux kernel, however, cifs picked up support for connecting to shares on Windows 9x/Me hosts, which makes it only a matter of time before the smbfs code is removed entirely.
The Linux CIFS filesystem is composed of two parts: the kernel code (referred to by the name of the kernel module, cifs) and the user-space mount tools. The cifs kernel filesystem support is generally built as a module and loaded when a user attempts to connect to an SMB/CIFS file server using the mount command. The easiest way to tell whether your Linux host possesses cifs support is to examine the contents of /proc/filesystems. Check this file and look for the term cifs listed in the output:
$ cat /proc/filesystems | grep cifs nodev cifs
If grep fails to match anything in the file, try manually loading the cifs kernel module with the help of the modprobe command. You must run the following command as root:
$ modprobe cifs
If you are returned immediately to a shell prompt, the module loaded correctly. Examine /proc/filesystems again; cifs should be listed this time. However, if the kernel was built without the cifs feature enabled, you will see the following error:
FATAL: Module cifs not found.
Either rebuild the system's kernel and enable the cifs filesystem, or (if you obtained your system through a license with a vendor) contact your vendor to receive a new kernel.
Next verify that the cifs mount and unmount utilities have been installed as /sbin/mount.cifs and /sbin/umount.cifs, respectively. If the files do not exist, check that you have the appropriate packages installed. Novell provides a separate cifs-mount RPM, and Red Hat includes the two binaries in their samba-client package. Debian, ironically enough, includes the cifs mount tools in the smbfs package.
Because the source files for mount.cifs and umount.cifs are included in the Samba source tree, you can manually build both tools by running these commands:
$ gcc -o mount.cifs client/mount.cifs.c $ gcc -o umount.cifs client/umount.cifs.c
You should then copy these files to the /sbin directory. Running the following commands as root ensures that the utilities are installed with the correct ownership and permissions:
# cp -p mount.cifs umount.cifs /sbin # chown root.root /sbin/mount.cifs /sbin/umount.cifs # chmod 755 /sbin/mount.cifs /sbin/umount.cifs
Manpages for both mount.cifs and umount.cifs are included with the Samba distribution files, and additional information is available in the fs/cifs/README file included in the Linux kernel source tree.
11.1.2. Mounting a SMB/CIFS File Share
You now have the pieces in place to mount a SMB/CIFS share as part of your local filesystem. Mounting filesystems is normally restricted to the root account. We'll show you how to allow users to mount and unmount SMB/CIFS shares shortly. For the moment, make sure to run the mount and umount commands as root. The general syntax for accessing a SMB/CIFS file share is:
$ mount -t cifs //server/share mount_point [-o options ]
The -t option specifies the filesystem type (cifs) and enables mount to know what external helper in the /sbin directory should be invoked (i.e., mount.cifs) to access the remote filesystem. The //server/share format is identical to what we've shown when using smbclient in prior chapters. The mount_point is the path to a local directory where the share will be mounted. Numerous options can be specified with the -o flag. One common value is the login name of the account used to connect to the remote server: user=name. If you do not specify this option, mount.cifs uses the value found in the USER environment variable.
Here is an example of connecting the share public provided by the Windows XP host fox to the local directory /cifs/public. Because mount.cifs does not use NetBIOS name services, it is assumed that the hostname fox can be resolved to an IP address using a simple lookup in /etc/hosts or a DNS query. If this is not the case, you may specify the remote server's IP address using the ip=aaa.bbb.ccc.ddd option. The user zoe is a local account on the Windows system.
$ mount -t cifs //fox/public /cifs/public -o user=zoe Password: <enter password for zoe>
The underlying mount.cifs helper prompts for a password if one is not provided in some other form. There are three methods for handling noninteractive mount requests. The first is to specify the password on the command line using the pass=password option. Using this option, our original mount request would appear as follows:
$ mount -t cifs //fox/public /cifs/public -o user=zoe,pass=FY23d^g
The second possibility is to store the password string in the environment variable PASSWD or to store it in a file specified by either the PASSWD_FD or PASSWD_FILE variable. If you use this option, make sure to export the variable to the environment so that it will be available to mount.cifs. This method can be useful when issuing mount requests from a script, but be careful to not leave passwords lying around in the environment where they can be read by other users.
The final possibility is to store the username and password in a file referenced by the cred parameter and read by mount.cifs at startup. Each line in the credentials file consists of a parameter=value pair. The three supported parameter values are:
In order to convert the original mount request to use the cred option, first create a file named .cifsrc in root's home directory containing the following lines:
Notice that the domain was omitted in this listing. Any of the three parameters not specified in the credentials file may be defined as a command-line argument if desired.
Protect the .cifsrc file with permissions that prevent others from reading the file, such as the octal permissions 600. Now the mount command listing no longer includes the username or password on the command line for other users to see:
$ mount -t cifs //fox/public /cifs/public -o cred=$HOME/.cifsrc
Running mount with no arguments lists all mounted filesystems, included the cifs share that was just connected:
$ mount <...output deleted...> //fox/public on /cifs/public type cifs (rw,mand)
Once the share has been mounted you can access files using normal tools:
$ cd /cifs/public $ ls -l total 4392 drwxrwxrwx 1 root root 0 Jul 23 2006 . drwxr-xr-x 4 root root 4096 Jul 23 13:43 .. -rwxrwSrwt 1 root root 2986038 Sep 1 2005 lastgold.bmp -rwxrwSrwt 1 root root 239023 Jul 22 04:30 lookupsid.pcap <...remaining output deleted...> $ echo "hello" > foo.txt $ cat foo.txt hello
When you mount shares from Windows servers, all files and directories will be reported as being owned by the user that mounted the share, and the group ownership will reflect the user's primary group. In our example, the user and group were root. When the cifs client connects to servers that support the CIFS Extensions for Unix, such as Samba, it reports the correct ownership and file permissions. (More on this in the next section.) Barring such support, you can control the reported ownership using the uid and gid parameters when mounting the share. Each accepts either the name or numeric id of a respective user or group on the local Linux host. To see how this works, first unmount the share from /cifs/public:
$ umount /cifs/public
Next, mount the share again, but this time add the options uid=zoe and gid=users to report files as being owned by zoe and the group users:
$ mount -t cifs //fox/public /cifs/public -o user=zoe,uid=zoe,gid=users Password: <enter password for zoe>
Now, when listing the files, the ownership and group ownership is displayed as requested by the uid and gid mount options:
$ ls -l /cifs/public total 4392 drwxrwxrwx 1 zoe users 0 Jul 23 2006 . drwxr-xr-x 4 root root 4096 Jul 23 13:43 .. -rwxrwSrwt 1 zoe users 2986038 Sep 1 2005 lastgold.bmp -rwxrwSrwt 1 zoe users 239023 Jul 22 04:30 lookupsid.pcap <...remaining output deleted...>
You probably also noticed the file permissions in the previous listing. Without help, cifs has no way of mapping Windows file ACLs to POSIX permissions. The file_mode and dir_mode options allow you to specify the permissions reported by the kernel for files and directories. By defining file_mode=0640 and dir_mode=0755 when mounting \\fox\public, you can restrict files from being accessed by accounts outside of root, zoe, and the users group, while still allowing everyone to scan the filesystem:
$ ls -l /cifs/public drwxr-xr-x 2 zoe users 0 Jul 23 2006 docs -rw-r----- 1 zoe users 2986038 Sep 1 2005 lastgold.bmp -rw-r----- 1 zoe users 239023 Jul 22 04:30 lookupsid.pcap <...remaining output deleted...>
The uid, gid, file_mode, and dir_mode options control the file attributes used by the Linux kernel when performing authorization checks. In reality, there are two access checks for every file. The server uses the file's security descriptor to verify that the connected user has the appropriate access rights, and the Linux kernel determines whether the local user should be granted access based on the calculated Unix permission set. So if the user who connected to the share is not authorized by the server's permissions to access a file, no amount of tweaking permissions on the client will give him access to it.
Table 11-1 completes this section by listing the common parameters to mount.cifs we've covered. Be sure to consult the utilities' manpage for a current list of options.
11.1.3. Allowing Normal User CIFS Mounts
Windows clients allow normal users to map a UNC path to a drive letter such as H:. Linux users frequently expect this same capability. In order to allow non-root users to mount SMB/CIFS file shares using mount.cifs, you have two options. The most flexible solution for users is to add the setuid bit for both mount.cifs and umount.cifs so the users are able to call mount.cifs directly instead of mount -t cifs. The remaining command-line arguments needed to mount a SMB/CIFS share are the same. To enable the setuid permission bit, run the following commands while logged in as root:
$ chmod u+s /sbin/mount.cifs /sbin/umount.cifs
Some administrators are uncomfortable with setuid binaries. To be fair, this is an extremely powerful privilege to grant to a program. Any potential flaws in the utility could be leveraged by an attacker to gain superuser privileges on the system.
The alternative method of allowing user mounts is to add a line to /etc/fstab referencing the remote filesystem and target mount point, and specifying the user mount option. The user option in this context is not the same as the mount.cifs user parameter. For example, the following line allows normal users to mount /cifs/cdrom from the UNC path \\media.example.com\cd. The noauto directive is used to prevent the filesystem from being mounted at boot time. Rather than placing it in /etc/fstab, the username sent in the SMB/CIFS connection request is pulled from the USER environment variable.
//media.example.com/cd /cifs/cdrom noauto,user 0 0
A non-root user can now simply invoke mount /cifs/cdrom to access the CD-ROM shared by the host media.example.com. More details regarding defining user mounts in /etc/fstab can be found in the mount and fstab manpages.
11.1.4. CIFS Extensions for Unix Clients
It is easy to view SMB/CIFS as a Windows protocol. Its history, however, extends before and beyond Microsoft. Although CIFS is not an open standard, extensions to the protocol have been developed and documented. These include the Mac extensions and the Unix extensions, both of which are described in the CIFS Technical Reference from the Storage Network Industry Association (http://www.snia.org).
The Unix extensions, as they are commonly called, were first developed in 1996 by Hewlett-Packard. Since then, they have received attention and updates from various companies and individuals, including Linux kernel engineers and Samba developers. The most notable features provided by these extensions are filename case sensitivity, symbolic links, POSIX locking semantics, and proper reporting of Unix ownership and permissions.
Both the cifs filesystem and Samba support the Unix extensions by default. Samba controls this behavior using the unix extensions Boolean parameter in smb.conf. You can manipulate Linux cifs client's support of the Unix extensions by flipping the value in /proc/fs/cifs/LinuxExtensionsEnabled between 0 and 1. The following command enables Unix extension support in the Linux client:
$ echo 1 > /proc/fs/cifs/LinuxExtensionsEnabled
The most visible enhancement to cifs provided by these extensions is the ability to report the correct ownership of files and directories. For example, the following cifs mount from a Samba host shows the real uid and gid ownership of files within the share:
drwxr-xr-x 4 rose users 0 Jun 3 10:09 iTunes drwxr-xr-x 11 lizard guest 0 May 22 16:27 Documents drwx------ 2 1217 hosts 0 Jun 15 11:05 vc6_sp5
The requirement for reporting correct ownership on cifs filesystems is the same as the one needed by NFS mounts: namely, that the uid and gid are assigned to the same user and group on both the client and server. In our example, both rose and lizard are the same on the client and server. However, the client has not assigned the uid 1217 to a user. The easiest way to handle common assignments for uids and gids is to make use of a directory service such as LDAP for distributing user and group information.
Table 11-2 provides a brief summary of the new smb.conf parameter.