The posix acl version of set_nt_acl() could set the stat_ex
[samba.git] / source3 / smbd / posix_acls.c
index 627ca2e171f2288ba404fa1124222fcde1385d5d..828053811b291b2cf967f899ed350baf1964db81 100644 (file)
@@ -181,6 +181,7 @@ static char *create_pai_buf_v2(canon_ace *file_ace_list,
        char *entry_offset = NULL;
        unsigned int num_entries = 0;
        unsigned int num_def_entries = 0;
+       unsigned int i;
 
        for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) {
                num_entries++;
@@ -207,8 +208,12 @@ static char *create_pai_buf_v2(canon_ace *file_ace_list,
        SSVAL(pai_buf,PAI_V2_NUM_ENTRIES_OFFSET,num_entries);
        SSVAL(pai_buf,PAI_V2_NUM_DEFAULT_ENTRIES_OFFSET,num_def_entries);
 
+       DEBUG(10,("create_pai_buf_v2: sd_type = 0x%x\n",
+                       (unsigned int)sd_type ));
+
        entry_offset = pai_buf + PAI_V2_ENTRIES_BASE;
 
+       i = 0;
        for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) {
                uint8_t type_val = (uint8_t)ace_list->owner_type;
                uint32_t entry_val = get_entry_val(ace_list);
@@ -216,6 +221,12 @@ static char *create_pai_buf_v2(canon_ace *file_ace_list,
                SCVAL(entry_offset,0,ace_list->ace_flags);
                SCVAL(entry_offset,1,type_val);
                SIVAL(entry_offset,2,entry_val);
+               DEBUG(10,("create_pai_buf_v2: entry %u [0x%x] [0x%x] [0x%x]\n",
+                       i,
+                       (unsigned int)ace_list->ace_flags,
+                       (unsigned int)type_val,
+                       (unsigned int)entry_val ));
+               i++;
                entry_offset += PAI_V2_ENTRY_LENGTH;
        }
 
@@ -226,6 +237,12 @@ static char *create_pai_buf_v2(canon_ace *file_ace_list,
                SCVAL(entry_offset,0,ace_list->ace_flags);
                SCVAL(entry_offset,1,type_val);
                SIVAL(entry_offset,2,entry_val);
+               DEBUG(10,("create_pai_buf_v2: entry %u [0x%x] [0x%x] [0x%x]\n",
+                       i,
+                       (unsigned int)ace_list->ace_flags,
+                       (unsigned int)type_val,
+                       (unsigned int)entry_val ));
+               i++;
                entry_offset += PAI_V2_ENTRY_LENGTH;
        }
 
@@ -256,15 +273,16 @@ static void store_inheritance_attributes(files_struct *fsp,
                ret = SMB_VFS_FSETXATTR(fsp, SAMBA_POSIX_INHERITANCE_EA_NAME,
                                pai_buf, store_size, 0);
        } else {
-               ret = SMB_VFS_SETXATTR(fsp->conn,fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME,
-                               pai_buf, store_size, 0);
+               ret = SMB_VFS_SETXATTR(fsp->conn, fsp->fsp_name->base_name,
+                                      SAMBA_POSIX_INHERITANCE_EA_NAME,
+                                      pai_buf, store_size, 0);
        }
 
        SAFE_FREE(pai_buf);
 
        DEBUG(10,("store_inheritance_attribute: type 0x%x for file %s\n",
                (unsigned int)sd_type,
-               fsp->fsp_name));
+               fsp_str_dbg(fsp)));
 
        if (ret == -1 && !no_acl_syscall_error(errno)) {
                DEBUG(1,("store_inheritance_attribute: Error %s\n", strerror(errno) ));
@@ -399,6 +417,8 @@ static bool get_pai_owner_type(struct pai_entry *paie, const char *entry_offset)
                        DEBUG(10,("get_pai_owner_type: world ace\n"));
                        break;
                default:
+                       DEBUG(10,("get_pai_owner_type: unknown type %u\n",
+                               (unsigned int)paie->owner_type ));
                        return false;
        }
        return true;
@@ -485,12 +505,13 @@ static struct pai_val *create_pai_val_v1(const char *buf, size_t size)
 ************************************************************************/
 
 static const char *create_pai_v2_entries(struct pai_val *paiv,
+                               unsigned int num_entries,
                                const char *entry_offset,
                                bool def_entry)
 {
-       int i;
+       unsigned int i;
 
-       for (i = 0; i < paiv->num_entries; i++) {
+       for (i = 0; i < num_entries; i++) {
                struct pai_entry *paie = SMB_MALLOC_P(struct pai_entry);
                if (!paie) {
                        return NULL;
@@ -498,9 +519,7 @@ static const char *create_pai_v2_entries(struct pai_val *paiv,
 
                paie->ace_flags = CVAL(entry_offset,0);
 
-               entry_offset++;
-
-               if (!get_pai_owner_type(paie, entry_offset)) {
+               if (!get_pai_owner_type(paie, entry_offset+1)) {
                        return NULL;
                }
                if (!def_entry) {
@@ -540,15 +559,18 @@ static struct pai_val *create_pai_val_v2(const char *buf, size_t size)
 
        entry_offset = buf + PAI_V2_ENTRIES_BASE;
 
-       DEBUG(10,("create_pai_val_v2: num_entries = %u, num_def_entries = %u\n",
+       DEBUG(10,("create_pai_val_v2: sd_type = 0x%x num_entries = %u, num_def_entries = %u\n",
+                       (unsigned int)paiv->sd_type,
                        paiv->num_entries, paiv->num_def_entries ));
 
-       entry_offset = create_pai_v2_entries(paiv, entry_offset, false);
+       entry_offset = create_pai_v2_entries(paiv, paiv->num_entries,
+                               entry_offset, false);
        if (entry_offset == NULL) {
                free_inherited_info(paiv);
                return NULL;
        }
-       entry_offset = create_pai_v2_entries(paiv, entry_offset, true);
+       entry_offset = create_pai_v2_entries(paiv, paiv->num_def_entries,
+                               entry_offset, true);
        if (entry_offset == NULL) {
                free_inherited_info(paiv);
                return NULL;
@@ -599,8 +621,10 @@ static struct pai_val *fload_inherited_info(files_struct *fsp)
                        ret = SMB_VFS_FGETXATTR(fsp, SAMBA_POSIX_INHERITANCE_EA_NAME,
                                        pai_buf, pai_buf_size);
                } else {
-                       ret = SMB_VFS_GETXATTR(fsp->conn,fsp->fsp_name,SAMBA_POSIX_INHERITANCE_EA_NAME,
-                                       pai_buf, pai_buf_size);
+                       ret = SMB_VFS_GETXATTR(fsp->conn,
+                                              fsp->fsp_name->base_name,
+                                              SAMBA_POSIX_INHERITANCE_EA_NAME,
+                                              pai_buf, pai_buf_size);
                }
 
                if (ret == -1) {
@@ -618,7 +642,8 @@ static struct pai_val *fload_inherited_info(files_struct *fsp)
                }
        } while (ret == -1);
 
-       DEBUG(10,("load_inherited_info: ret = %lu for file %s\n", (unsigned long)ret, fsp->fsp_name));
+       DEBUG(10,("load_inherited_info: ret = %lu for file %s\n",
+                 (unsigned long)ret, fsp_str_dbg(fsp)));
 
        if (ret == -1) {
                /* No attribute or not supported. */
@@ -637,8 +662,7 @@ static struct pai_val *fload_inherited_info(files_struct *fsp)
 
        if (paiv) {
                DEBUG(10,("load_inherited_info: ACL type is 0x%x for file %s\n",
-                       (unsigned int)paiv->sd_type,
-                       fsp->fsp_name));
+                         (unsigned int)paiv->sd_type, fsp_str_dbg(fsp)));
        }
 
        SAFE_FREE(pai_buf);
@@ -888,34 +912,13 @@ void create_file_sids(const SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID
        gid_to_sid( pgroup_sid, psbuf->st_ex_gid );
 }
 
-/****************************************************************************
- Is the identity in two ACEs equal ? Check both SID and uid/gid.
-****************************************************************************/
-
-static bool identity_in_ace_equal(canon_ace *ace1, canon_ace *ace2)
-{
-       if (sid_equal(&ace1->trustee, &ace2->trustee)) {
-               return True;
-       }
-       if (ace1->owner_type == ace2->owner_type) {
-               if (ace1->owner_type == UID_ACE &&
-                               ace1->unix_ug.uid == ace2->unix_ug.uid) {
-                       return True;
-               } else if (ace1->owner_type == GID_ACE &&
-                               ace1->unix_ug.gid == ace2->unix_ug.gid) {
-                       return True;
-               }
-       }
-       return False;
-}
-
 /****************************************************************************
  Merge aces with a common sid - if both are allow or deny, OR the permissions together and
  delete the second one. If the first is deny, mask the permissions off and delete the allow
  if the permissions become zero, delete the deny if the permissions are non zero.
 ****************************************************************************/
 
-static void merge_aces( canon_ace **pp_list_head )
+static void merge_aces( canon_ace **pp_list_head, bool dir_acl)
 {
        canon_ace *l_head = *pp_list_head;
        canon_ace *curr_ace_outer;
@@ -933,12 +936,24 @@ static void merge_aces( canon_ace **pp_list_head )
                curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
 
                for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
+                       bool can_merge = false;
 
                        curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
 
-                       if (identity_in_ace_equal(curr_ace, curr_ace_outer) &&
-                               (curr_ace->attr == curr_ace_outer->attr)) {
+                       /* For file ACLs we can merge if the SIDs and ALLOW/DENY
+                        * types are the same. For directory acls we must also
+                        * ensure the POSIX ACL types are the same. */
 
+                       if (!dir_acl) {
+                               can_merge = (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
+                                               (curr_ace->attr == curr_ace_outer->attr));
+                       } else {
+                               can_merge = (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
+                                               (curr_ace->type == curr_ace_outer->type) &&
+                                               (curr_ace->attr == curr_ace_outer->attr));
+                       }
+
+                       if (can_merge) {
                                if( DEBUGLVL( 10 )) {
                                        dbgtext("merge_aces: Merging ACE's\n");
                                        print_canon_ace( curr_ace_outer, 0);
@@ -947,7 +962,13 @@ static void merge_aces( canon_ace **pp_list_head )
 
                                /* Merge two allow or two deny ACE's. */
 
+                               /* Theoretically we shouldn't merge a dir ACE if
+                                * one ACE has the CI flag set, and the other
+                                * ACE has the OI flag set, but this is rare
+                                * enough we can ignore it. */
+
                                curr_ace_outer->perms |= curr_ace->perms;
+                               curr_ace_outer->ace_flags |= curr_ace->ace_flags;
                                DLIST_REMOVE(l_head, curr_ace);
                                SAFE_FREE(curr_ace);
                                curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
@@ -976,7 +997,7 @@ static void merge_aces( canon_ace **pp_list_head )
                         * we've put on the ACL, we know the deny must be the first one.
                         */
 
-                       if (identity_in_ace_equal(curr_ace, curr_ace_outer) &&
+                       if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
                                (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
 
                                if( DEBUGLVL( 10 )) {
@@ -1047,7 +1068,7 @@ bool nt4_compatible_acls(void)
  not get. Deny entries are implicit on get with ace->perms = 0.
 ****************************************************************************/
 
-static uint32_t map_canon_ace_perms(int snum,
+uint32_t map_canon_ace_perms(int snum,
                                enum security_ace_type *pacl_type,
                                mode_t perms,
                                bool directory_ace)
@@ -1500,12 +1521,56 @@ static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID
                DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n"));
 }
 
+/****************************************************************************
+ If an ACE entry is SMB_ACL_USER_OBJ and not CREATOR_OWNER, map to SMB_ACL_USER.
+ If an ACE entry is SMB_ACL_GROUP_OBJ and not CREATOR_GROUP, map to SMB_ACL_GROUP
+****************************************************************************/
+
+static bool dup_owning_ace(canon_ace *dir_ace, canon_ace *ace)
+{
+       /* dir ace must be followings.
+          SMB_ACL_USER_OBJ : trustee(CREATOR_OWNER) -> Posix ACL d:u::perm
+          SMB_ACL_USER     : not trustee    -> Posix ACL u:user:perm
+          SMB_ACL_USER_OBJ : trustee -> convert to SMB_ACL_USER : trustee
+          Posix ACL u:trustee:perm
+
+          SMB_ACL_GROUP_OBJ: trustee(CREATOR_GROUP) -> Posix ACL d:g::perm
+          SMB_ACL_GROUP    : not trustee   -> Posix ACL g:group:perm
+          SMB_ACL_GROUP_OBJ: trustee -> convert to SMB_ACL_GROUP : trustee
+          Posix ACL g:trustee:perm
+       */
+
+       if (ace->type == SMB_ACL_USER_OBJ &&
+                       !(sid_equal(&ace->trustee, &global_sid_Creator_Owner))) {
+               canon_ace *dup_ace = dup_canon_ace(ace);
+
+               if (dup_ace == NULL) {
+                       return false;
+               }
+               dup_ace->type = SMB_ACL_USER;
+               DLIST_ADD_END(dir_ace, dup_ace, canon_ace *);
+       }
+
+       if (ace->type == SMB_ACL_GROUP_OBJ &&
+                       !(sid_equal(&ace->trustee, &global_sid_Creator_Group))) {
+               canon_ace *dup_ace = dup_canon_ace(ace);
+
+               if (dup_ace == NULL) {
+                       return false;
+               }
+               dup_ace->type = SMB_ACL_GROUP;
+               DLIST_ADD_END(dir_ace, dup_ace, canon_ace *);
+       }
+
+       return true;
+}
+
 /****************************************************************************
  Unpack a SEC_DESC into two canonical ace lists.
 ****************************************************************************/
 
 static bool create_canon_ace_lists(files_struct *fsp,
-                                       SMB_STRUCT_STAT *pst,
+                                       const SMB_STRUCT_STAT *pst,
                                        DOM_SID *pfile_owner_sid,
                                        DOM_SID *pfile_grp_sid,
                                        canon_ace **ppfile_ace,
@@ -1631,11 +1696,11 @@ static bool create_canon_ace_lists(files_struct *fsp,
                        /*
                         * The Creator Owner entry only specifies inheritable permissions,
                         * never access permissions. WinNT doesn't always set the ACE to
-                        *INHERIT_ONLY, though.
+                        * INHERIT_ONLY, though.
                         */
 
-                       if (nt4_compatible_acls())
-                               psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+                       psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+
                } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Group)) {
                        current_ace->owner_type = GID_ACE;
                        current_ace->unix_ug.gid = pst->st_ex_gid;
@@ -1644,10 +1709,9 @@ static bool create_canon_ace_lists(files_struct *fsp,
                        /*
                         * The Creator Group entry only specifies inheritable permissions,
                         * never access permissions. WinNT doesn't always set the ACE to
-                        *INHERIT_ONLY, though.
+                        * INHERIT_ONLY, though.
                         */
-                       if (nt4_compatible_acls())
-                               psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+                       psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
 
                } else if (sid_to_uid( &current_ace->trustee, &current_ace->unix_ug.uid)) {
                        current_ace->owner_type = UID_ACE;
@@ -1727,8 +1791,12 @@ static bool create_canon_ace_lists(files_struct *fsp,
                                        got_dir_allow = True;
 
                                if ((current_ace->attr == DENY_ACE) && got_dir_allow) {
-                                       DEBUG(0,("create_canon_ace_lists: malformed ACL in inheritable ACL ! \
-Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
+                                       DEBUG(0,("create_canon_ace_lists: "
+                                                "malformed ACL in "
+                                                "inheritable ACL! Deny entry "
+                                                "after Allow entry. Failing "
+                                                "to set on file %s.\n",
+                                                fsp_str_dbg(fsp)));
                                        free_canon_ace_list(file_ace);
                                        free_canon_ace_list(dir_ace);
                                        return False;
@@ -1739,6 +1807,34 @@ Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
                                        print_canon_ace( current_ace, 0);
                                }
 
+                               /*
+                                * We have a lossy mapping: directory ACE entries
+                                * CREATOR_OWNER ------\
+                                *     (map to)         +---> SMB_ACL_USER_OBJ
+                                * owning sid    ------/
+                                *
+                                * CREATOR_GROUP ------\
+                                *     (map to)         +---> SMB_ACL_GROUP_OBJ
+                                * primary group sid --/
+                                *
+                                * on set. And on read of a directory ACL
+                                *
+                                * SMB_ACL_USER_OBJ ----> CREATOR_OWNER
+                                * SMB_ACL_GROUP_OBJ ---> CREATOR_GROUP.
+                                *
+                                * Deal with this on set by duplicating
+                                * owning sid and primary group sid ACE
+                                * entries into the directory ACL.
+                                * Fix from Tsukasa Hamano <hamano@osstech.co.jp>.
+                                */
+
+                               if (!dup_owning_ace(dir_ace, current_ace)) {
+                                       DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
+                                       free_canon_ace_list(file_ace);
+                                       free_canon_ace_list(dir_ace);
+                                       return false;
+                               }
+
                                /*
                                 * If this is not an inherit only ACE we need to add a duplicate
                                 * to the file acl.
@@ -1759,6 +1855,13 @@ Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
                                         * pointer is now owned by the dir_ace list.
                                         */
                                        current_ace = dup_ace;
+                                       /* We've essentially split this ace into two,
+                                        * and added the ace with inheritance request
+                                        * bits to the directory ACL. Drop those bits for
+                                        * the ACE we're adding to the file list. */
+                                       current_ace->ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
+                                                               SEC_ACE_FLAG_CONTAINER_INHERIT|
+                                                               SEC_ACE_FLAG_INHERIT_ONLY);
                                } else {
                                        /*
                                         * We must not free current_ace here as its
@@ -1785,8 +1888,10 @@ Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
                                got_file_allow = True;
 
                        if ((current_ace->attr == DENY_ACE) && got_file_allow) {
-                               DEBUG(0,("create_canon_ace_lists: malformed ACL in file ACL ! \
-Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
+                               DEBUG(0,("create_canon_ace_lists: malformed "
+                                        "ACL in file ACL ! Deny entry after "
+                                        "Allow entry. Failing to set on file "
+                                        "%s.\n", fsp_str_dbg(fsp)));
                                free_canon_ace_list(file_ace);
                                free_canon_ace_list(dir_ace);
                                return False;
@@ -2166,10 +2271,14 @@ static mode_t create_default_mode(files_struct *fsp, bool interitable_mode)
        int snum = SNUM(fsp->conn);
        mode_t and_bits = (mode_t)0;
        mode_t or_bits = (mode_t)0;
-       mode_t mode = interitable_mode
-               ? unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name,
-                            NULL )
-               : S_IRUSR;
+       mode_t mode;
+
+       if (interitable_mode) {
+               mode = unix_mode(fsp->conn, FILE_ATTRIBUTE_ARCHIVE,
+                                fsp->fsp_name, NULL);
+       } else {
+               mode = S_IRUSR;
+       }
 
        if (fsp->is_directory)
                mode |= (S_IWUSR|S_IXUSR);
@@ -2196,7 +2305,7 @@ static mode_t create_default_mode(files_struct *fsp, bool interitable_mode)
 ****************************************************************************/
 
 static bool unpack_canon_ace(files_struct *fsp,
-                               SMB_STRUCT_STAT *pst,
+                               const SMB_STRUCT_STAT *pst,
                                DOM_SID *pfile_owner_sid,
                                DOM_SID *pfile_grp_sid,
                                canon_ace **ppfile_ace,
@@ -2204,6 +2313,7 @@ static bool unpack_canon_ace(files_struct *fsp,
                                uint32 security_info_sent,
                                const SEC_DESC *psd)
 {
+       SMB_STRUCT_STAT st;
        canon_ace *file_ace = NULL;
        canon_ace *dir_ace = NULL;
 
@@ -2243,10 +2353,10 @@ static bool unpack_canon_ace(files_struct *fsp,
         */
 
        print_canon_ace_list( "file ace - before merge", file_ace);
-       merge_aces( &file_ace );
+       merge_aces( &file_ace, false);
 
        print_canon_ace_list( "dir ace - before merge", dir_ace);
-       merge_aces( &dir_ace );
+       merge_aces( &dir_ace, true);
 
        /*
         * NT ACLs are order dependent. Go through the acl lists and
@@ -2267,14 +2377,17 @@ static bool unpack_canon_ace(files_struct *fsp,
 
        print_canon_ace_list( "file ace - before valid", file_ace);
 
+       st = *pst;
+
        /*
         * A default 3 element mode entry for a file should be r-- --- ---.
         * A default 3 element mode entry for a directory should be rwx --- ---.
         */
 
-       pst->st_ex_mode = create_default_mode(fsp, False);
+       st.st_ex_mode = create_default_mode(fsp, False);
 
-       if (!ensure_canon_entry_valid(&file_ace, fsp->conn->params, fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst, True)) {
+       if (!ensure_canon_entry_valid(&file_ace, fsp->conn->params,
+                       fsp->is_directory, pfile_owner_sid, pfile_grp_sid, &st, True)) {
                free_canon_ace_list(file_ace);
                free_canon_ace_list(dir_ace);
                return False;
@@ -2288,9 +2401,10 @@ static bool unpack_canon_ace(files_struct *fsp,
         * it's a directory.
         */
 
-       pst->st_ex_mode = create_default_mode(fsp, True);
+       st.st_ex_mode = create_default_mode(fsp, True);
 
-       if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp->conn->params, fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst, True)) {
+       if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp->conn->params,
+                       fsp->is_directory, pfile_owner_sid, pfile_grp_sid, &st, True)) {
                free_canon_ace_list(file_ace);
                free_canon_ace_list(dir_ace);
                return False;
@@ -2412,17 +2526,6 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn,
                                                DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
                                                continue;
                                        }
-                                       /*
-                                        * A SMB_ACL_USER entry for the owner is shadowed by the
-                                        * SMB_ACL_USER_OBJ entry and Windows also cannot represent
-                                        * that entry, so we ignore it. We also don't create such
-                                        * entries out of the blue when setting ACLs, so a get/set
-                                        * cycle will drop them.
-                                        */
-                                       if (the_acl_type == SMB_ACL_TYPE_ACCESS && *puid == psbuf->st_ex_uid) {
-                                               SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
-                                               continue;
-                                       }
                                        uid_to_sid( &sid, *puid);
                                        unix_ug.uid = *puid;
                                        owner_type = UID_ACE;
@@ -2547,36 +2650,23 @@ static bool current_user_in_group(gid_t gid)
 ****************************************************************************/
 
 static bool acl_group_override(connection_struct *conn,
-                               const SMB_STRUCT_STAT *psbuf,
-                               const char *fname)
+                              const struct smb_filename *smb_fname)
 {
-       struct smb_filename *smb_fname = NULL;
-       NTSTATUS status;
-
        if ((errno != EPERM) && (errno != EACCES)) {
                return false;
        }
 
        /* file primary group == user primary or supplementary group */
        if (lp_acl_group_control(SNUM(conn)) &&
-                       current_user_in_group(psbuf->st_ex_gid)) {
+           current_user_in_group(smb_fname->st.st_ex_gid)) {
                return true;
        }
 
-       status = create_synthetic_smb_fname_split(talloc_tos(), fname, psbuf,
-                                                 &smb_fname);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               return false;
-       }
-
        /* user has writeable permission */
        if (lp_dos_filemode(SNUM(conn)) &&
            can_write_to_file(conn, smb_fname)) {
-               TALLOC_FREE(smb_fname);
                return true;
        }
-       TALLOC_FREE(smb_fname);
 
        return false;
 }
@@ -2603,6 +2693,9 @@ static bool set_canon_ace_list(files_struct *fsp,
        bool needs_mask = False;
        mode_t mask_perms = 0;
 
+       /* Use the psbuf that was passed in. */
+       fsp->fsp_name->st = *psbuf;
+
 #if defined(POSIX_ACL_NEEDS_MASK)
        /* HP-UX always wants to have a mask (called "class" there). */
        needs_mask = True;
@@ -2619,7 +2712,7 @@ static bool set_canon_ace_list(files_struct *fsp,
                                default_ace ? "default" : "file", strerror(errno) ));
                }
                *pacl_set_support = False;
-               return False;
+               goto fail;
        }
 
        if( DEBUGLVL( 10 )) {
@@ -2759,7 +2852,8 @@ static bool set_canon_ace_list(files_struct *fsp,
         */
 
        if(default_ace || fsp->is_directory || fsp->fh->fd == -1) {
-               if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl) == -1) {
+               if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name->base_name,
+                                            the_acl_type, the_acl) == -1) {
                        /*
                         * Some systems allow all the above calls and only fail with no ACL support
                         * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
@@ -2768,14 +2862,18 @@ static bool set_canon_ace_list(files_struct *fsp,
                                *pacl_set_support = False;
                        }
 
-                       if (acl_group_override(conn, psbuf, fsp->fsp_name)) {
+                       if (acl_group_override(conn, fsp->fsp_name)) {
                                int sret;
 
-                               DEBUG(5,("set_canon_ace_list: acl group control on and current user in file %s primary group.\n",
-                                       fsp->fsp_name ));
+                               DEBUG(5,("set_canon_ace_list: acl group "
+                                        "control on and current user in file "
+                                        "%s primary group.\n",
+                                        fsp_str_dbg(fsp)));
 
                                become_root();
-                               sret = SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl);
+                               sret = SMB_VFS_SYS_ACL_SET_FILE(conn,
+                                   fsp->fsp_name->base_name, the_acl_type,
+                                   the_acl);
                                unbecome_root();
                                if (sret == 0) {
                                        ret = True;     
@@ -2783,9 +2881,12 @@ static bool set_canon_ace_list(files_struct *fsp,
                        }
 
                        if (ret == False) {
-                               DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
-                                               the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
-                                               fsp->fsp_name, strerror(errno) ));
+                               DEBUG(2,("set_canon_ace_list: "
+                                        "sys_acl_set_file type %s failed for "
+                                        "file %s (%s).\n",
+                                        the_acl_type == SMB_ACL_TYPE_DEFAULT ?
+                                        "directory default" : "file",
+                                        fsp_str_dbg(fsp), strerror(errno)));
                                goto fail;
                        }
                }
@@ -2799,11 +2900,13 @@ static bool set_canon_ace_list(files_struct *fsp,
                                *pacl_set_support = False;
                        }
 
-                       if (acl_group_override(conn, psbuf, fsp->fsp_name)) {
+                       if (acl_group_override(conn, fsp->fsp_name)) {
                                int sret;
 
-                               DEBUG(5,("set_canon_ace_list: acl group control on and current user in file %s primary group.\n",
-                                       fsp->fsp_name ));
+                               DEBUG(5,("set_canon_ace_list: acl group "
+                                        "control on and current user in file "
+                                        "%s primary group.\n",
+                                        fsp_str_dbg(fsp)));
 
                                become_root();
                                sret = SMB_VFS_SYS_ACL_SET_FD(fsp, the_acl);
@@ -2814,8 +2917,10 @@ static bool set_canon_ace_list(files_struct *fsp,
                        }
 
                        if (ret == False) {
-                               DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
-                                               fsp->fsp_name, strerror(errno) ));
+                               DEBUG(2,("set_canon_ace_list: "
+                                        "sys_acl_set_file failed for file %s "
+                                        "(%s).\n",
+                                        fsp_str_dbg(fsp), strerror(errno)));
                                goto fail;
                        }
                }
@@ -2883,8 +2988,9 @@ static bool convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file
        mode_t or_bits;
 
        if (ace_count != 3) {
-               DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \
-posix perms.\n", fsp->fsp_name ));
+               DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE "
+                        "entries for file %s to convert to posix perms.\n",
+                        fsp_str_dbg(fsp)));
                return False;
        }
 
@@ -2898,8 +3004,8 @@ posix perms.\n", fsp->fsp_name ));
        }
 
        if (!owner_ace || !group_ace || !other_ace) {
-               DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n",
-                               fsp->fsp_name ));
+               DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get "
+                        "standard entries for file %s.\n", fsp_str_dbg(fsp)));
                return False;
        }
 
@@ -2933,9 +3039,10 @@ posix perms.\n", fsp->fsp_name ));
 
        *posix_perms = (((*posix_perms) & and_bits)|or_bits);
 
-       DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n",
-               (int)owner_ace->perms, (int)group_ace->perms, (int)other_ace->perms, (int)*posix_perms,
-               fsp->fsp_name ));
+       DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o "
+                 "to perm=0%o for file %s.\n", (int)owner_ace->perms,
+                 (int)group_ace->perms, (int)other_ace->perms,
+                 (int)*posix_perms, fsp_str_dbg(fsp)));
 
        return True;
 }
@@ -3328,11 +3435,12 @@ NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info,
 
        *ppdesc = NULL;
 
-       DEBUG(10,("posix_fget_nt_acl: called for file %s\n", fsp->fsp_name ));
+       DEBUG(10,("posix_fget_nt_acl: called for file %s\n",
+                 fsp_str_dbg(fsp)));
 
        /* can it happen that fsp_name == NULL ? */
        if (fsp->is_directory ||  fsp->fh->fd == -1) {
-               return posix_get_nt_acl(fsp->conn, fsp->fsp_name,
+               return posix_get_nt_acl(fsp->conn, fsp->fsp_name->base_name,
                                        security_info, ppdesc);
        }
 
@@ -3346,24 +3454,35 @@ NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info,
 
        pal = fload_inherited_info(fsp);
 
-       return posix_get_nt_acl_common(fsp->conn, fsp->fsp_name, &sbuf, pal,
-                                      posix_acl, NULL, security_info, ppdesc);
+       return posix_get_nt_acl_common(fsp->conn, fsp->fsp_name->base_name,
+                                      &sbuf, pal, posix_acl, NULL,
+                                      security_info, ppdesc);
 }
 
 NTSTATUS posix_get_nt_acl(struct connection_struct *conn, const char *name,
                          uint32_t security_info, SEC_DESC **ppdesc)
 {
-       SMB_STRUCT_STAT sbuf;
        SMB_ACL_T posix_acl = NULL;
        SMB_ACL_T def_acl = NULL;
        struct pai_val *pal;
+       struct smb_filename smb_fname;
+       int ret;
 
        *ppdesc = NULL;
 
        DEBUG(10,("posix_get_nt_acl: called for file %s\n", name ));
 
+       ZERO_STRUCT(smb_fname);
+       smb_fname.base_name = discard_const_p(char, name);
+
        /* Get the stat struct for the owner info. */
-       if(vfs_stat_smb_fname(conn, name, &sbuf) != 0) {
+       if (lp_posix_pathnames()) {
+               ret = SMB_VFS_LSTAT(conn, &smb_fname);
+       } else {
+               ret = SMB_VFS_STAT(conn, &smb_fname);
+       }
+
+       if (ret == -1) {
                return map_nt_error_from_unix(errno);
        }
 
@@ -3371,15 +3490,16 @@ NTSTATUS posix_get_nt_acl(struct connection_struct *conn, const char *name,
        posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, name, SMB_ACL_TYPE_ACCESS);
 
        /* If it's a directory get the default POSIX ACL. */
-       if(S_ISDIR(sbuf.st_ex_mode)) {
+       if(S_ISDIR(smb_fname.st.st_ex_mode)) {
                def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, name, SMB_ACL_TYPE_DEFAULT);
                def_acl = free_empty_sys_acl(conn, def_acl);
        }
 
        pal = load_inherited_info(conn, name);
 
-       return posix_get_nt_acl_common(conn, name, &sbuf, pal, posix_acl,
-                                      def_acl, security_info, ppdesc);
+       return posix_get_nt_acl_common(conn, name, &smb_fname.st, pal,
+                                      posix_acl, def_acl, security_info,
+                                      ppdesc);
 }
 
 /****************************************************************************
@@ -3392,11 +3512,11 @@ NTSTATUS posix_get_nt_acl(struct connection_struct *conn, const char *name,
      then allow chown to the currently authenticated user.
 ****************************************************************************/
 
-int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
+int try_chown(connection_struct *conn, struct smb_filename *smb_fname,
+             uid_t uid, gid_t gid)
 {
        int ret;
        files_struct *fsp;
-       SMB_STRUCT_STAT st;
 
        if(!CAN_WRITE(conn)) {
                return -1;
@@ -3404,7 +3524,12 @@ int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
 
        /* Case (1). */
        /* try the direct way first */
-       ret = SMB_VFS_CHOWN(conn, fname, uid, gid);
+       if (lp_posix_pathnames()) {
+               ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, uid, gid);
+       } else {
+               ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid, gid);
+       }
+
        if (ret == 0)
                return 0;
 
@@ -3423,7 +3548,13 @@ int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
 
                        become_root();
                        /* Keep the current file gid the same - take ownership doesn't imply group change. */
-                       ret = SMB_VFS_CHOWN(conn, fname, uid, (gid_t)-1);
+                       if (lp_posix_pathnames()) {
+                               ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, uid,
+                                                   (gid_t)-1);
+                       } else {
+                               ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid,
+                                                   (gid_t)-1);
+                       }
                        unbecome_root();
                        return ret;
                }
@@ -3444,17 +3575,33 @@ int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
                return -1;
        }
 
-       if (vfs_stat_smb_fname(conn,fname,&st)) {
+       if (lp_posix_pathnames()) {
+               ret = SMB_VFS_LSTAT(conn, smb_fname);
+       } else {
+               ret = SMB_VFS_STAT(conn, smb_fname);
+       }
+
+       if (ret == -1) {
                return -1;
        }
 
-       if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, fname, &st, &fsp))) {
+       if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname, &fsp))) {
                return -1;
        }
 
        become_root();
        /* Keep the current file gid the same. */
-       ret = SMB_VFS_FCHOWN(fsp, uid, (gid_t)-1);
+       if (fsp->fh->fd == -1) {
+               if (lp_posix_pathnames()) {
+                       ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, uid,
+                                           (gid_t)-1);
+               } else {
+                       ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid,
+                                           (gid_t)-1);
+               }
+       } else {
+               ret = SMB_VFS_FCHOWN(fsp, uid, (gid_t)-1);
+       }
        unbecome_root();
 
        close_file_fchmod(NULL, fsp);
@@ -3490,12 +3637,13 @@ NTSTATUS append_parent_acl(files_struct *fsp,
                return NT_STATUS_NO_MEMORY;
        }
 
-       if (!parent_dirname(mem_ctx, fsp->fsp_name, &parent_name, NULL)) {
+       if (!parent_dirname(mem_ctx, fsp->fsp_name->base_name, &parent_name,
+                           NULL)) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       status = create_synthetic_smb_fname_split(mem_ctx, parent_name, NULL,
-                                                 &smb_dname);
+       status = create_synthetic_smb_fname(mem_ctx, parent_name, NULL, NULL,
+                                           &smb_dname);
        if (!NT_STATUS_IS_OK(status)) {
                goto fail;
        }
@@ -3517,16 +3665,16 @@ NTSTATUS append_parent_acl(files_struct *fsp,
                &parent_fsp,                            /* result */
                &info);                                 /* pinfo */
 
-       TALLOC_FREE(smb_fname);
-
        if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(smb_dname);
                return status;
        }
 
-       status = SMB_VFS_GET_NT_ACL(parent_fsp->conn, parent_fsp->fsp_name,
+       status = SMB_VFS_GET_NT_ACL(parent_fsp->conn, smb_dname->base_name,
                                    DACL_SECURITY_INFORMATION, &parent_sd );
 
        close_file(NULL, parent_fsp, NORMAL_CLOSE);
+       TALLOC_FREE(smb_dname);
 
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -3572,7 +3720,7 @@ NTSTATUS append_parent_acl(files_struct *fsp,
                                        "ignoring non container "
                                        "inherit flags %u on ACE with sid %s "
                                        "from parent %s\n",
-                                       fsp->fsp_name,
+                                       fsp_str_dbg(fsp),
                                        (unsigned int)se->flags,
                                        sid_string_dbg(&se->trustee),
                                        parent_name));
@@ -3585,7 +3733,7 @@ NTSTATUS append_parent_acl(files_struct *fsp,
                                        "ignoring non object "
                                        "inherit flags %u on ACE with sid %s "
                                        "from parent %s\n",
-                                       fsp->fsp_name,
+                                       fsp_str_dbg(fsp),
                                        (unsigned int)se->flags,
                                        sid_string_dbg(&se->trustee),
                                        parent_name));
@@ -3609,7 +3757,7 @@ NTSTATUS append_parent_acl(files_struct *fsp,
                                DEBUG(10,("append_parent_acl: path %s "
                                        "ignoring ACE with protected sid %s "
                                        "from parent %s\n",
-                                       fsp->fsp_name,
+                                       fsp_str_dbg(fsp),
                                        sid_string_dbg(&se->trustee),
                                        parent_name));
                                continue;
@@ -3647,7 +3795,7 @@ NTSTATUS append_parent_acl(files_struct *fsp,
                DEBUG(10,("append_parent_acl: path %s "
                        "inheriting ACE with sid %s "
                        "from parent %s\n",
-                       fsp->fsp_name,
+                       fsp_str_dbg(fsp),
                        sid_string_dbg(&se->trustee),
                        parent_name));
        }
@@ -3673,7 +3821,6 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
        connection_struct *conn = fsp->conn;
        uid_t user = (uid_t)-1;
        gid_t grp = (gid_t)-1;
-       SMB_STRUCT_STAT sbuf;
        DOM_SID file_owner_sid;
        DOM_SID file_grp_sid;
        canon_ace *file_ace_list = NULL;
@@ -3685,7 +3832,8 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
        bool acl_set_support = false;
        bool ret = false;
 
-       DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
+       DEBUG(10,("set_nt_acl: called for file %s\n",
+                 fsp_str_dbg(fsp)));
 
        if (!CAN_WRITE(conn)) {
                DEBUG(10,("set acl rejected on read-only share\n"));
@@ -3696,16 +3844,13 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
         * Get the current state of the file.
         */
 
-       if(fsp->is_directory || fsp->fh->fd == -1) {
-               if(vfs_stat_smb_fname(fsp->conn,fsp->fsp_name, &sbuf) != 0)
-                       return map_nt_error_from_unix(errno);
-       } else {
-               if(SMB_VFS_FSTAT(fsp, &sbuf) != 0)
-                       return map_nt_error_from_unix(errno);
+       status = vfs_stat_fsp(fsp);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
        /* Save the original element we check against. */
-       orig_mode = sbuf.st_ex_mode;
+       orig_mode = fsp->fsp_name->st.st_ex_mode;
 
        /*
         * Unpack the user/group/world id's.
@@ -3722,14 +3867,18 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
         * Noticed by Simo.
         */
 
-       if (((user != (uid_t)-1) && (sbuf.st_ex_uid != user)) || (( grp != (gid_t)-1) && (sbuf.st_ex_gid != grp))) {
+       if (((user != (uid_t)-1) && (fsp->fsp_name->st.st_ex_uid != user)) ||
+           (( grp != (gid_t)-1) && (fsp->fsp_name->st.st_ex_gid != grp))) {
 
                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) ));
+                        fsp_str_dbg(fsp), (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_str_dbg(fsp),
+                                (unsigned int)user, (unsigned int)grp,
+                                strerror(errno)));
                        if (errno == EPERM) {
                                return NT_STATUS_INVALID_OWNER;
                        }
@@ -3741,28 +3890,13 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
                 * (suid/sgid bits, for instance)
                 */
 
-               if(fsp->is_directory) {
-                       if(vfs_stat_smb_fname(fsp->conn, fsp->fsp_name,
-                                             &sbuf) != 0) {
-                               return map_nt_error_from_unix(errno);
-                       }
-               } else {
-
-                       int sret;
-
-                       if(fsp->fh->fd == -1)
-                               sret = vfs_stat_smb_fname(fsp->conn,
-                                                         fsp->fsp_name,
-                                                         &sbuf);
-                       else
-                               sret = SMB_VFS_FSTAT(fsp, &sbuf);
-
-                       if(sret != 0)
-                               return map_nt_error_from_unix(errno);
+               status = vfs_stat_fsp(fsp);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
                }
 
                /* Save the original element we check against. */
-               orig_mode = sbuf.st_ex_mode;
+               orig_mode = fsp->fsp_name->st.st_ex_mode;
 
                /* If we successfully chowned, we know we must
                 * be able to set the acl, so do it as root.
@@ -3770,10 +3904,11 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
                set_acl_as_root = true;
        }
 
-       create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
+       create_file_sids(&fsp->fsp_name->st, &file_owner_sid, &file_grp_sid);
 
-       acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
-                                       &file_ace_list, &dir_ace_list, security_info_sent, psd);
+       acl_perms = unpack_canon_ace(fsp, &fsp->fsp_name->st, &file_owner_sid,
+                                    &file_grp_sid, &file_ace_list,
+                                    &dir_ace_list, security_info_sent, psd);
 
        /* Ignore W2K traverse DACL set. */
        if (!file_ace_list && !dir_ace_list) {
@@ -3806,12 +3941,15 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
                if (set_acl_as_root) {
                        become_root();
                }
-               ret = set_canon_ace_list(fsp, file_ace_list, False, &sbuf, &acl_set_support);
+               ret = set_canon_ace_list(fsp, file_ace_list, false,
+                                        &fsp->fsp_name->st, &acl_set_support);
                if (set_acl_as_root) {
                        unbecome_root();
                }
                if (acl_set_support && ret == false) {
-                       DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
+                       DEBUG(3,("set_nt_acl: failed to set file acl on file "
+                                "%s (%s).\n", fsp_str_dbg(fsp),
+                                strerror(errno)));
                        free_canon_ace_list(file_ace_list);
                        free_canon_ace_list(dir_ace_list);
                        return map_nt_error_from_unix(errno);
@@ -3823,12 +3961,16 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
                        if (set_acl_as_root) {
                                become_root();
                        }
-                       ret = set_canon_ace_list(fsp, dir_ace_list, True, &sbuf, &acl_set_support);
+                       ret = set_canon_ace_list(fsp, dir_ace_list, true,
+                                                &fsp->fsp_name->st,
+                                                &acl_set_support);
                        if (set_acl_as_root) {
                                unbecome_root();
                        }
                        if (ret == false) {
-                               DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
+                               DEBUG(3,("set_nt_acl: failed to set default "
+                                        "acl on directory %s (%s).\n",
+                                        fsp_str_dbg(fsp), strerror(errno)));
                                free_canon_ace_list(file_ace_list);
                                free_canon_ace_list(dir_ace_list);
                                return map_nt_error_from_unix(errno);
@@ -3843,18 +3985,24 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
                        if (set_acl_as_root) {
                                become_root();
                        }
-                       sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name);
+                       sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn,
+                           fsp->fsp_name->base_name);
                        if (set_acl_as_root) {
                                unbecome_root();
                        }
                        if (sret == -1) {
-                               if (acl_group_override(conn, &sbuf, fsp->fsp_name)) {
-                                       DEBUG(5,("set_nt_acl: acl group control on and "
-                                               "current user in file %s primary group. Override delete_def_acl\n",
-                                               fsp->fsp_name ));
+                               if (acl_group_override(conn, fsp->fsp_name)) {
+                                       DEBUG(5,("set_nt_acl: acl group "
+                                                "control on and current user "
+                                                "in file %s primary group. "
+                                                "Override delete_def_acl\n",
+                                                fsp_str_dbg(fsp)));
 
                                        become_root();
-                                       sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name);
+                                       sret =
+                                           SMB_VFS_SYS_ACL_DELETE_DEF_FILE(
+                                                   conn,
+                                                   fsp->fsp_name->base_name);
                                        unbecome_root();
                                }
 
@@ -3891,8 +4039,9 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
                if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
                        free_canon_ace_list(file_ace_list);
                        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 ));
+                       DEBUG(3,("set_nt_acl: failed to convert file acl to "
+                                "posix permissions for file %s.\n",
+                                fsp_str_dbg(fsp)));
                        return NT_STATUS_ACCESS_DENIED;
                }
 
@@ -3900,29 +4049,37 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
                        int sret = -1;
 
                        DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
-                               fsp->fsp_name, (unsigned int)posix_perms ));
+                                fsp_str_dbg(fsp), (unsigned int)posix_perms));
 
                        if (set_acl_as_root) {
                                become_root();
                        }
-                       sret = SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms);
+                       sret = SMB_VFS_CHMOD(conn, fsp->fsp_name->base_name,
+                                            posix_perms);
                        if (set_acl_as_root) {
                                unbecome_root();
                        }
                        if(sret == -1) {
-                               if (acl_group_override(conn, &sbuf, fsp->fsp_name)) {
-                                       DEBUG(5,("set_nt_acl: acl group control on and "
-                                               "current user in file %s primary group. Override chmod\n",
-                                               fsp->fsp_name ));
+                               if (acl_group_override(conn, fsp->fsp_name)) {
+                                       DEBUG(5,("set_nt_acl: acl group "
+                                                "control on and current user "
+                                                "in file %s primary group. "
+                                                "Override chmod\n",
+                                                fsp_str_dbg(fsp)));
 
                                        become_root();
-                                       sret = SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms);
+                                       sret = SMB_VFS_CHMOD(conn,
+                                           fsp->fsp_name->base_name,
+                                           posix_perms);
                                        unbecome_root();
                                }
 
                                if (sret == -1) {
-                                       DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
-                                               fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
+                                       DEBUG(3,("set_nt_acl: chmod %s, 0%o "
+                                                "failed. Error = %s.\n",
+                                                fsp_str_dbg(fsp),
+                                                (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);
@@ -3934,6 +4091,9 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
        free_canon_ace_list(file_ace_list);
        free_canon_ace_list(dir_ace_list);
 
+       /* Ensure the stat struct in the fsp is correct. */
+       status = vfs_stat_fsp(fsp);
+
        return NT_STATUS_OK;
 }
 
@@ -4301,7 +4461,7 @@ static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_
  on the directory.
 ****************************************************************************/
 
-bool set_unix_posix_default_acl(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf,
+bool set_unix_posix_default_acl(connection_struct *conn, const char *fname, const SMB_STRUCT_STAT *psbuf,
                                uint16 num_def_acls, const char *pdata)
 {
        SMB_ACL_T def_acl = NULL;
@@ -4537,6 +4697,7 @@ SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
        connection_struct *conn;
        files_struct finfo;
        struct fd_handle fh;
+       NTSTATUS status;
 
        conn = TALLOC_ZERO_P(ctx, connection_struct);
        if (conn == NULL) {
@@ -4556,7 +4717,7 @@ SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
 
        if (!smbd_vfs_init(conn)) {
                DEBUG(0,("get_nt_acl_no_snum: Unable to create a fake connection struct!\n"));
-               conn_free_internal( conn );
+               conn_free(conn);
                return NULL;
         }
 
@@ -4567,17 +4728,25 @@ SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
        finfo.conn = conn;
        finfo.fh = &fh;
        finfo.fh->fd = -1;
-       finfo.fsp_name = CONST_DISCARD(char *,fname);
+
+       status = create_synthetic_smb_fname(talloc_tos(), fname, NULL, NULL,
+                                           &finfo.fsp_name);
+       if (!NT_STATUS_IS_OK(status)) {
+               conn_free(conn);
+               return NULL;
+       }
 
        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 );
+               TALLOC_FREE(finfo.fsp_name);
+               conn_free(conn);
                return NULL;
        }
 
        ret_sd = dup_sec_desc( ctx, psd );
 
-       conn_free_internal( conn );
+       TALLOC_FREE(finfo.fsp_name);
+       conn_free(conn);
 
        return ret_sd;
 }