From df34e804fc1a44e6ff096fbaf7a643778e857481 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 4 Feb 2011 17:48:10 -0800 Subject: Fix try_chown code. Use new vfs_chown_fsp() which always trys fd first. Autobuild-User: Jeremy Allison Autobuild-Date: Sat Feb 5 03:33:59 CET 2011 on sn-devel-104 --- source3/include/proto.h | 4 +- source3/modules/nfs4_acls.c | 8 +-- source3/smbd/posix_acls.c | 117 ++++++++++++++++---------------------------- source3/smbd/vfs.c | 30 ++++++++++++ 4 files changed, 78 insertions(+), 81 deletions(-) diff --git a/source3/include/proto.h b/source3/include/proto.h index 4c7d4f3d42..94cd0a9867 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -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 */ diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c index e2f9fe3a81..6e6b015f07 100644 --- a/source3/modules/nfs4_acls.c +++ b/source3/modules/nfs4_acls.c @@ -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", diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c index 880d5b9452..8707ff799c 100644 --- a/source3/smbd/posix_acls.c +++ b/source3/smbd/posix_acls.c @@ -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; } /* diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 802639f2fb..9e44d02e15 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -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); -- cgit