From c4d2904b362ff7180ee1596632433dabd45f36a7 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 22 Mar 2011 13:43:57 -0700 Subject: [PATCH] Fix bug #7996 - sgid bit lost on folder rename. From the chmod 2 man page: "If the calling process is not privileged, and the group of the file does not match the effective group ID of the process or one of its supplementary group IDs, the S_ISGID bit will be turned off, but this will not cause an error to be returned." Jeremy. --- source3/include/proto.h | 1 + source3/modules/vfs_default.c | 61 +++++++++++++++++++++++++++++++++++++++++ source3/smbd/posix_acls.c | 2 +- 3 files changed, 63 insertions(+), 1 deletions(-) diff --git a/source3/include/proto.h b/source3/include/proto.h index ef80b92..4229cc0 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -6751,6 +6751,7 @@ uint32_t map_canon_ace_perms(int snum, mode_t perms, bool directory_ace); NTSTATUS unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, const SEC_DESC *psd); +bool current_user_in_group(gid_t gid); SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl); NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info, SEC_DESC **ppdesc); diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 60b85d9..f5098a7 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -737,6 +737,7 @@ static int vfswrap_unlink(vfs_handle_struct *handle, static int vfswrap_chmod(vfs_handle_struct *handle, const char *path, mode_t mode) { int result; + bool as_root = false; START_PROFILE(syscall_chmod); @@ -757,7 +758,44 @@ static int vfswrap_chmod(vfs_handle_struct *handle, const char *path, mode_t mo errno = saved_errno; } + /* + * From the chmod 2 man page: + * + * "If the calling process is not privileged, and the group of the file + * does not match the effective group ID of the process or one of its + * supplementary group IDs, the S_ISGID bit will be turned off, but + * this will not cause an error to be returned." + * + */ + + if ((mode & S_ISGID) && geteuid() != sec_initial_uid()) { + SMB_STRUCT_STAT st; + struct smb_filename smb_fname; + + ZERO_STRUCT(smb_fname); + smb_fname.base_name = discard_const_p(char, path); + + if (lp_posix_pathnames()) { + result = SMB_VFS_LSTAT(handle->conn, &smb_fname); + } else { + result = SMB_VFS_STAT(handle->conn, &smb_fname); + } + + if (result != 0) { + END_PROFILE(syscall_chmod); + return -1; + } + if (!current_user_in_group(smb_fname.st.st_ex_gid)) { + as_root = true; + } + } + if (as_root) { + become_root(); + } result = chmod(path, mode); + if (as_root) { + unbecome_root(); + } END_PROFILE(syscall_chmod); return result; } @@ -765,6 +803,7 @@ static int vfswrap_chmod(vfs_handle_struct *handle, const char *path, mode_t mo static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode) { int result; + bool as_root = false; START_PROFILE(syscall_fchmod); @@ -785,7 +824,29 @@ static int vfswrap_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t m } #if defined(HAVE_FCHMOD) + /* + * From the fchmod 2 man page: + * + * "If the calling process is not privileged, and the group of the file + * does not match the effective group ID of the process or one of its + * supplementary group IDs, the S_ISGID bit will be turned off, but + * this will not cause an error to be returned." + * + */ + + if ((mode & S_ISGID) && + VALID_STAT(fsp->fsp_name->st) && + geteuid() != sec_initial_uid() && + !current_user_in_group(fsp->fsp_name->st.st_ex_gid)) { + as_root = true; + } + if (as_root) { + become_root(); + } result = fchmod(fsp->fh->fd, mode); + if (as_root) { + unbecome_root(); + } #else result = -1; errno = ENOSYS; diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c index aaca9f4..714a4d3 100644 --- a/source3/smbd/posix_acls.c +++ b/source3/smbd/posix_acls.c @@ -2644,7 +2644,7 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn, Check if the current user group list contains a given group. ****************************************************************************/ -static bool current_user_in_group(gid_t gid) +bool current_user_in_group(gid_t gid) { int i; -- 1.7.3.1