How to map Windows ACL to Linux ones on a CIFS share?

Context

We have a Windows server with an Active Directory domain and a network share.

I have a Linux machine and I want to mount the share.

sudo mount -t cifs //server/share /mnt/share -o user=[act-dir user],domain=[domain],uid=[linux user],gid=[linux group]

It's more or less OK. My Linux user gets mapped to all files on the share and some of the ACL are translated. But I want to go a level further:

  • More than one user is connected to the Linux box
  • Each Linux user has a dedicated Active Directory account
  • I want each Windows owner to be mapped to the corresponding Linux owner if it exists

A solution and the problem

Samba offers the mount option cifsacl which requires to set-up cifs.idmap and winbindd. Both are installed, I've read both man pages and tried to configure them but it does not work. The newly mount command is now:

sudo mount -t cifs //server/share /mnt/share -o user=[act-dir user],domain=[domain],cifsacl

But everything is mapped to root:root, which means the cifs.idmap could not be performed.

Actually, I'm not all surprised because I did not understand where to write the actual mapping so where should I write that Windows userX actually maps to Linux userY? And I'm not sure that the winbindd configuration is correct, what should be the minimum set of parameters and is smbd and/or nmbd require to run? Do I need to open the port in the firewall?

Background infos

Share structure

The shared directory has several sub directories, some commons and some "privates" (although the private ones are actually readable by everyone). Each user would need to access from time to time the common space, and also other user private directories, but mainly/often their own directory.

Tech data

  • RHEL 6, Samba 3.5.6
  • Ubuntu 12.04, Samba 3.6.3

You would probably need to use the username map functionality inside samba (winbind) for the mapping to work so that winbind knows about the AD account for every Linux user. I believe username map can take commands and lists (and some pattern conversions), but it's far easier if the Linux usernames can match the AD usernames, by using pam_winbind for instance. I guess that when the mapping is working you can actually start verifying whether the share is working as well.


How to set up a CIFS Multiuser Mount

CIFS is a session-based protocol. This means that the session runs with the privileges of the user who logged on for the CIFS session. Therefore, the normal way of using CIFS is to mount the shares at user login time with the privileges of the user logging in. This is what the protocol was designed for.

Nontheless, the Linux CIFS driver offers a way to mount the share at startup time already. This is called a multiuser mount. The strategy for a multiuser mount is to mount the share at startup time with minimal privileges. For every user accessing the share, the CIFS driver will internally create a separate CIFS session with the server.

When a user accesses the multiuser-mounted share for the first time, the CIFS driver needs to create a CIFS session with the fileserver for this user. This requires security information, e.g. a username and a password. Because the driver cannot prompt for login data, it will look into the kernel keyring for the current Linux user. If a suitable security information can be found, then the CIFS driver will use it to create a CIFS session for the current user with the fileserver and the user can access the share.

This post may look like a howto, but in fact it is meant as a collection of possible pitfalls.

Step 1: Create a share SHARE at the fileserver FILESERVER and a local user CIFS_GUEST on the fileserver with minimal privileges. The user must only be allowed to mount the share from a remote machine. The password of the user must never expire.

Notes & Pitfalls:

  • The user does not need to be in the local "Remote Desktop Users" group of FILESERVER.
  • If the share SHARE is a so-called "administrative share", then the users (including CIFS_GUEST) would have to have administrative privileges. It is recommended to create a share of the normal, non-administrative type.

    Step 2: Mount the share from your Linux machine, e.g.

    mount.cifs //FILESERVER/SHARE /mnt --verbose -o domain=FILESERVER,username=CIFS_GUEST

This should mount the share properly. If not, I recommend a look at the manpage mount.cifs(8).

Notes & Pitfalls:

  • Make sure to specify the option domain=FILESERVER. Otherwise, the fileserver may assume that CIFS_GUEST is a domain (non-local) user and deny access.
  • If you run into trouble with authentication, check the logs of the server(e.g. Windows event logs in case of a Windows fileserver)
  • You may want to add the mount option noperm to disable permission checking on the client side. The permissions are enforced by the server anyway.

Step 3: Mount again with the multiuser option:

umount /mnt
mount.cifs //FILESERVER/SHARE /mnt -v -o multiuser,domain=FILESERVER,username=CIFS_GUEST

Verify that multiuser has been used:

mount | grep cifs

Step 4: Create a credentials file for automatic, non-interactive mounting. Protect it against all non-root access.

File contents of /etc/cifs.SHARE.cred:

username=CIFS_GUEST
password=<pass>
Domain=FILESERVER

Then execute:

chown root /etc/cifs.SHARE.cred
chmod 600 /etc/cifs.SHARE.cred

Notes & Pitfalls:

  • Make sure that the credentials file does not contain a byte order mark (BOM) when using UTF-8 encoding. Otherwise you may get a spurious "Credential formatted incorrectly" message from mount.cifs.

Step 5: Try to Mount the share with the credentials file. This should be completely non-interactive now:

umount /mnt
mount.cifs //FILESERVER/SHARE /mnt -v -o multiuser,credentials=/etc/cifs.SHARE.cred

If this works, you can add the mount to /etc/fstab:

...
//FILESERVER/SHARE /mnt cifs rw,auto,multiuser,credentials=/etc/cifs.SHARE.cred 0 0
...

Notes & Pitfalls:

  • The option auto has been added for automatic mounting of the share.

Step 6: Login as normal user at the Linux machine now. Try to access the mounted share, e.g.

cd /mnt
ls

The permission should be denied.

Then, manually store CIFS credentials in the session keyring:

cifscreds add FILESERVER -u <username>

You will be prompted for a password. Afterwards, you should be able to access the share, if <username> has access permission for the share on the fileserver.

Notes & Pitfalls:

  • You can use your Windows Explorer to verify that <username> has Access permissions for the share. This way, you can rule out that the error is on FILESERVER.
  • If cifscredsgives a warning about a non-persistent session keyring, then type keyctl session and try again.
  • You can display the contents of the keyring with keyctl show -3.
  • The cifscreds will not create the CIFS session with the fileserver. It merely puts security info into the keyring, so that the CIFS driver can use it to create a CIFS session when you access the share. This means that changing the key in the keyring with cifscreds update ... will leave you logged on with the old user (!).

Step 7: Finally, the step of feeding the keyring can be automatized. As root, add the following lines to your PAM configuration (e.g. /etc/pam.d/login):

...
auth optional pam_cifscreds.so debug
...
session optional pam_cifscreds.so domain=<AD Domain> debug
...

The first line captures the password on login. The password is stored until the session is created. When the session is created, then the second line will put the record into the keyring. There will be no need to call cifscreds and the share should be accessible immediately after login.

Notes & Pitfalls:

  • You may want to remove the debug option after testing to reduce logging verbosity.
  • Make sure that both lines are executed in every case in the PAM stack. (sequence of entries in the configuration file)
  • You can replace the optional with required to enforce authentication with the fileserver.
  • Before the second line, the existence of a permanent session keyring should be ensured. If in doubt, add the following line immediately before the second line: session required pam_keyinit.so
  • Both lines should leave a messages in the system logs when using the debug option.
  • The same modifications should also be made to the configuration of other PAM-Aware login programs, e.g. to /etc/pam.d/sshd, /etc/pam.d/xdm, ...

Up to this point, the access permissions to files and folders on the share are enforced by the FILESERVER. The permissions, user names and group names displayed on the Linux side are completely wrong. In order to get them properly, add the mount option cifsacl and set identity mapping. However, this probably requires, among other things, setting up the Winbind Service. Additional information can be found in the manpage mount.cifs(8).