Another attempt to fix bug #4308 - Excel save operation corrupts file ACLs.
[sfrench/samba-autobuild/.git] / source3 / smbd / posix_acls.c
index 427cfc9a0d341524d179c5235e3ec800fe41e65e..951046c56253034882f4121894088a6e632fb1d8 100644 (file)
@@ -725,7 +725,7 @@ static int map_acl_perms_to_permset(connection_struct *conn, mode_t mode, SMB_AC
  Function to create owner and group SIDs from a SMB_STRUCT_STAT.
 ****************************************************************************/
 
-static void create_file_sids(const SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
+void create_file_sids(const SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
 {
        uid_to_sid( powner_sid, psbuf->st_uid );
        gid_to_sid( pgroup_sid, psbuf->st_gid );
@@ -870,7 +870,7 @@ static void merge_aces( canon_ace **pp_list_head )
  Check if we need to return NT4.x compatible ACL entries.
 ****************************************************************************/
 
-static bool nt4_compatible_acls(void)
+bool nt4_compatible_acls(void)
 {
        int compat = lp_acl_compatibility();
 
@@ -890,13 +890,12 @@ static bool nt4_compatible_acls(void)
  not get. Deny entries are implicit on get with ace->perms = 0.
 ****************************************************************************/
 
-static SEC_ACCESS map_canon_ace_perms(int snum,
+static uint32_t map_canon_ace_perms(int snum,
                                enum security_ace_type *pacl_type,
                                mode_t perms,
                                bool directory_ace)
 {
-       SEC_ACCESS sa;
-       uint32 nt_mask = 0;
+       uint32_t nt_mask = 0;
 
        *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
 
@@ -935,8 +934,7 @@ static SEC_ACCESS map_canon_ace_perms(int snum,
        DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
                        (unsigned int)perms, (unsigned int)nt_mask ));
 
-       init_sec_access(&sa,nt_mask);
-       return sa;
+       return nt_mask;
 }
 
 /****************************************************************************
@@ -988,7 +986,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)
+NTSTATUS unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, const SEC_DESC *psd)
 {
        DOM_SID owner_sid;
        DOM_SID grp_sid;
@@ -1329,11 +1327,13 @@ static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID
  Unpack a SEC_DESC into two canonical ace lists.
 ****************************************************************************/
 
-static bool create_canon_ace_lists(files_struct *fsp, SMB_STRUCT_STAT *pst,
-                                                       DOM_SID *pfile_owner_sid,
-                                                       DOM_SID *pfile_grp_sid,
-                                                       canon_ace **ppfile_ace, canon_ace **ppdir_ace,
-                                                       SEC_ACL *dacl)
+static bool create_canon_ace_lists(files_struct *fsp,
+                                       SMB_STRUCT_STAT *pst,
+                                       DOM_SID *pfile_owner_sid,
+                                       DOM_SID *pfile_grp_sid,
+                                       canon_ace **ppfile_ace,
+                                       canon_ace **ppdir_ace,
+                                       const SEC_ACL *dacl)
 {
        bool all_aces_are_inherit_only = (fsp->is_directory ? True : False);
        canon_ace *file_ace = NULL;
@@ -2016,12 +2016,14 @@ static mode_t create_default_mode(files_struct *fsp, bool interitable_mode)
  succeeding.
 ****************************************************************************/
 
-static bool unpack_canon_ace(files_struct *fsp, 
-                                                       SMB_STRUCT_STAT *pst,
-                                                       DOM_SID *pfile_owner_sid,
-                                                       DOM_SID *pfile_grp_sid,
-                                                       canon_ace **ppfile_ace, canon_ace **ppdir_ace,
-                                                       uint32 security_info_sent, SEC_DESC *psd)
+static bool unpack_canon_ace(files_struct *fsp,
+                               SMB_STRUCT_STAT *pst,
+                               DOM_SID *pfile_owner_sid,
+                               DOM_SID *pfile_grp_sid,
+                               canon_ace **ppfile_ace,
+                               canon_ace **ppdir_ace,
+                               uint32 security_info_sent,
+                               const SEC_DESC *psd)
 {
        canon_ace *file_ace = NULL;
        canon_ace *dir_ace = NULL;
@@ -2958,9 +2960,7 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
                         */
 
                        for (ace = file_ace; ace != NULL; ace = ace->next) {
-                               SEC_ACCESS acc;
-
-                               acc = map_canon_ace_perms(SNUM(conn),
+                               uint32_t acc = map_canon_ace_perms(SNUM(conn),
                                                &nt_acl_type,
                                                ace->perms,
                                                S_ISDIR(sbuf->st_mode));
@@ -2975,19 +2975,14 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
                        /* The User must have access to a profile share - even
                         * if we can't map the SID. */
                        if (lp_profile_acls(SNUM(conn))) {
-                               SEC_ACCESS acc;
-
-                               init_sec_access(&acc,FILE_GENERIC_ALL);
                                init_sec_ace(&nt_ace_list[num_aces++],
                                                &global_sid_Builtin_Users,
                                                SEC_ACE_TYPE_ACCESS_ALLOWED,
-                                               acc, 0);
+                                               FILE_GENERIC_ALL, 0);
                        }
 
                        for (ace = dir_ace; ace != NULL; ace = ace->next) {
-                               SEC_ACCESS acc;
-
-                               acc = map_canon_ace_perms(SNUM(conn),
+                               uint32_t acc = map_canon_ace_perms(SNUM(conn),
                                                &nt_acl_type,
                                                ace->perms,
                                                S_ISDIR(sbuf->st_mode));
@@ -3005,10 +3000,7 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
                        /* The User must have access to a profile share - even
                         * if we can't map the SID. */
                        if (lp_profile_acls(SNUM(conn))) {
-                               SEC_ACCESS acc;
-
-                               init_sec_access(&acc,FILE_GENERIC_ALL);
-                               init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc,
+                               init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, FILE_GENERIC_ALL,
                                                SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
                                                SEC_ACE_FLAG_INHERIT_ONLY|0);
                        }
@@ -3199,7 +3191,7 @@ int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
                return -1;
        }
 
-       if (!NT_STATUS_IS_OK(open_file_fchmod(conn,fname,&st,&fsp))) {
+       if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, fname, &st, &fsp))) {
                return -1;
        }
 
@@ -3214,56 +3206,63 @@ int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
        ret = SMB_VFS_FCHOWN(fsp, uid, (gid_t)-1);
        unbecome_root();
 
-       close_file_fchmod(fsp);
+       close_file_fchmod(NULL, fsp);
 
        return ret;
 }
 
+#if 0
+/* Disable this - prevents ACL inheritance from the ACL editor. JRA. */
+
 /****************************************************************************
  Take care of parent ACL inheritance.
 ****************************************************************************/
 
-static NTSTATUS append_parent_acl(files_struct *fsp,
-                               SMB_STRUCT_STAT *psbuf,
-                               SEC_DESC *psd,
+NTSTATUS append_parent_acl(files_struct *fsp,
+                               const SEC_DESC *pcsd,
                                SEC_DESC **pp_new_sd)
 {
        SEC_DESC *parent_sd = NULL;
        files_struct *parent_fsp = NULL;
-       TALLOC_CTX *mem_ctx = talloc_parent(psd);
+       TALLOC_CTX *mem_ctx = talloc_tos();
        char *parent_name = NULL;
        SEC_ACE *new_ace = NULL;
-       unsigned int num_aces = psd->dacl->num_aces;
+       unsigned int num_aces = pcsd->dacl->num_aces;
        SMB_STRUCT_STAT sbuf;
        NTSTATUS status;
        int info;
        unsigned int i, j;
-       bool is_dacl_protected = (psd->type & SE_DESC_DACL_PROTECTED);
+       SEC_DESC *psd = dup_sec_desc(talloc_tos(), pcsd);
+       bool is_dacl_protected = (pcsd->type & SE_DESC_DACL_PROTECTED);
 
        ZERO_STRUCT(sbuf);
 
-       if (mem_ctx == NULL) {
+       if (psd == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       if (!parent_dirname_talloc(mem_ctx,
-                               fsp->fsp_name,
-                               &parent_name,
-                               NULL)) {
+       if (!parent_dirname(mem_ctx, fsp->fsp_name, &parent_name, NULL)) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       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,
-                               &info,
-                               &parent_fsp);
+       status = SMB_VFS_CREATE_FILE(
+               fsp->conn,                              /* conn */
+               NULL,                                   /* req */
+               0,                                      /* root_dir_fid */
+               parent_name,                            /* fname */
+               0,                                      /* create_file_flags */
+               FILE_READ_ATTRIBUTES,                   /* access_mask */
+               FILE_SHARE_NONE,                        /* share_access */
+               FILE_OPEN,                              /* create_disposition*/
+               FILE_DIRECTORY_FILE,                    /* create_options */
+               0,                                      /* file_attributes */
+               INTERNAL_OPEN_ONLY,                     /* oplock_request */
+               0,                                      /* allocation_size */
+               NULL,                                   /* sd */
+               NULL,                                   /* ea_list */
+               &parent_fsp,                            /* result */
+               &info,                                  /* pinfo */
+               &sbuf);                                 /* psbuf */
 
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -3272,7 +3271,7 @@ static NTSTATUS append_parent_acl(files_struct *fsp,
        status = SMB_VFS_GET_NT_ACL(parent_fsp->conn, parent_fsp->fsp_name,
                                    DACL_SECURITY_INFORMATION, &parent_sd );
 
-       close_file(parent_fsp, NORMAL_CLOSE);
+       close_file(NULL, parent_fsp, NORMAL_CLOSE);
 
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -3398,12 +3397,15 @@ static NTSTATUS append_parent_acl(files_struct *fsp,
                        parent_name));
        }
 
-       parent_sd->dacl->aces = new_ace;
-       parent_sd->dacl->num_aces = i;
+       psd->dacl->aces = new_ace;
+       psd->dacl->num_aces = i;
+       psd->type &= ~(SE_DESC_DACL_AUTO_INHERITED|
+                         SE_DESC_DACL_AUTO_INHERIT_REQ);
 
-       *pp_new_sd = parent_sd;
+       *pp_new_sd = psd;
        return status;
 }
+#endif
 
 /****************************************************************************
  Reply to set a security descriptor on an fsp. security_info_sent is the
@@ -3411,7 +3413,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)
+NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC *psd)
 {
        connection_struct *conn = fsp->conn;
        uid_t user = (uid_t)-1;
@@ -3426,7 +3428,6 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
        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 ));
 
@@ -3462,14 +3463,12 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
        }
 
        /*
-        * Do we need to chown ?
+        * Do we need to chown ? If so this must be done first as the incoming
+        * CREATOR_OWNER acl will be relative to the *new* owner, not the old.
+        * Noticed by Simo.
         */
 
        if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp))) {
-               need_chown = True;
-       }
-
-       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 ));
@@ -3509,24 +3508,31 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
                orig_mode = sbuf.st_mode;
                orig_uid = sbuf.st_uid;
                orig_gid = sbuf.st_gid;
-
-               /* We did chown already, drop the flag */
-               need_chown = False;
        }
 
        create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
 
+#if 0
+       /* Disable this - prevents ACL inheritance from the ACL editor. JRA. */
+
+       /* See here: http://www.codeproject.com/KB/winsdk/accessctrl2.aspx
+        * for details and also the log trace in bug #4308. JRA.
+        */
+
        if ((security_info_sent & DACL_SECURITY_INFORMATION) &&
                psd->dacl != NULL &&
                (psd->type & (SE_DESC_DACL_AUTO_INHERITED|
                              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);
+               SEC_DESC *new_sd = NULL;
+               status = append_parent_acl(fsp, psd, &new_sd);
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }
+               psd = new_sd;
        }
+#endif
 
        acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
                                        &file_ace_list, &dir_ace_list, security_info_sent, psd);
@@ -3652,24 +3658,9 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
                }
 
                free_canon_ace_list(file_ace_list);
-               free_canon_ace_list(dir_ace_list); 
+               free_canon_ace_list(dir_ace_list);
        }
 
-       /* 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) ));
-                       if (errno == EPERM) {
-                               return NT_STATUS_INVALID_OWNER;
-                       }
-                       return map_nt_error_from_unix(errno);
-               }
-       }
-       
        return NT_STATUS_OK;
 }
 
@@ -4301,7 +4292,7 @@ SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
        finfo.fh->fd = -1;
        finfo.fsp_name = CONST_DISCARD(char *,fname);
 
-       if (!NT_STATUS_IS_OK(posix_fget_nt_acl( &finfo, DACL_SECURITY_INFORMATION, &psd))) {
+       if (!NT_STATUS_IS_OK(SMB_VFS_FGET_NT_ACL( &finfo, DACL_SECURITY_INFORMATION, &psd))) {
                DEBUG(0,("get_nt_acl_no_snum: get_nt_acl returned zero.\n"));
                conn_free_internal( conn );
                return NULL;