Fix try_chown code. Use new vfs_chown_fsp() which always trys fd first.
authorJeremy Allison <jra@samba.org>
Sat, 5 Feb 2011 01:48:10 +0000 (17:48 -0800)
committerJeremy Allison <jra@samba.org>
Sat, 5 Feb 2011 02:33:58 +0000 (03:33 +0100)
Autobuild-User: Jeremy Allison <jra@samba.org>
Autobuild-Date: Sat Feb  5 03:33:59 CET 2011 on sn-devel-104

source3/include/proto.h
source3/modules/nfs4_acls.c
source3/smbd/posix_acls.c
source3/smbd/vfs.c

index 4c7d4f3d4250f394ed92982d4cc3ac2026c00577..94cd0a9867c12b2b211252bbbd15a0f002265f49 100644 (file)
@@ -5158,8 +5158,7 @@ NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info,
                           struct security_descriptor **ppdesc);
 NTSTATUS posix_get_nt_acl(struct connection_struct *conn, const char *name,
                          uint32_t security_info, struct security_descriptor **ppdesc);
-int try_chown(connection_struct *conn, struct smb_filename *smb_fname,
-             uid_t uid, gid_t gid);
+NTSTATUS try_chown(files_struct *fsp, uid_t uid, gid_t gid);
 NTSTATUS append_parent_acl(files_struct *fsp,
                                const struct security_descriptor *pcsd,
                                struct security_descriptor **pp_new_sd);
@@ -5606,6 +5605,7 @@ int vfs_stat_smb_fname(struct connection_struct *conn, const char *fname,
 int vfs_lstat_smb_fname(struct connection_struct *conn, const char *fname,
                        SMB_STRUCT_STAT *psbuf);
 NTSTATUS vfs_stat_fsp(files_struct *fsp);
+NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid);
 
 /* The following definitions come from utils/passwd_util.c  */
 
index e2f9fe3a81588b6c0f7db3276c8ec1446d5fb0c1..6e6b015f0701e8d025baf94a0121f08bb7c4ea37 100644 (file)
@@ -765,14 +765,14 @@ NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
                if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
                    ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
 
-                       if(try_chown(fsp->conn, fsp->fsp_name, newUID,
-                                    newGID)) {
+                       status = try_chown(fsp, newUID, newGID);
+                       if (!NT_STATUS_IS_OK(status)) {
                                DEBUG(3,("chown %s, %u, %u failed. Error = "
                                         "%s.\n", fsp_str_dbg(fsp),
                                         (unsigned int)newUID,
                                         (unsigned int)newGID,
-                                        strerror(errno)));
-                               return map_nt_error_from_unix(errno);
+                                        nt_errstr(status)));
+                               return status;
                        }
 
                        DEBUG(10,("chown %s, %u, %u succeeded.\n",
index 880d5b945258d4a30ebcad25d8f131e542ccf349..8707ff799c661b3e4bb8a967d7751ba38c820c6f 100644 (file)
@@ -3526,105 +3526,73 @@ NTSTATUS posix_get_nt_acl(struct connection_struct *conn, const char *name,
  Try to chown a file. We will be able to chown it under the following conditions.
 
   1) If we have root privileges, then it will just work.
-  2) If we have SeTakeOwnershipPrivilege we can change the user to the current user.
-  3) If we have SeRestorePrivilege we can change the user to any other user. 
+  2) If we have SeRestorePrivilege we can change the user + group to any other user. 
+  3) If we have SeTakeOwnershipPrivilege we can change the user to the current user.
   4) If we have write permission to the file and dos_filemodes is set
      then allow chown to the currently authenticated user.
 ****************************************************************************/
 
-int try_chown(connection_struct *conn, struct smb_filename *smb_fname,
-             uid_t uid, gid_t gid)
+NTSTATUS try_chown(files_struct *fsp, uid_t uid, gid_t gid)
 {
-       int ret;
-       files_struct *fsp;
+       NTSTATUS status;
 
-       if(!CAN_WRITE(conn)) {
-               return -1;
+       if(!CAN_WRITE(fsp->conn)) {
+               return NT_STATUS_MEDIA_WRITE_PROTECTED;
        }
 
        /* Case (1). */
-       /* try the direct way first */
-       if (lp_posix_pathnames()) {
-               ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, uid, gid);
-       } else {
-               ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid, gid);
+       status = vfs_chown_fsp(fsp, uid, gid);
+       if (NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
-       if (ret == 0)
-               return 0;
-
        /* Case (2) / (3) */
        if (lp_enable_privileges()) {
-
-               bool has_take_ownership_priv = security_token_has_privilege(get_current_nttok(conn), SEC_PRIV_TAKE_OWNERSHIP);
-               bool has_restore_priv = security_token_has_privilege(get_current_nttok(conn), SEC_PRIV_RESTORE);
-
-               /* Case (2) */
-               if ( ( has_take_ownership_priv && ( uid == get_current_uid(conn) ) ) ||
-               /* Case (3) */
-                    ( has_restore_priv ) ) {
-
-                       become_root();
-                       /* Keep the current file gid the same - take ownership doesn't imply group change. */
-                       if (lp_posix_pathnames()) {
-                               ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, uid,
-                                                   (gid_t)-1);
+               bool has_take_ownership_priv = security_token_has_privilege(
+                                               get_current_nttok(fsp->conn),
+                                               SEC_PRIV_TAKE_OWNERSHIP);
+               bool has_restore_priv = security_token_has_privilege(
+                                               get_current_nttok(fsp->conn),
+                                               SEC_PRIV_RESTORE);
+
+               if (has_restore_priv) {
+                       ; /* Case (2) */
+               } else if (has_take_ownership_priv) {
+                       /* Case (3) */
+                       if (uid == get_current_uid(fsp->conn)) {
+                               gid = (gid_t)-1;
                        } else {
-                               ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid,
-                                                   (gid_t)-1);
+                               has_take_ownership_priv = false;
                        }
+               }
+
+               if (has_take_ownership_priv || has_restore_priv) {
+                       become_root();
+                       status = vfs_chown_fsp(fsp, uid, gid);
                        unbecome_root();
-                       return ret;
+                       return status;
                }
        }
 
        /* Case (4). */
-       if (!lp_dos_filemode(SNUM(conn))) {
-               errno = EPERM;
-               return -1;
+       if (!lp_dos_filemode(SNUM(fsp->conn))) {
+               return NT_STATUS_ACCESS_DENIED;
        }
 
        /* only allow chown to the current user. This is more secure,
           and also copes with the case where the SID in a take ownership ACL is
           a local SID on the users workstation
        */
-       if (uid != get_current_uid(conn)) {
-               errno = EPERM;
-               return -1;
-       }
-
-       if (lp_posix_pathnames()) {
-               ret = SMB_VFS_LSTAT(conn, smb_fname);
-       } else {
-               ret = SMB_VFS_STAT(conn, smb_fname);
-       }
-
-       if (ret == -1) {
-               return -1;
-       }
-
-       if (!NT_STATUS_IS_OK(open_file_fchmod(conn, smb_fname, &fsp))) {
-               return -1;
+       if (uid != get_current_uid(fsp->conn)) {
+               return NT_STATUS_ACCESS_DENIED;
        }
 
        become_root();
        /* Keep the current file gid the same. */
-       if (fsp->fh->fd == -1) {
-               if (lp_posix_pathnames()) {
-                       ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, uid,
-                                           (gid_t)-1);
-               } else {
-                       ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid,
-                                           (gid_t)-1);
-               }
-       } else {
-               ret = SMB_VFS_FCHOWN(fsp, uid, (gid_t)-1);
-       }
+       status = vfs_chown_fsp(fsp, uid, (gid_t)-1);
        unbecome_root();
 
-       close_file(NULL, fsp, NORMAL_CLOSE);
-
-       return ret;
+       return status;
 }
 
 #if 0
@@ -3912,15 +3880,14 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct s
                         fsp_str_dbg(fsp), (unsigned int)user,
                         (unsigned int)grp));
 
-               if(try_chown(fsp->conn, fsp->fsp_name, user, grp) == -1) {
+               status = try_chown(fsp, user, grp);
+               if(!NT_STATUS_IS_OK(status)) {
                        DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error "
-                                "= %s.\n", fsp_str_dbg(fsp),
-                                (unsigned int)user, (unsigned int)grp,
-                                strerror(errno)));
-                       if (errno == EPERM) {
-                               return NT_STATUS_INVALID_OWNER;
-                       }
-                       return map_nt_error_from_unix(errno);
+                               "= %s.\n", fsp_str_dbg(fsp),
+                               (unsigned int)user,
+                               (unsigned int)grp,
+                               nt_errstr(status)));
+                       return status;
                }
 
                /*
index 802639f2fb352bcddf573798311b6f3a3d046e5a..9e44d02e15c42368b2177d291c246c12b80177b6 100644 (file)
@@ -1439,6 +1439,36 @@ int smb_vfs_call_lchown(struct vfs_handle_struct *handle, const char *path,
        return handle->fns->lchown(handle, path, uid, gid);
 }
 
+NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid)
+{
+       int ret;
+
+       if (!fsp->is_directory && fsp->fh->fd != -1) {
+               /* Try fchown. */
+               ret = SMB_VFS_FCHOWN(fsp, uid, gid);
+               if (ret == 0) {
+                       return NT_STATUS_OK;
+               }
+               if (ret == -1 && errno != ENOSYS) {
+                       return map_nt_error_from_unix(errno);
+               }
+       }
+
+       if (fsp->posix_open) {
+               ret = SMB_VFS_LCHOWN(fsp->conn,
+                       fsp->fsp_name->base_name,
+                       uid, gid);
+       } else {
+               ret = SMB_VFS_CHOWN(fsp->conn,
+                       fsp->fsp_name->base_name,
+                       uid, gid);
+       }
+       if (ret == 0) {
+               return NT_STATUS_OK;
+       }
+       return map_nt_error_from_unix(errno);
+}
+
 int smb_vfs_call_chdir(struct vfs_handle_struct *handle, const char *path)
 {
        VFS_FIND(chdir);