The branch, master has been updated
       via  e49893c Use handle based xattr set if available.
       via  525ccd5 Ensure vfs_chown_fsp() is safe against races.
      from  e4c4dcf s3-waf: only LIBNMB needs to linked against -lresolv.

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit e49893c68ef29f71ac6301f3955a7404e9c6daba
Author: Jeremy Allison <j...@samba.org>
Date:   Fri Apr 15 10:49:34 2011 -0700

    Use handle based xattr set if available.
    
    Autobuild-User: Jeremy Allison <j...@samba.org>
    Autobuild-Date: Fri Apr 15 22:11:12 CEST 2011 on sn-devel-104

commit 525ccd589ede79e97e83699629a1d98538855803
Author: Jeremy Allison <j...@samba.org>
Date:   Fri Apr 15 12:21:39 2011 -0700

    Ensure vfs_chown_fsp() is safe against races.

-----------------------------------------------------------------------

Summary of changes:
 source3/smbd/dosmode.c |    9 +++--
 source3/smbd/open.c    |    2 +-
 source3/smbd/proto.h   |    2 +
 source3/smbd/vfs.c     |   76 ++++++++++++++++++++++++++++++++++++++++++++---
 4 files changed, 79 insertions(+), 10 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
index 1ea4c68..a9b6dfe 100644
--- a/source3/smbd/dosmode.c
+++ b/source3/smbd/dosmode.c
@@ -348,8 +348,6 @@ static bool set_ea_dos_attribute(connection_struct *conn,
        struct xattr_DOSATTRIB dosattrib;
        enum ndr_err_code ndr_err;
        DATA_BLOB blob;
-       files_struct *fsp = NULL;
-       bool ret = false;
 
        if (!lp_store_dos_attributes(SNUM(conn))) {
                return False;
@@ -387,6 +385,9 @@ static bool set_ea_dos_attribute(connection_struct *conn,
        if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
                             SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length,
                             0) == -1) {
+               bool ret = false;
+               files_struct *fsp = NULL;
+
                if((errno != EPERM) && (errno != EACCES)) {
                        if (errno == ENOSYS
 #if defined(ENOTSUP)
@@ -419,9 +420,9 @@ static bool set_ea_dos_attribute(connection_struct *conn,
 
                if (!NT_STATUS_IS_OK(open_file_fchmod(conn, smb_fname,
                                                      &fsp)))
-                       return ret;
+                       return false;
                become_root();
-               if (SMB_VFS_SETXATTR(conn, smb_fname->base_name,
+               if (SMB_VFS_FSETXATTR(fsp,
                                     SAMBA_XATTR_DOS_ATTRIB, blob.data,
                                     blob.length, 0) == 0) {
                        ret = true;
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index b7c8540..14e6bf9 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -2563,7 +2563,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
  Ensure we didn't get symlink raced on opening a directory.
 ****************************************************************************/
 
-static bool check_same_stat(const SMB_STRUCT_STAT *sbuf1,
+bool check_same_stat(const SMB_STRUCT_STAT *sbuf1,
                        const SMB_STRUCT_STAT *sbuf2)
 {
        if (sbuf1->st_ex_uid != sbuf2->st_ex_uid ||
diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index c097202..36eea5e 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -567,6 +567,8 @@ void remove_deferred_open_entry(struct file_id id, uint64_t 
mid,
 NTSTATUS open_file_fchmod(connection_struct *conn,
                          struct smb_filename *smb_fname,
                          files_struct **result);
+bool check_same_stat(const SMB_STRUCT_STAT *sbuf1,
+                       const SMB_STRUCT_STAT *sbuf2);
 NTSTATUS create_directory(connection_struct *conn, struct smb_request *req,
                          struct smb_filename *smb_dname);
 void msg_file_was_renamed(struct messaging_context *msg,
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index d8c57a6..0438f79 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -1455,6 +1455,11 @@ int smb_vfs_call_lchown(struct vfs_handle_struct 
*handle, const char *path,
 NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid)
 {
        int ret;
+       bool as_root = false;
+       const char *path;
+       char *saved_dir = NULL;
+       char *parent_dir = NULL;
+       NTSTATUS status;
 
        if (fsp->fh->fd != -1) {
                /* Try fchown. */
@@ -1467,19 +1472,80 @@ NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, 
gid_t gid)
                }
        }
 
-       if (fsp->posix_open) {
+       as_root = (geteuid() == 0);
+
+       if (as_root) {
+               /*
+                * We are being asked to chown as root. Make
+                * sure we chdir() into the path to pin it,
+                * and always act using lchown to ensure we
+                * don't deref any symbolic links.
+                */
+               const char *final_component = NULL;
+               struct smb_filename local_fname;
+
+               saved_dir = vfs_GetWd(talloc_tos(),fsp->conn);
+               if (!saved_dir) {
+                       status = map_nt_error_from_unix(errno);
+                       DEBUG(0,("vfs_chown_fsp: failed to get "
+                               "current working directory. Error was %s\n",
+                               strerror(errno)));
+                       return status;
+               }
+
+               if (!parent_dirname(talloc_tos(),
+                               fsp->fsp_name->base_name,
+                               &parent_dir,
+                               &final_component)) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               /* cd into the parent dir to pin it. */
+               ret = SMB_VFS_CHDIR(fsp->conn, parent_dir);
+               if (ret == -1) {
+                       return map_nt_error_from_unix(errno);
+               }
+
+               ZERO_STRUCT(local_fname);
+               local_fname.base_name = CONST_DISCARD(char *,final_component);
+
+               /* Must use lstat here. */
+               ret = SMB_VFS_LSTAT(fsp->conn, &local_fname);
+               if (ret == -1) {
+                       return map_nt_error_from_unix(errno);
+               }
+
+               /* Ensure it matches the fsp stat. */
+               if (!check_same_stat(&local_fname.st, &fsp->fsp_name->st)) {
+                        return NT_STATUS_ACCESS_DENIED;
+                }
+                path = final_component;
+        } else {
+                path = fsp->fsp_name->base_name;
+        }
+
+       if (fsp->posix_open || as_root) {
                ret = SMB_VFS_LCHOWN(fsp->conn,
-                       fsp->fsp_name->base_name,
+                       path,
                        uid, gid);
        } else {
                ret = SMB_VFS_CHOWN(fsp->conn,
-                       fsp->fsp_name->base_name,
+                       path,
                        uid, gid);
        }
+
        if (ret == 0) {
-               return NT_STATUS_OK;
+               status = NT_STATUS_OK;
+       } else {
+               status = map_nt_error_from_unix(errno);
+       }
+
+       if (as_root) {
+               vfs_ChDir(fsp->conn,saved_dir);
+               TALLOC_FREE(saved_dir);
+               TALLOC_FREE(parent_dir);
        }
-       return map_nt_error_from_unix(errno);
+       return status;
 }
 
 int smb_vfs_call_chdir(struct vfs_handle_struct *handle, const char *path)


-- 
Samba Shared Repository

Reply via email to