[GLUE] Rsync SAMBA_3_0 SVN r25598 in order to create the v3-0-test branch.
[gd/samba/.git] / source / smbd / posix_acls.c
index 947c30fb4a3231135fd07832b47fe9abd91fa021..ade64c1c6ccee7d76008f20571993b6675bd6174 100644 (file)
@@ -926,7 +926,7 @@ static mode_t map_nt_perms( uint32 *mask, int type)
  Unpack a SEC_DESC into a UNIX owner and group.
 ****************************************************************************/
 
-NTSTATUS unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
+BOOL unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
 {
        DOM_SID owner_sid;
        DOM_SID grp_sid;
@@ -936,7 +936,7 @@ NTSTATUS unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_i
 
        if(security_info_sent == 0) {
                DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
-               return NT_STATUS_OK;
+               return True;
        }
 
        /*
@@ -964,11 +964,9 @@ NTSTATUS unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_i
                                DEBUG(3,("unpack_nt_owners: unable to validate"
                                         " owner sid for %s\n",
                                         sid_string_static(&owner_sid)));
-                               return NT_STATUS_INVALID_OWNER;
+                               return False;
                        }
                }
-               DEBUG(3,("unpack_nt_owners: owner sid mapped to uid %u\n",
-                        (unsigned int)*puser ));
        }
 
        /*
@@ -986,16 +984,14 @@ NTSTATUS unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_i
                        } else {
                                DEBUG(3,("unpack_nt_owners: unable to validate"
                                         " group sid.\n"));
-                               return NT_STATUS_INVALID_OWNER;
+                               return False;
                        }
                }
-               DEBUG(3,("unpack_nt_owners: group sid mapped to gid %u\n",
-                        (unsigned int)*pgrp));
-       }
+       }
 
        DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
 
-       return NT_STATUS_OK;
+       return True;
 }
 
 /****************************************************************************
@@ -3076,7 +3072,6 @@ int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
 
        /* Case (4). */
        if (!lp_dos_filemode(SNUM(conn))) {
-               errno = EPERM;
                return -1;
        }
 
@@ -3112,7 +3107,7 @@ static NTSTATUS append_ugw_ace(files_struct *fsp,
 {
        mode_t perms;
        SEC_ACCESS acc;
-       int acl_type;
+       int nt_acl_type; /* Tru64 has "acl_type" as a macro.. */
        DOM_SID trustee;
 
        switch (ugw) {
@@ -3141,13 +3136,13 @@ static NTSTATUS append_ugw_ace(files_struct *fsp,
                        return NT_STATUS_INVALID_PARAMETER;
        }
        acc = map_canon_ace_perms(SNUM(fsp->conn),
-                               &acl_type,
+                               &nt_acl_type,
                                perms,
                                fsp->is_directory);
 
        init_sec_ace(se,
                &trustee,
-               acl_type,
+               nt_acl_type,
                acc,
                0);
        return NT_STATUS_OK;
@@ -3195,14 +3190,13 @@ static NTSTATUS append_parent_acl(files_struct *fsp,
                        parent_name);
 
        status = open_directory(fsp->conn,
-                               NULL,
                                parent_name,
                                &sbuf,
                                FILE_READ_ATTRIBUTES, /* Just a stat open */
                                FILE_SHARE_NONE, /* Ignored for stat opens */
                                FILE_OPEN,
                                0,
-                               INTERNAL_OPEN_ONLY,
+                               0,
                                &info,
                                &parent_fsp);
 
@@ -3303,7 +3297,7 @@ static NTSTATUS append_parent_acl(files_struct *fsp,
  This should be the only external function needed for the UNIX style set ACL.
 ****************************************************************************/
 
-NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
+BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
 {
        connection_struct *conn = fsp->conn;
        uid_t user = (uid_t)-1;
@@ -3315,13 +3309,15 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
        canon_ace *dir_ace_list = NULL;
        BOOL acl_perms = False;
        mode_t orig_mode = (mode_t)0;
-       NTSTATUS status;
+       uid_t orig_uid;
+       gid_t orig_gid;
+       BOOL need_chown = False;
 
        DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
 
        if (!CAN_WRITE(conn)) {
                DEBUG(10,("set acl rejected on read-only share\n"));
-               return NT_STATUS_MEDIA_WRITE_PROTECTED;
+               return False;
        }
 
        /*
@@ -3330,29 +3326,40 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
 
        if(fsp->is_directory || fsp->fh->fd == -1) {
                if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0)
-                       return map_nt_error_from_unix(errno);
+                       return False;
        } else {
                if(SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) != 0)
-                       return map_nt_error_from_unix(errno);
+                       return False;
        }
 
        /* Save the original elements we check against. */
        orig_mode = sbuf.st_mode;
+       orig_uid = sbuf.st_uid;
+       orig_gid = sbuf.st_gid;
 
        /*
         * Unpack the user/group/world id's.
         */
 
-       status = unpack_nt_owners( SNUM(conn), &user, &grp, security_info_sent, psd);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       if (!unpack_nt_owners( SNUM(conn), &user, &grp, security_info_sent, psd)) {
+               return False;
        }
 
        /*
         * Do we need to chown ?
         */
 
-       if (((user != (uid_t)-1) && (sbuf.st_uid != user)) || (( grp != (gid_t)-1) && (sbuf.st_gid != grp))) {
+       if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp))) {
+               need_chown = True;
+       }
+
+       /*
+        * Chown before setting ACL only if we don't change the user, or
+        * if we change to the current user, but not if we want to give away
+        * the file.
+        */
+
+       if (need_chown && (user == (uid_t)-1 || user == current_user.ut.uid)) {
 
                DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
                                fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
@@ -3360,10 +3367,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
                if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
                        DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
                                fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
-                       if (errno == EPERM) {
-                               return NT_STATUS_INVALID_OWNER;
-                       }
-                       return map_nt_error_from_unix(errno);
+                       return False;
                }
 
                /*
@@ -3373,7 +3377,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
 
                if(fsp->is_directory) {
                        if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
-                               return map_nt_error_from_unix(errno);
+                               return False;
                        }
                } else {
 
@@ -3385,11 +3389,16 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
                                ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf);
 
                        if(ret != 0)
-                               return map_nt_error_from_unix(errno);
+                               return False;
                }
 
                /* Save the original elements we check against. */
                orig_mode = sbuf.st_mode;
+               orig_uid = sbuf.st_uid;
+               orig_gid = sbuf.st_gid;
+
+               /* We did it, don't try again */
+               need_chown = False;
        }
 
        create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
@@ -3400,9 +3409,9 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
                              SE_DESC_DACL_AUTO_INHERIT_REQ))==
                        (SE_DESC_DACL_AUTO_INHERITED|
                         SE_DESC_DACL_AUTO_INHERIT_REQ) ) {
-               status = append_parent_acl(fsp, &sbuf, psd, &psd);
+               NTSTATUS status = append_parent_acl(fsp, &sbuf, psd, &psd);
                if (!NT_STATUS_IS_OK(status)) {
-                       return status;
+                       return False;
                }
        }
 
@@ -3416,7 +3425,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
                        DEBUG(3,("set_nt_acl: cannot set permissions\n"));
                        free_canon_ace_list(file_ace_list);
                        free_canon_ace_list(dir_ace_list); 
-                       return NT_STATUS_ACCESS_DENIED;
+                       return False;
                }
 
                /*
@@ -3439,7 +3448,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
                                        DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
                                        free_canon_ace_list(file_ace_list);
                                        free_canon_ace_list(dir_ace_list); 
-                                       return map_nt_error_from_unix(errno);
+                                       return False;
                                }
                        }
 
@@ -3449,7 +3458,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
                                                DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
                                                free_canon_ace_list(file_ace_list);
                                                free_canon_ace_list(dir_ace_list); 
-                                               return map_nt_error_from_unix(errno);
+                                               return False;
                                        }
                                } else {
 
@@ -3474,7 +3483,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
                                                        DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
                                                        free_canon_ace_list(file_ace_list);
                                                        free_canon_ace_list(dir_ace_list);
-                                                       return map_nt_error_from_unix(errno);
+                                                       return False;
                                                }
                                        }
                                }
@@ -3497,7 +3506,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
                                        free_canon_ace_list(dir_ace_list);
                                        DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
                                                fsp->fsp_name ));
-                                       return NT_STATUS_ACCESS_DENIED;
+                                       return False;
                                }
 
                                if (orig_mode != posix_perms) {
@@ -3522,7 +3531,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
                                                                fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
                                                        free_canon_ace_list(file_ace_list);
                                                        free_canon_ace_list(dir_ace_list);
-                                                       return map_nt_error_from_unix(errno);
+                                                       return False;
                                                }
                                        }
                                }
@@ -3533,7 +3542,20 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
                free_canon_ace_list(dir_ace_list); 
        }
 
-       return NT_STATUS_OK;
+       /* Any chown pending? */
+       if (need_chown) {
+
+               DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
+                       fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
+
+               if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
+                       DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
+                               fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
+                       return False;
+               }
+       }
+
+       return True;
 }
 
 /****************************************************************************