cifs: have find_readable/writable_file filter by fsuid
authorJeff Layton <jlayton@redhat.com>
Wed, 29 Sep 2010 23:51:11 +0000 (19:51 -0400)
committerSteve French <sfrench@us.ibm.com>
Wed, 6 Oct 2010 16:12:59 +0000 (16:12 +0000)
When we implement multiuser mounts, we'll need to filter filehandles
by fsuid. Add a flag for multiuser mounts and code to filter by
fsuid when it's set.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
fs/cifs/cifs_fs_sb.h
fs/cifs/cifsacl.c
fs/cifs/cifsproto.h
fs/cifs/dir.c
fs/cifs/file.c
fs/cifs/inode.c

index ba0afd3..e04e692 100644 (file)
@@ -37,6 +37,7 @@
 #define CIFS_MOUNT_NOSSYNC      0x4000 /* don't do slow SMBflush on every sync*/
 #define CIFS_MOUNT_FSCACHE     0x8000 /* local caching enabled */
 #define CIFS_MOUNT_MF_SYMLINKS 0x10000 /* Minshall+French Symlinks enabled */
+#define CIFS_MOUNT_MULTIUSER   0x20000 /* multiuser mount */
 
 struct cifs_sb_info {
        struct cifsTconInfo *ptcon;     /* primary mount */
@@ -48,7 +49,7 @@ struct cifs_sb_info {
        gid_t   mnt_gid;
        mode_t  mnt_file_mode;
        mode_t  mnt_dir_mode;
-       int     mnt_cifs_flags;
+       unsigned int mnt_cifs_flags;
        int     prepathlen;
        char   *prepath; /* relative path under the share to mount to */
 #ifdef CONFIG_CIFS_DFS_UPCALL
index 2647ea4..c9b4792 100644 (file)
@@ -615,7 +615,7 @@ static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
        struct cifsFileInfo *open_file = NULL;
 
        if (inode)
-               open_file = find_readable_file(CIFS_I(inode));
+               open_file = find_readable_file(CIFS_I(inode), true);
        if (!open_file)
                return get_cifs_acl_by_path(cifs_sb, path, pacllen);
 
@@ -685,7 +685,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
 
        cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);
 
-       open_file = find_readable_file(CIFS_I(inode));
+       open_file = find_readable_file(CIFS_I(inode), true);
        if (!open_file)
                return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
 
index 7294723..29a2ee8 100644 (file)
@@ -78,9 +78,9 @@ extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
 extern bool is_valid_oplock_break(struct smb_hdr *smb,
                                  struct TCP_Server_Info *);
 extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
-extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
+extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool);
 #ifdef CONFIG_CIFS_EXPERIMENTAL
-extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *);
+extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
 #endif
 extern unsigned int smbCalcSize(struct smb_hdr *ptr);
 extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
index 5adf47f..e249b56 100644 (file)
@@ -144,6 +144,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, struct file *file,
 
        pCifsFile->netfid = fileHandle;
        pCifsFile->pid = current->tgid;
+       pCifsFile->uid = current_fsuid();
        pCifsFile->pInode = igrab(newinode);
        pCifsFile->mnt = mnt;
        pCifsFile->pfile = file;
index 24332d4..80856f1 100644 (file)
@@ -1168,9 +1168,15 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
 }
 
 #ifdef CONFIG_CIFS_EXPERIMENTAL
-struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
+struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
+                                       bool fsuid_only)
 {
        struct cifsFileInfo *open_file = NULL;
+       struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
+
+       /* only filter by fsuid on multiuser mounts */
+       if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
+               fsuid_only = false;
 
        read_lock(&GlobalSMBSeslock);
        /* we could simply get the first_list_entry since write-only entries
@@ -1179,6 +1185,8 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
        list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
                if (open_file->closePend)
                        continue;
+               if (fsuid_only && open_file->uid != current_fsuid())
+                       continue;
                if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
                    (open_file->pfile->f_flags & O_RDONLY))) {
                        if (!open_file->invalidHandle) {
@@ -1198,9 +1206,11 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
 }
 #endif
 
-struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
+struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
+                                       bool fsuid_only)
 {
        struct cifsFileInfo *open_file;
+       struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
        bool any_available = false;
        int rc;
 
@@ -1214,13 +1224,19 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
                return NULL;
        }
 
+       /* only filter by fsuid on multiuser mounts */
+       if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
+               fsuid_only = false;
+
        read_lock(&GlobalSMBSeslock);
 refind_writable:
        list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
-               if (open_file->closePend ||
-                   (!any_available && open_file->pid != current->tgid))
+               if (open_file->closePend)
+                       continue;
+               if (!any_available && open_file->pid != current->tgid)
+                       continue;
+               if (fsuid_only && open_file->uid != current_fsuid())
                        continue;
-
                if (open_file->pfile &&
                    ((open_file->pfile->f_flags & O_RDWR) ||
                     (open_file->pfile->f_flags & O_WRONLY))) {
@@ -1315,7 +1331,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
        if (mapping->host->i_size - offset < (loff_t)to)
                to = (unsigned)(mapping->host->i_size - offset);
 
-       open_file = find_writable_file(CIFS_I(mapping->host));
+       open_file = find_writable_file(CIFS_I(mapping->host), false);
        if (open_file) {
                bytes_written = cifs_write(open_file->pfile, write_data,
                                           to-from, &offset);
@@ -1388,7 +1404,7 @@ static int cifs_writepages(struct address_space *mapping,
         * but it'll at least handle the return. Maybe it should be
         * a BUG() instead?
         */
-       open_file = find_writable_file(CIFS_I(mapping->host));
+       open_file = find_writable_file(CIFS_I(mapping->host), false);
        if (!open_file) {
                kfree(iov);
                return generic_writepages(mapping, wbc);
@@ -1505,7 +1521,8 @@ retry:
                                break;
                }
                if (n_iov) {
-                       open_file = find_writable_file(CIFS_I(mapping->host));
+                       open_file = find_writable_file(CIFS_I(mapping->host),
+                                                       false);
                        if (!open_file) {
                                cERROR(1, "No writable handles for inode");
                                rc = -EBADF;
index a39a1c4..df29a3a 100644 (file)
@@ -963,7 +963,7 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
        /*
         * If the file is already open for write, just use that fileid
         */
-       open_file = find_writable_file(cifsInode);
+       open_file = find_writable_file(cifsInode, true);
        if (open_file) {
                netfid = open_file->netfid;
                netpid = open_file->pid;
@@ -1813,7 +1813,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
         * writebehind data than the SMB timeout for the SetPathInfo
         * request would allow
         */
-       open_file = find_writable_file(cifsInode);
+       open_file = find_writable_file(cifsInode, true);
        if (open_file) {
                __u16 nfid = open_file->netfid;
                __u32 npid = open_file->pid;
@@ -1978,7 +1978,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
                args->ctime = NO_CHANGE_64;
 
        args->device = 0;
-       open_file = find_writable_file(cifsInode);
+       open_file = find_writable_file(cifsInode, true);
        if (open_file) {
                u16 nfid = open_file->netfid;
                u32 npid = open_file->pid;