vfs_gpfs: handle EACCES when fetching DOS attributes from xattr
authorRalph Boehme <slow@samba.org>
Thu, 8 Jun 2017 17:18:36 +0000 (19:18 +0200)
committerKarolin Seeger <kseeger@samba.org>
Fri, 11 Aug 2017 12:48:10 +0000 (14:48 +0200)
When trying to fetch the DOS attributes via gpfswrap_get_winattrs_path()
if the filesystem doesn't grant READ_ATTR to the file the function fails
with EACCESS.

But according to MS-FSA 2.1.5.1.2.1 "Algorithm to Check Access to an
Existing File" FILE_LIST_DIRECTORY on a directory implies
FILE_READ_ATTRIBUTES for directory entries.

So if the user can open the parent directory for reading this implies
FILE_LIST_DIRECTORY and we can safely call gpfswrap_get_winattrs_path()
with DAC_OVERRIDE_CAPABILITY.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=12944

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Christof Schmitt <cs@samba.org>
Autobuild-User(master): Ralph Böhme <slow@samba.org>
Autobuild-Date(master): Wed Aug  9 01:21:14 CEST 2017 on sn-devel-144

(cherry picked from commit 62d73f5b936550d623ef4f31c7438ac3c90105b9)

Autobuild-User(v4-7-test): Karolin Seeger <kseeger@samba.org>
Autobuild-Date(v4-7-test): Fri Aug 11 14:48:10 CEST 2017 on sn-devel-144

source3/modules/vfs_gpfs.c

index a552cdda4d95809f41785b3eb18d9545b78a53e8..b2c92447f75f4389c9a1a432aeea57c88995408b 100644 (file)
@@ -1537,6 +1537,47 @@ static unsigned int vfs_gpfs_dosmode_to_winattrs(uint32_t dosmode)
        return winattrs;
 }
 
+static int get_dos_attr_with_capability(struct smb_filename *smb_fname,
+                                       struct gpfs_winattr *attr)
+{
+       int saved_errno = 0;
+       int ret;
+
+       /*
+        * According to MS-FSA 2.1.5.1.2.1 "Algorithm to Check Access to an
+        * Existing File" FILE_LIST_DIRECTORY on a directory implies
+        * FILE_READ_ATTRIBUTES for directory entries. Being able to stat() a
+        * file implies FILE_LIST_DIRECTORY for the directory containing the
+        * file.
+        */
+
+       if (!VALID_STAT(smb_fname->st)) {
+               /*
+                * Safety net: dos_mode() already checks this, but as we set
+                * DAC_OVERRIDE_CAPABILITY based on this, add an additional
+                * layer of defense.
+                */
+               DBG_ERR("Rejecting DAC override, invalid stat [%s]\n",
+                       smb_fname_str_dbg(smb_fname));
+               errno = EACCES;
+               return -1;
+       }
+
+       set_effective_capability(DAC_OVERRIDE_CAPABILITY);
+
+       ret = gpfswrap_get_winattrs_path(smb_fname->base_name, attr);
+       if (ret == -1) {
+               saved_errno = errno;
+       }
+
+       drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
+
+       if (saved_errno != 0) {
+               errno = saved_errno;
+       }
+       return ret;
+}
+
 static NTSTATUS vfs_gpfs_get_dos_attributes(struct vfs_handle_struct *handle,
                                            struct smb_filename *smb_fname,
                                            uint32_t *dosmode)
@@ -1559,7 +1600,9 @@ static NTSTATUS vfs_gpfs_get_dos_attributes(struct vfs_handle_struct *handle,
                return SMB_VFS_NEXT_GET_DOS_ATTRIBUTES(handle, smb_fname,
                                                       dosmode);
        }
-
+       if (ret == -1 && errno == EACCES) {
+               ret = get_dos_attr_with_capability(smb_fname, &attrs);
+       }
        if (ret == -1) {
                DBG_WARNING("Getting winattrs failed for %s: %s\n",
                            smb_fname->base_name, strerror(errno));
@@ -1595,6 +1638,30 @@ static NTSTATUS vfs_gpfs_fget_dos_attributes(struct vfs_handle_struct *handle,
                return SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle, fsp, dosmode);
        }
 
+       if (ret == -1 && errno == EACCES) {
+               int saved_errno = 0;
+
+               /*
+                * According to MS-FSA 2.1.5.1.2.1 "Algorithm to Check Access to
+                * an Existing File" FILE_LIST_DIRECTORY on a directory implies
+                * FILE_READ_ATTRIBUTES for directory entries. Being able to
+                * open a file implies FILE_LIST_DIRECTORY.
+                */
+
+               set_effective_capability(DAC_OVERRIDE_CAPABILITY);
+
+               ret = gpfswrap_get_winattrs(fsp->fh->fd, &attrs);
+               if (ret == -1) {
+                       saved_errno = errno;
+               }
+
+               drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
+
+               if (saved_errno != 0) {
+                       errno = saved_errno;
+               }
+       }
+
        if (ret == -1) {
                DBG_WARNING("Getting winattrs failed for %s: %s\n",
                            fsp->fsp_name->base_name, strerror(errno));