UID/GID override on CIFS mounts to Samba and proposed new mount parameter to disable Unix Extensions on the client
From: Steve French
Date: Mon Apr 30 2007 - 10:26:36 EST
When CIFS Unix Extensions are negotiated we get the Unix uid and gid
owners of the file from the server (on the Unix Query Path Info
levels), but if the server's uids don't match the client uid's users
were having to disable the Unix Extensions (which turned off features
they still wanted). The attached patch allows users to override uid
and/or gid for file/directory owner with a default uid and/or gid
specified at mount (as is often done when mounting from Linux cifs
client to Windows server). The attached patch also displays the uid
and gid used by default in /proc/mounts (if applicable).
I also would like suggestions on what we should call a proposed mount
option (not coded yet) which would disable the CIFS Unix Extensions on
a per-mount basis (or more likely actually would require it on the
first mount to the server, subsequent mounts would probably inherit
the capabilities). Current cifs code can disable mount options before
a mount by specifying
"echo 0 > /proc/fs/cifs/LinuxExtensionsEnabled")
but it might be easier to specify it on mount (e.g.
"nolinuxextensions" or "linuxextensions=no" ?). Slightly harder
would be disabling Unix Extensions after the user has already mounted
(with Unix Extensions) to the same server (perhaps to a different
share). How important would it be to have two mounts to the same
server one with unix extensions and one without?
--
Thanks,
Steve
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 301631c..62dcf63 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -2,7 +2,11 @@ Version 1.49
------------
IPv6 support. Enable ipv6 addresses to be passed on mount (put the ipv6
address after the "ip=" mount option, at least until mount.cifs is fixed to
-handle DNS host to ipv6 name translation).
+handle DNS host to ipv6 name translation). Accept override of uid or gid
+on mount even when Unix Extensions are negotiated (it used to be ignored
+when Unix Extensions were ignored). This allows users to override the
+default uid and gid for files when they are certain that the uids or
+gids on the server do not match those of the client.
Version 1.48
------------
diff --git a/fs/cifs/README b/fs/cifs/README
index 080c5eb..93fe359 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -257,13 +257,19 @@ A partial list of the supported mount op
mount.
domain Set the SMB/CIFS workgroup name prepended to the
username during CIFS session establishment
- uid If CIFS Unix extensions are not supported by the server
- this overrides the default uid for inodes. For mounts to
- servers which do support the CIFS Unix extensions, such
- as a properly configured Samba server, the server provides
- the uid, gid and mode. For servers which do not support
- the Unix extensions, the default uid (and gid) returned on
- lookup of existing files is the uid (gid) of the person
+ uid Set the default uid for inodes. For mounts to servers
+ which do support the CIFS Unix extensions, such as a
+ properly configured Samba server, the server provides
+ the uid, gid and mode so this parameter should not be
+ specified unless the server and clients uid and gid
+ numbering differ. If the server and client are in the
+ same domain (e.g. running winbind or nss_ldap) and
+ the server supports the Unix Extensions then the uid
+ and gid can be retrieved from the server (and uid
+ and gid would not have to be specifed on the mount.
+ For servers which do not support the CIFS Unix
+ extensions, the default uid (and gid) returned on lookup
+ of existing files will be the uid (gid) of the person
who executed the mount (root, except when mount.cifs
is configured setuid for user mounts) unless the "uid="
(gid) mount option is specified. For the uid (gid) of newly
@@ -281,8 +287,7 @@ A partial list of the supported mount op
the client. Note that the mount.cifs helper must be
at version 1.10 or higher to support specifying the uid
(or gid) in non-numberic form.
- gid If CIFS Unix extensions are not supported by the server
- this overrides the default gid for inodes.
+ gid Set the default gid for inodes (similar to above).
file_mode If CIFS Unix extensions are not supported by the server
this overrides the default mode for file inodes.
dir_mode If CIFS Unix extensions are not supported by the server
diff --git a/fs/cifs/TODO b/fs/cifs/TODO
index b70a69b..78b620e 100644
--- a/fs/cifs/TODO
+++ b/fs/cifs/TODO
@@ -80,7 +80,7 @@ need to add ability to set time to serve
u) DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for this too)
-v) mount check for unmatched uids - and uid override
+v) mount check for unmatched uids
w) Add mount option for Linux extension disable per mount, and partial
disable per mount (uid off, symlink/fifo/mknod on but what about posix acls?)
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index fd1e52e..4cc2012 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -22,12 +22,14 @@
#define CIFS_MOUNT_SET_UID 2 /* set current->euid in create etc. */
#define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */
#define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */
-#define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */
-#define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
-#define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible. */
-#define CIFS_MOUNT_UNX_EMUL 0x80 /* Network compat with SFUnix emulation */
-#define CIFS_MOUNT_NO_BRL 0x100 /* No sending byte range locks to srv */
-#define CIFS_MOUNT_CIFS_ACL 0x200 /* send ACL requests to non-POSIX srv */
+#define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */
+#define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
+#define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible*/
+#define CIFS_MOUNT_UNX_EMUL 0x80 /* Network compat with SFUnix emulation */
+#define CIFS_MOUNT_NO_BRL 0x100 /* No sending byte range locks to srv */
+#define CIFS_MOUNT_CIFS_ACL 0x200 /* send ACL requests to non-POSIX srv */
+#define CIFS_MOUNT_OVERR_UID 0x400 /* override uid returned from server */
+#define CIFS_MOUNT_OVERR_GID 0x800 /* override gid returned from server */
struct cifs_sb_info {
struct cifsTconInfo *tcon; /* primary mount */
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index dd03e68..24eb0c5 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -306,6 +306,14 @@ cifs_show_options(struct seq_file *s, st
cifs_sb->tcon->ses->domainName);
}
}
+ if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
+ seq_printf(s, ",posixpaths");
+ if((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) ||
+ !(cifs_sb->tcon->ses->capabilities & CAP_UNIX))
+ seq_printf(s, ",uid=%d", cifs_sb->mnt_uid);
+ if((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) ||
+ !(cifs_sb->tcon->ses->capabilities & CAP_UNIX))
+ seq_printf(s, ",gid=%d", cifs_sb->mnt_gid);
seq_printf(s, ",rsize=%d",cifs_sb->rsize);
seq_printf(s, ",wsize=%d",cifs_sb->wsize);
}
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index c1af159..a7c6c35 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -75,6 +75,8 @@ struct smb_vol {
unsigned retry:1;
unsigned intr:1;
unsigned setuids:1;
+ unsigned override_uid:1;
+ unsigned override_gid:1;
unsigned noperm:1;
unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
unsigned cifs_acl:1;
@@ -1042,11 +1044,13 @@ cifs_parse_mount_options(char *options,
if (value && *value) {
vol->linux_uid =
simple_strtoul(value, &value, 0);
+ vol->override_uid = 1;
}
} else if (strnicmp(data, "gid", 3) == 0) {
if (value && *value) {
vol->linux_gid =
simple_strtoul(value, &value, 0);
+ vol->override_gid = 1;
}
} else if (strnicmp(data, "file_mode", 4) == 0) {
if (value && *value) {
@@ -1989,7 +1993,10 @@ cifs_mount(struct super_block *sb, struc
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
if(volume_info.cifs_acl)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
-
+ if(volume_info.override_uid)
+ cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
+ if(volume_info.override_gid)
+ cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
if(volume_info.direct_io) {
cFYI(1,("mounting share using direct i/o"));
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index f74f37c..fe5d326 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -139,8 +139,17 @@ int cifs_get_inode_info_unix(struct inod
inode->i_mode |= S_IFREG;
cFYI(1,("unknown type %d",type));
}
- inode->i_uid = le64_to_cpu(findData.Uid);
- inode->i_gid = le64_to_cpu(findData.Gid);
+
+ if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
+ inode->i_uid = cifs_sb->mnt_uid;
+ else
+ inode->i_uid = le64_to_cpu(findData.Uid);
+
+ if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
+ inode->i_gid = cifs_sb->mnt_gid;
+ else
+ inode->i_gid = le64_to_cpu(findData.Gid);
+
inode->i_nlink = le64_to_cpu(findData.Nlinks);
spin_lock(&inode->i_lock);
@@ -523,6 +532,8 @@ int cifs_get_inode_info(struct inode **p
or retrieve from NTFS stream extended attribute */
if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
/* fill in uid, gid, mode from server ACL */
+ /* BB FIXME this should also take into account the
+ * default uid specified on mount if present */
get_sfu_uid_mode(inode, search_path, cifs_sb, xid);
} else if (atomic_read(&cifsInfo->inUse) == 0) {
inode->i_uid = cifs_sb->mnt_uid;
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index b80b0fc..24d3133 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -357,8 +357,14 @@ static void unix_fill_in_inode(struct in
cFYI(1,("unknown inode type %d",type));
}
- tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
- tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
+ if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
+ tmp_inode->i_uid = cifs_sb->mnt_uid;
+ else
+ tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
+ if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
+ tmp_inode->i_gid = cifs_sb->mnt_gid;
+ else
+ tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
spin_lock(&tmp_inode->i_lock);
@@ -382,7 +388,6 @@ static void unix_fill_in_inode(struct in
tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
else
tmp_inode->i_fop = &cifs_file_direct_ops;
-
} else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
tmp_inode->i_fop = &cifs_file_nobrl_ops;
else