From f9a2f4f47c71e5054c05703e72c24f2f5a87d993 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 30 Mar 2011 18:00:09 -0700 Subject: Fix bug #7996 - sgid bit lost on folder rename. Refuse to set dos attributes into unix mode bits on such a folder. --- source3/smbd/dosmode.c | 21 +++++++++++++++++++++ source3/smbd/posix_acls.c | 2 +- source3/smbd/proto.h | 1 + 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c index 0e45e88d8d..1ea4c686d5 100644 --- a/source3/smbd/dosmode.c +++ b/source3/smbd/dosmode.c @@ -798,6 +798,27 @@ int file_set_dosmode(connection_struct *conn, struct smb_filename *smb_fname, unixmode |= (smb_fname->st.st_ex_mode & (S_IWUSR|S_IWGRP|S_IWOTH)); } + /* + * 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." + * + * Simply refuse to do the chmod in this case. + */ + + if (S_ISDIR(smb_fname->st.st_ex_mode) && (unixmode & S_ISGID) && + geteuid() != sec_initial_uid() && + !current_user_in_group(conn, smb_fname->st.st_ex_gid)) { + DEBUG(3,("file_set_dosmode: setgid bit cannot be " + "set for directory %s\n", + smb_fname_str_dbg(smb_fname))); + errno = EPERM; + return -1; + } + ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode); if (ret == 0) { if(!newfile || (lret != -1)) { diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c index 1d287160b1..9252ee639f 100644 --- a/source3/smbd/posix_acls.c +++ b/source3/smbd/posix_acls.c @@ -2656,7 +2656,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(connection_struct *conn, gid_t gid) +bool current_user_in_group(connection_struct *conn, gid_t gid) { int i; const struct security_unix_token *utok = get_current_utok(conn); diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index 9366ee6d89..f4b2e5ef59 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -684,6 +684,7 @@ uint32_t map_canon_ace_perms(int snum, mode_t perms, bool directory_ace); NTSTATUS unpack_nt_owners(connection_struct *conn, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, const struct security_descriptor *psd); +bool current_user_in_group(connection_struct *conn, 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, struct security_descriptor **ppdesc); -- cgit