Fix bug #7996 - sgid bit lost on folder rename.
authorJeremy Allison <jra@samba.org>
Thu, 31 Mar 2011 01:00:09 +0000 (18:00 -0700)
committerJeremy Allison <jra@samba.org>
Thu, 31 Mar 2011 01:01:19 +0000 (18:01 -0700)
Refuse to set dos attributes into unix mode bits on such a
folder.

source3/smbd/dosmode.c
source3/smbd/posix_acls.c
source3/smbd/proto.h

index 0e45e88d8ddd9e1d3b1ca922565d5d365b5ee3aa..1ea4c686d51a02469e0d88d8cb83b8bd40a8edb3 100644 (file)
@@ -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));
        }
 
                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)) {
        ret = SMB_VFS_CHMOD(conn, smb_fname->base_name, unixmode);
        if (ret == 0) {
                if(!newfile || (lret != -1)) {
index 1d287160b1d9df63d85d159ace9881dad81429a0..9252ee639fd3be4ae40a520eba5651a16ddde673 100644 (file)
@@ -2656,7 +2656,7 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn,
  Check if the current user group list contains a given group.
 ****************************************************************************/
 
  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);
 {
        int i;
        const struct security_unix_token *utok = get_current_utok(conn);
index 9366ee6d894d3fe83a9fc19c2f1c334c16110602..f4b2e5ef5945a7c8bb43df44da3f24550a83fd0a 100644 (file)
@@ -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);
                                 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);
 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);