s3-smbd: Call sys_acl_create_entry() directly rather than via the VFS
[vlendec/samba-autobuild/.git] / source3 / smbd / posix_acls.c
index b61421dc8f6975b26915f3093d6a5540b8b7b8b0..79eb8aa09751a1531d1adcf28c7fa154b9d52280 100644 (file)
 */
 
 #include "includes.h"
+#include "smbd/smbd.h"
+#include "system/filesys.h"
+#include "../libcli/security/security.h"
+#include "trans2.h"
+#include "passdb/lookup_sid.h"
+#include "auth.h"
+#include "../librpc/gen_ndr/idmap.h"
+#include "lib/param/loadparm.h"
 
-extern struct current_user current_user;
 extern const struct generic_mapping file_generic_mapping;
 
 #undef  DBGC_CLASS
@@ -34,20 +41,14 @@ extern const struct generic_mapping file_generic_mapping;
 enum ace_owner {UID_ACE, GID_ACE, WORLD_ACE};
 enum ace_attribute {ALLOW_ACE, DENY_ACE}; /* Used for incoming NT ACLS. */
 
-typedef union posix_id {
-               uid_t uid;
-               gid_t gid;
-               int world;
-} posix_id;
-
 typedef struct canon_ace {
        struct canon_ace *next, *prev;
        SMB_ACL_TAG_T type;
        mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */
-       DOM_SID trustee;
+       struct dom_sid trustee;
        enum ace_owner owner_type;
        enum ace_attribute attr;
-       posix_id unix_ug;
+       struct unixid unix_ug;
        uint8_t ace_flags; /* From windows ACE entry. */
 } canon_ace;
 
@@ -116,7 +117,7 @@ struct pai_entry {
        struct pai_entry *next, *prev;
        uint8_t ace_flags;
        enum ace_owner owner_type;
-       posix_id unix_ug;
+       struct unixid unix_ug;
 };
 
 struct pai_val {
@@ -135,11 +136,11 @@ static uint32_t get_pai_entry_val(struct pai_entry *paie)
 {
        switch (paie->owner_type) {
                case UID_ACE:
-                       DEBUG(10,("get_pai_entry_val: uid = %u\n", (unsigned int)paie->unix_ug.uid ));
-                       return (uint32_t)paie->unix_ug.uid;
+                       DEBUG(10,("get_pai_entry_val: uid = %u\n", (unsigned int)paie->unix_ug.id ));
+                       return (uint32_t)paie->unix_ug.id;
                case GID_ACE:
-                       DEBUG(10,("get_pai_entry_val: gid = %u\n", (unsigned int)paie->unix_ug.gid ));
-                       return (uint32_t)paie->unix_ug.gid;
+                       DEBUG(10,("get_pai_entry_val: gid = %u\n", (unsigned int)paie->unix_ug.id ));
+                       return (uint32_t)paie->unix_ug.id;
                case WORLD_ACE:
                default:
                        DEBUG(10,("get_pai_entry_val: world ace\n"));
@@ -155,11 +156,11 @@ static uint32_t get_entry_val(canon_ace *ace_entry)
 {
        switch (ace_entry->owner_type) {
                case UID_ACE:
-                       DEBUG(10,("get_entry_val: uid = %u\n", (unsigned int)ace_entry->unix_ug.uid ));
-                       return (uint32_t)ace_entry->unix_ug.uid;
+                       DEBUG(10,("get_entry_val: uid = %u\n", (unsigned int)ace_entry->unix_ug.id ));
+                       return (uint32_t)ace_entry->unix_ug.id;
                case GID_ACE:
-                       DEBUG(10,("get_entry_val: gid = %u\n", (unsigned int)ace_entry->unix_ug.gid ));
-                       return (uint32_t)ace_entry->unix_ug.gid;
+                       DEBUG(10,("get_entry_val: gid = %u\n", (unsigned int)ace_entry->unix_ug.id ));
+                       return (uint32_t)ace_entry->unix_ug.id;
                case WORLD_ACE:
                default:
                        DEBUG(10,("get_entry_val: world ace\n"));
@@ -181,6 +182,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++;
@@ -195,7 +197,7 @@ static char *create_pai_buf_v2(canon_ace *file_ace_list,
        *store_size = PAI_V2_ENTRIES_BASE +
                ((num_entries + num_def_entries)*PAI_V2_ENTRY_LENGTH);
 
-       pai_buf = (char *)SMB_MALLOC(*store_size);
+       pai_buf = talloc_array(talloc_tos(), char, *store_size);
        if (!pai_buf) {
                return NULL;
        }
@@ -207,8 +209,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 +222,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 +238,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;
        }
 
@@ -261,7 +279,7 @@ static void store_inheritance_attributes(files_struct *fsp,
                                       pai_buf, store_size, 0);
        }
 
-       SAFE_FREE(pai_buf);
+       TALLOC_FREE(pai_buf);
 
        DEBUG(10,("store_inheritance_attribute: type 0x%x for file %s\n",
                (unsigned int)sd_type,
@@ -282,13 +300,13 @@ static void free_inherited_info(struct pai_val *pal)
                struct pai_entry *paie, *paie_next;
                for (paie = pal->entry_list; paie; paie = paie_next) {
                        paie_next = paie->next;
-                       SAFE_FREE(paie);
+                       TALLOC_FREE(paie);
                }
                for (paie = pal->def_entry_list; paie; paie = paie_next) {
                        paie_next = paie->next;
-                       SAFE_FREE(paie);
+                       TALLOC_FREE(paie);
                }
-               SAFE_FREE(pal);
+               TALLOC_FREE(pal);
        }
 }
 
@@ -386,20 +404,25 @@ static bool get_pai_owner_type(struct pai_entry *paie, const char *entry_offset)
        paie->owner_type = (enum ace_owner)CVAL(entry_offset,0);
        switch( paie->owner_type) {
                case UID_ACE:
-                       paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1);
+                       paie->unix_ug.type = ID_TYPE_UID;
+                       paie->unix_ug.id = (uid_t)IVAL(entry_offset,1);
                        DEBUG(10,("get_pai_owner_type: uid = %u\n",
-                               (unsigned int)paie->unix_ug.uid ));
+                               (unsigned int)paie->unix_ug.id ));
                        break;
                case GID_ACE:
-                       paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1);
+                       paie->unix_ug.type = ID_TYPE_GID;
+                       paie->unix_ug.id = (gid_t)IVAL(entry_offset,1);
                        DEBUG(10,("get_pai_owner_type: gid = %u\n",
-                               (unsigned int)paie->unix_ug.gid ));
+                               (unsigned int)paie->unix_ug.id ));
                        break;
                case WORLD_ACE:
-                       paie->unix_ug.world = -1;
+                       paie->unix_ug.type = ID_TYPE_NOT_SPECIFIED;
+                       paie->unix_ug.id = -1;
                        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;
@@ -416,13 +439,14 @@ static const char *create_pai_v1_entries(struct pai_val *paiv,
        int i;
 
        for (i = 0; i < paiv->num_entries; i++) {
-               struct pai_entry *paie = SMB_MALLOC_P(struct pai_entry);
+               struct pai_entry *paie = talloc(talloc_tos(), struct pai_entry);
                if (!paie) {
                        return NULL;
                }
 
                paie->ace_flags = SEC_ACE_FLAG_INHERITED_ACE;
                if (!get_pai_owner_type(paie, entry_offset)) {
+                       TALLOC_FREE(paie);
                        return NULL;
                }
 
@@ -449,7 +473,7 @@ static struct pai_val *create_pai_val_v1(const char *buf, size_t size)
                return NULL;
        }
 
-       paiv = SMB_MALLOC_P(struct pai_val);
+       paiv = talloc(talloc_tos(), struct pai_val);
        if (!paiv) {
                return NULL;
        }
@@ -457,7 +481,7 @@ static struct pai_val *create_pai_val_v1(const char *buf, size_t size)
        memset(paiv, '\0', sizeof(struct pai_val));
 
        paiv->sd_type = (CVAL(buf,PAI_V1_FLAG_OFFSET) == PAI_V1_ACL_FLAG_PROTECTED) ?
-                       SE_DESC_DACL_PROTECTED : 0;
+                       SEC_DESC_DACL_PROTECTED : 0;
 
        paiv->num_entries = SVAL(buf,PAI_V1_NUM_ENTRIES_OFFSET);
        paiv->num_def_entries = SVAL(buf,PAI_V1_NUM_DEFAULT_ENTRIES_OFFSET);
@@ -486,22 +510,22 @@ 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++) {
-               struct pai_entry *paie = SMB_MALLOC_P(struct pai_entry);
+       for (i = 0; i < num_entries; i++) {
+               struct pai_entry *paie = talloc(talloc_tos(), struct pai_entry);
                if (!paie) {
                        return NULL;
                }
 
                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)) {
+                       TALLOC_FREE(paie);
                        return NULL;
                }
                if (!def_entry) {
@@ -527,7 +551,7 @@ static struct pai_val *create_pai_val_v2(const char *buf, size_t size)
                return NULL;
        }
 
-       paiv = SMB_MALLOC_P(struct pai_val);
+       paiv = talloc(talloc_tos(), struct pai_val);
        if (!paiv) {
                return NULL;
        }
@@ -541,15 +565,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;
@@ -591,7 +618,7 @@ static struct pai_val *fload_inherited_info(files_struct *fsp)
                return NULL;
        }
 
-       if ((pai_buf = (char *)SMB_MALLOC(pai_buf_size)) == NULL) {
+       if ((pai_buf = talloc_array(talloc_tos(), char, pai_buf_size)) == NULL) {
                return NULL;
        }
 
@@ -612,11 +639,11 @@ static struct pai_val *fload_inherited_info(files_struct *fsp)
                        }
                        /* Buffer too small - enlarge it. */
                        pai_buf_size *= 2;
-                       SAFE_FREE(pai_buf);
+                       TALLOC_FREE(pai_buf);
                        if (pai_buf_size > 1024*1024) {
                                return NULL; /* Limit malloc to 1mb. */
                        }
-                       if ((pai_buf = (char *)SMB_MALLOC(pai_buf_size)) == NULL)
+                       if ((pai_buf = talloc_array(talloc_tos(), char, pai_buf_size)) == NULL)
                                return NULL;
                }
        } while (ret == -1);
@@ -633,7 +660,7 @@ static struct pai_val *fload_inherited_info(files_struct *fsp)
                if (errno != ENOSYS)
                        DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
 #endif
-               SAFE_FREE(pai_buf);
+               TALLOC_FREE(pai_buf);
                return NULL;
        }
 
@@ -644,7 +671,7 @@ static struct pai_val *fload_inherited_info(files_struct *fsp)
                          (unsigned int)paiv->sd_type, fsp_str_dbg(fsp)));
        }
 
-       SAFE_FREE(pai_buf);
+       TALLOC_FREE(pai_buf);
        return paiv;
 }
 
@@ -664,7 +691,7 @@ static struct pai_val *load_inherited_info(const struct connection_struct *conn,
                return NULL;
        }
 
-       if ((pai_buf = (char *)SMB_MALLOC(pai_buf_size)) == NULL) {
+       if ((pai_buf = talloc_array(talloc_tos(), char, pai_buf_size)) == NULL) {
                return NULL;
        }
 
@@ -679,11 +706,11 @@ static struct pai_val *load_inherited_info(const struct connection_struct *conn,
                        }
                        /* Buffer too small - enlarge it. */
                        pai_buf_size *= 2;
-                       SAFE_FREE(pai_buf);
+                       TALLOC_FREE(pai_buf);
                        if (pai_buf_size > 1024*1024) {
                                return NULL; /* Limit malloc to 1mb. */
                        }
-                       if ((pai_buf = (char *)SMB_MALLOC(pai_buf_size)) == NULL)
+                       if ((pai_buf = talloc_array(talloc_tos(), char, pai_buf_size)) == NULL)
                                return NULL;
                }
        } while (ret == -1);
@@ -699,7 +726,7 @@ static struct pai_val *load_inherited_info(const struct connection_struct *conn,
                if (errno != ENOSYS)
                        DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
 #endif
-               SAFE_FREE(pai_buf);
+               TALLOC_FREE(pai_buf);
                return NULL;
        }
 
@@ -711,7 +738,7 @@ static struct pai_val *load_inherited_info(const struct connection_struct *conn,
                        fname));
        }
 
-       SAFE_FREE(pai_buf);
+       TALLOC_FREE(pai_buf);
        return paiv;
 }
 
@@ -745,7 +772,7 @@ static void free_canon_ace_list( canon_ace *l_head )
        for (list = l_head; list; list = next) {
                next = list->next;
                DLIST_REMOVE(l_head, list);
-               SAFE_FREE(list);
+               TALLOC_FREE(list);
        }
 }
 
@@ -755,7 +782,7 @@ static void free_canon_ace_list( canon_ace *l_head )
 
 static canon_ace *dup_canon_ace( canon_ace *src_ace)
 {
-       canon_ace *dst_ace = SMB_MALLOC_P(canon_ace);
+       canon_ace *dst_ace = talloc(talloc_tos(), canon_ace);
 
        if (dst_ace == NULL)
                return NULL;
@@ -774,11 +801,11 @@ static void print_canon_ace(canon_ace *pace, int num)
        dbgtext( "canon_ace index %d. Type = %s ", num, pace->attr == ALLOW_ACE ? "allow" : "deny" );
        dbgtext( "SID = %s ", sid_string_dbg(&pace->trustee));
        if (pace->owner_type == UID_ACE) {
-               const char *u_name = uidtoname(pace->unix_ug.uid);
-               dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.uid, u_name );
+               const char *u_name = uidtoname(pace->unix_ug.id);
+               dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.id, u_name );
        } else if (pace->owner_type == GID_ACE) {
-               char *g_name = gidtoname(pace->unix_ug.gid);
-               dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.gid, g_name );
+               char *g_name = gidtoname(pace->unix_ug.id);
+               dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.id, g_name );
        } else
                dbgtext( "other ");
        switch (pace->type) {
@@ -832,9 +859,9 @@ static mode_t convert_permset_to_mode_t(connection_struct *conn, SMB_ACL_PERMSET
 {
        mode_t ret = 0;
 
-       ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRUSR : 0);
-       ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
-       ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
+       ret |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? S_IRUSR : 0);
+       ret |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
+       ret |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
 
        return ret;
 }
@@ -864,18 +891,18 @@ static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x
 
 static int map_acl_perms_to_permset(connection_struct *conn, mode_t mode, SMB_ACL_PERMSET_T *p_permset)
 {
-       if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) ==  -1)
+       if (sys_acl_clear_perms(*p_permset) ==  -1)
                return -1;
        if (mode & S_IRUSR) {
-               if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1)
+               if (sys_acl_add_perm(*p_permset, SMB_ACL_READ) == -1)
                        return -1;
        }
        if (mode & S_IWUSR) {
-               if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1)
+               if (sys_acl_add_perm(*p_permset, SMB_ACL_WRITE) == -1)
                        return -1;
        }
        if (mode & S_IXUSR) {
-               if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1)
+               if (sys_acl_add_perm(*p_permset, SMB_ACL_EXECUTE) == -1)
                        return -1;
        }
        return 0;
@@ -885,40 +912,19 @@ 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.
 ****************************************************************************/
 
-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, struct dom_sid *powner_sid, struct dom_sid *pgroup_sid)
 {
        uid_to_sid( powner_sid, psbuf->st_ex_uid );
        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
+ Merge aces with a common UID or GID - 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;
@@ -936,12 +942,30 @@ 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.
+                        *
+                        * For the IDMAP_BOTH case, we must not merge
+                        * the UID and GID ACE values for same SID
+                        */
+
+                       if (!dir_acl) {
+                               can_merge = (curr_ace->unix_ug.id == curr_ace_outer->unix_ug.id &&
+                                            curr_ace->owner_type == curr_ace_outer->owner_type &&
+                                            (curr_ace->attr == curr_ace_outer->attr));
+                       } else {
+                               can_merge = (curr_ace->unix_ug.id == curr_ace_outer->unix_ug.id &&
+                                            curr_ace->owner_type == curr_ace_outer->owner_type &&
+                                            (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);
@@ -950,9 +974,15 @@ 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);
+                               TALLOC_FREE(curr_ace);
                                curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
                        }
                }
@@ -979,8 +1009,9 @@ 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) &&
-                               (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
+                       if (curr_ace->unix_ug.id == curr_ace_outer->unix_ug.id &&
+                           (curr_ace->owner_type == curr_ace_outer->owner_type) &&
+                           (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
 
                                if( DEBUGLVL( 10 )) {
                                        dbgtext("merge_aces: Masking ACE's\n");
@@ -997,7 +1028,7 @@ static void merge_aces( canon_ace **pp_list_head )
                                         */
 
                                        DLIST_REMOVE(l_head, curr_ace);
-                                       SAFE_FREE(curr_ace);
+                                       TALLOC_FREE(curr_ace);
                                        curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
 
                                } else {
@@ -1013,7 +1044,7 @@ static void merge_aces( canon_ace **pp_list_head )
                                         */
 
                                        DLIST_REMOVE(l_head, curr_ace_outer);
-                                       SAFE_FREE(curr_ace_outer);
+                                       TALLOC_FREE(curr_ace_outer);
                                        break;
                                }
                        }
@@ -1050,7 +1081,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)
@@ -1091,6 +1122,10 @@ static uint32_t map_canon_ace_perms(int snum,
                }
        }
 
+       if ((perms & S_IWUSR) && lp_dos_filemode(snum)) {
+               nt_mask |= (SEC_STD_WRITE_DAC|SEC_STD_WRITE_OWNER|DELETE_ACCESS);
+       }
+
        DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
                        (unsigned int)perms, (unsigned int)nt_mask ));
 
@@ -1101,8 +1136,8 @@ static uint32_t map_canon_ace_perms(int snum,
  Map NT perms to a UNIX mode_t.
 ****************************************************************************/
 
-#define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
-#define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
+#define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA)
+#define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA)
 #define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
 
 static mode_t map_nt_perms( uint32 *mask, int type)
@@ -1143,13 +1178,16 @@ static mode_t map_nt_perms( uint32 *mask, int type)
 }
 
 /****************************************************************************
- Unpack a SEC_DESC into a UNIX owner and group.
+ Unpack a struct security_descriptor into a UNIX owner and group.
 ****************************************************************************/
 
-NTSTATUS unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, const SEC_DESC *psd)
+NTSTATUS unpack_nt_owners(struct connection_struct *conn,
+                       uid_t *puser, gid_t *pgrp,
+                       uint32 security_info_sent, const struct
+                       security_descriptor *psd)
 {
-       DOM_SID owner_sid;
-       DOM_SID grp_sid;
+       struct dom_sid owner_sid;
+       struct dom_sid grp_sid;
 
        *puser = (uid_t)-1;
        *pgrp = (gid_t)-1;
@@ -1173,13 +1211,13 @@ NTSTATUS unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_i
         * This may be a group chown only set.
         */
 
-       if (security_info_sent & OWNER_SECURITY_INFORMATION) {
+       if (security_info_sent & SECINFO_OWNER) {
                sid_copy(&owner_sid, psd->owner_sid);
                if (!sid_to_uid(&owner_sid, puser)) {
-                       if (lp_force_unknown_acl_user(snum)) {
+                       if (lp_force_unknown_acl_user(SNUM(conn))) {
                                /* this allows take ownership to work
                                 * reasonably */
-                               *puser = current_user.ut.uid;
+                               *puser = get_current_uid(conn);
                        } else {
                                DEBUG(3,("unpack_nt_owners: unable to validate"
                                         " owner sid for %s\n",
@@ -1196,13 +1234,13 @@ NTSTATUS unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_i
         * This may be an owner chown only set.
         */
 
-       if (security_info_sent & GROUP_SECURITY_INFORMATION) {
+       if (security_info_sent & SECINFO_GROUP) {
                sid_copy(&grp_sid, psd->group_sid);
                if (!sid_to_gid( &grp_sid, pgrp)) {
-                       if (lp_force_unknown_acl_user(snum)) {
+                       if (lp_force_unknown_acl_user(SNUM(conn))) {
                                /* this allows take group ownership to work
                                 * reasonably */
-                               *pgrp = current_user.ut.gid;
+                               *pgrp = get_current_gid(conn);
                        } else {
                                DEBUG(3,("unpack_nt_owners: unable to validate"
                                         " group sid.\n"));
@@ -1267,46 +1305,40 @@ static void apply_default_perms(const struct share_params *params,
  expensive and will need optimisation. A *lot* of optimisation :-). JRA.
 ****************************************************************************/
 
-static bool uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
+static bool uid_entry_in_group(connection_struct *conn, canon_ace *uid_ace, canon_ace *group_ace )
 {
-       const char *u_name = NULL;
-
        /* "Everyone" always matches every uid. */
 
-       if (sid_equal(&group_ace->trustee, &global_sid_World))
+       if (dom_sid_equal(&group_ace->trustee, &global_sid_World))
                return True;
 
        /*
         * if it's the current user, we already have the unix token
         * and don't need to do the complex user_in_group_sid() call
         */
-       if (uid_ace->unix_ug.uid == current_user.ut.uid) {
+       if (uid_ace->unix_ug.id == get_current_uid(conn)) {
+               const struct security_unix_token *curr_utok = NULL;
                size_t i;
 
-               if (group_ace->unix_ug.gid == current_user.ut.gid) {
+               if (group_ace->unix_ug.id == get_current_gid(conn)) {
                        return True;
                }
 
-               for (i=0; i < current_user.ut.ngroups; i++) {
-                       if (group_ace->unix_ug.gid == current_user.ut.groups[i]) {
+               curr_utok = get_current_utok(conn);
+               for (i=0; i < curr_utok->ngroups; i++) {
+                       if (group_ace->unix_ug.id == curr_utok->groups[i]) {
                                return True;
                        }
                }
        }
 
-       /* u_name talloc'ed off tos. */
-       u_name = uidtoname(uid_ace->unix_ug.uid);
-       if (!u_name) {
-               return False;
-       }
-
        /*
-        * user_in_group_sid() uses create_token_from_username()
+        * user_in_group_sid() uses create_token_from_sid()
         * which creates an artificial NT token given just a username,
         * so this is not reliable for users from foreign domains
         * exported by winbindd!
         */
-       return user_in_group_sid(u_name, &group_ace->trustee);
+       return user_sid_in_group_sid(&uid_ace->trustee, &group_ace->trustee);
 }
 
 /****************************************************************************
@@ -1319,18 +1351,17 @@ static bool uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
  type.
 ****************************************************************************/
 
-static bool ensure_canon_entry_valid(canon_ace **pp_ace,
+static bool ensure_canon_entry_valid(connection_struct *conn, canon_ace **pp_ace,
                                     const struct share_params *params,
                                     const bool is_directory,
-                                                       const DOM_SID *pfile_owner_sid,
-                                                       const DOM_SID *pfile_grp_sid,
+                                                       const struct dom_sid *pfile_owner_sid,
+                                                       const struct dom_sid *pfile_grp_sid,
                                                        const SMB_STRUCT_STAT *pst,
                                                        bool setting_acl)
 {
        canon_ace *pace;
-       bool got_user = False;
-       bool got_grp = False;
-       bool got_other = False;
+       canon_ace *pace_user = NULL;
+       canon_ace *pace_group = NULL;
        canon_ace *pace_other = NULL;
 
        for (pace = *pp_ace; pace; pace = pace->next) {
@@ -1338,7 +1369,7 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace,
 
                        if (setting_acl)
                                apply_default_perms(params, is_directory, pace, S_IRUSR);
-                       got_user = True;
+                       pace_user = pace;
 
                } else if (pace->type == SMB_ACL_GROUP_OBJ) {
 
@@ -1348,7 +1379,7 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace,
 
                        if (setting_acl)
                                apply_default_perms(params, is_directory, pace, S_IRGRP);
-                       got_grp = True;
+                       pace_group = pace;
 
                } else if (pace->type == SMB_ACL_OTHER) {
 
@@ -1358,13 +1389,12 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace,
 
                        if (setting_acl)
                                apply_default_perms(params, is_directory, pace, S_IROTH);
-                       got_other = True;
                        pace_other = pace;
                }
        }
 
-       if (!got_user) {
-               if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
+       if (!pace_user) {
+               if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
                        DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
                        return False;
                }
@@ -1372,32 +1402,39 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace,
                ZERO_STRUCTP(pace);
                pace->type = SMB_ACL_USER_OBJ;
                pace->owner_type = UID_ACE;
-               pace->unix_ug.uid = pst->st_ex_uid;
+               pace->unix_ug.type = ID_TYPE_UID;
+               pace->unix_ug.id = pst->st_ex_uid;
                pace->trustee = *pfile_owner_sid;
                pace->attr = ALLOW_ACE;
+               /* Start with existing permissions, principle of least
+                  surprises for the user. */
+               pace->perms = pst->st_ex_mode;
 
                if (setting_acl) {
                        /* See if the owning user is in any of the other groups in
-                          the ACE. If so, OR in the permissions from that group. */
+                          the ACE, or if there's a matching user entry (by uid
+                          or in the case of ID_TYPE_BOTH by SID).
+                          If so, OR in the permissions from that entry. */
 
-                       bool group_matched = False;
                        canon_ace *pace_iter;
 
                        for (pace_iter = *pp_ace; pace_iter; pace_iter = pace_iter->next) {
-                               if (pace_iter->type == SMB_ACL_GROUP_OBJ || pace_iter->type == SMB_ACL_GROUP) {
-                                       if (uid_entry_in_group(pace, pace_iter)) {
+                               if (pace_iter->type == SMB_ACL_USER &&
+                                               pace_iter->unix_ug.id == pace->unix_ug.id) {
+                                       pace->perms |= pace_iter->perms;
+                               } else if (pace_iter->type == SMB_ACL_GROUP_OBJ || pace_iter->type == SMB_ACL_GROUP) {
+                                       if (dom_sid_equal(&pace->trustee, &pace_iter->trustee)) {
+                                               pace->perms |= pace_iter->perms;
+                                       } else if (uid_entry_in_group(conn, pace, pace_iter)) {
                                                pace->perms |= pace_iter->perms;
-                                               group_matched = True;
                                        }
                                }
                        }
 
-                       /* If we only got an "everyone" perm, just use that. */
-                       if (!group_matched) {
-                               if (got_other)
+                       if (pace->perms == 0) {
+                               /* If we only got an "everyone" perm, just use that. */
+                               if (pace_other)
                                        pace->perms = pace_other->perms;
-                               else
-                                       pace->perms = 0;
                        }
 
                        apply_default_perms(params, is_directory, pace, S_IRUSR);
@@ -1406,10 +1443,11 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace,
                }
 
                DLIST_ADD(*pp_ace, pace);
+               pace_user = pace;
        }
 
-       if (!got_grp) {
-               if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
+       if (!pace_group) {
+               if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
                        DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
                        return False;
                }
@@ -1417,12 +1455,13 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace,
                ZERO_STRUCTP(pace);
                pace->type = SMB_ACL_GROUP_OBJ;
                pace->owner_type = GID_ACE;
-               pace->unix_ug.uid = pst->st_ex_gid;
+               pace->unix_ug.type = ID_TYPE_GID;
+               pace->unix_ug.id = pst->st_ex_gid;
                pace->trustee = *pfile_grp_sid;
                pace->attr = ALLOW_ACE;
                if (setting_acl) {
                        /* If we only got an "everyone" perm, just use that. */
-                       if (got_other)
+                       if (pace_other)
                                pace->perms = pace_other->perms;
                        else
                                pace->perms = 0;
@@ -1432,10 +1471,11 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace,
                }
 
                DLIST_ADD(*pp_ace, pace);
+               pace_group = pace;
        }
 
-       if (!got_other) {
-               if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
+       if (!pace_other) {
+               if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
                        DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
                        return False;
                }
@@ -1443,7 +1483,8 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace,
                ZERO_STRUCTP(pace);
                pace->type = SMB_ACL_OTHER;
                pace->owner_type = WORLD_ACE;
-               pace->unix_ug.world = -1;
+               pace->unix_ug.type = ID_TYPE_NOT_SPECIFIED;
+               pace->unix_ug.id = -1;
                pace->trustee = global_sid_World;
                pace->attr = ALLOW_ACE;
                if (setting_acl) {
@@ -1453,6 +1494,114 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace,
                        pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IROTH, S_IWOTH, S_IXOTH);
 
                DLIST_ADD(*pp_ace, pace);
+               pace_other = pace;
+       }
+
+       if (setting_acl) {
+               /* Ensure when setting a POSIX ACL, that the uid for a
+                  SMB_ACL_USER_OBJ ACE (the owner ACE entry) has a duplicate
+                  permission entry as an SMB_ACL_USER, and a gid for a
+                  SMB_ACL_GROUP_OBJ ACE (the primary group ACE entry) also has
+                  a duplicate permission entry as an SMB_ACL_GROUP. If not,
+                  then if the ownership or group ownership of this file or
+                  directory gets changed, the user or group can lose their
+                  access. */
+               bool got_duplicate_user = false;
+               bool got_duplicate_group = false;
+
+               for (pace = *pp_ace; pace; pace = pace->next) {
+                       if (pace->type == SMB_ACL_USER &&
+                                       pace->unix_ug.id == pace_user->unix_ug.id) {
+                               /* Already got one. */
+                               got_duplicate_user = true;
+                       } else if (pace->type == SMB_ACL_GROUP &&
+                                       pace->unix_ug.id == pace_user->unix_ug.id) {
+                               /* Already got one. */
+                               got_duplicate_group = true;
+                       } else if ((pace->type == SMB_ACL_GROUP)
+                                  && (dom_sid_equal(&pace->trustee, &pace_user->trustee))) {
+                               /* If the SID owning the file appears
+                                * in a group entry, then we have
+                                * enough duplication, they will still
+                                * have access */
+                               got_duplicate_user = true;
+                       }
+               }
+
+               /* If the SID is equal for the user and group that we need
+                  to add the duplicate for, add only the group */
+               if (!got_duplicate_user && !got_duplicate_group
+                               && dom_sid_equal(&pace_group->trustee,
+                                               &pace_user->trustee)) {
+                       /* Add a duplicate SMB_ACL_GROUP entry, this
+                        * will cover the owning SID as well, as it
+                        * will always be mapped to both a uid and
+                        * gid. */
+
+                       if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
+                               DEBUG(0,("ensure_canon_entry_valid: talloc fail.\n"));
+                               return false;
+                       }
+
+                       ZERO_STRUCTP(pace);
+                       pace->type = SMB_ACL_GROUP;;
+                       pace->owner_type = GID_ACE;
+                       pace->unix_ug.type = ID_TYPE_GID;
+                       pace->unix_ug.id = pace_group->unix_ug.id;
+                       pace->trustee = pace_group->trustee;
+                       pace->attr = pace_group->attr;
+                       pace->perms = pace_group->perms;
+
+                       DLIST_ADD(*pp_ace, pace);
+
+                       /* We're done here, make sure the
+                          statements below are not executed. */
+                       got_duplicate_user = true;
+                       got_duplicate_group = true;
+               }
+
+               if (!got_duplicate_user) {
+                       /* Add a duplicate SMB_ACL_USER entry. */
+                       if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
+                               DEBUG(0,("ensure_canon_entry_valid: talloc fail.\n"));
+                               return false;
+                       }
+
+                       ZERO_STRUCTP(pace);
+                       pace->type = SMB_ACL_USER;;
+                       pace->owner_type = UID_ACE;
+                       pace->unix_ug.type = ID_TYPE_UID;
+                       pace->unix_ug.id = pace_user->unix_ug.id;
+                       pace->trustee = pace_user->trustee;
+                       pace->attr = pace_user->attr;
+                       pace->perms = pace_user->perms;
+
+                       DLIST_ADD(*pp_ace, pace);
+
+                       got_duplicate_user = true;
+               }
+
+               if (!got_duplicate_group) {
+                       /* Add a duplicate SMB_ACL_GROUP entry. */
+                       if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
+                               DEBUG(0,("ensure_canon_entry_valid: talloc fail.\n"));
+                               return false;
+                       }
+
+                       ZERO_STRUCTP(pace);
+                       pace->type = SMB_ACL_GROUP;;
+                       pace->owner_type = GID_ACE;
+                       pace->unix_ug.type = ID_TYPE_GID;
+                       pace->unix_ug.id = pace_group->unix_ug.id;
+                       pace->trustee = pace_group->trustee;
+                       pace->attr = pace_group->attr;
+                       pace->perms = pace_group->perms;
+
+                       DLIST_ADD(*pp_ace, pace);
+
+                       got_duplicate_group = true;
+               }
+
        }
 
        return True;
@@ -1462,9 +1611,10 @@ static bool ensure_canon_entry_valid(canon_ace **pp_ace,
  Check if a POSIX ACL has the required SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries.
  If it does not have them, check if there are any entries where the trustee is the
  file owner or the owning group, and map these to SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ.
+ Note we must not do this to default directory ACLs.
 ****************************************************************************/
 
-static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid)
+static void check_owning_objs(canon_ace *ace, struct dom_sid *pfile_owner_sid, struct dom_sid *pfile_grp_sid)
 {
        bool got_user_obj, got_group_obj;
        canon_ace *current_ace;
@@ -1487,12 +1637,12 @@ static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID
 
        for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
                if (!got_user_obj && current_ace->owner_type == UID_ACE &&
-                               sid_equal(&current_ace->trustee, pfile_owner_sid)) {
+                               dom_sid_equal(&current_ace->trustee, pfile_owner_sid)) {
                        current_ace->type = SMB_ACL_USER_OBJ;
                        got_user_obj = True;
                }
                if (!got_group_obj && current_ace->owner_type == GID_ACE &&
-                               sid_equal(&current_ace->trustee, pfile_grp_sid)) {
+                               dom_sid_equal(&current_ace->trustee, pfile_grp_sid)) {
                        current_ace->type = SMB_ACL_GROUP_OBJ;
                        got_group_obj = True;
                }
@@ -1503,17 +1653,192 @@ 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"));
 }
 
+static bool add_current_ace_to_acl(files_struct *fsp, struct security_ace *psa,
+                                  canon_ace **file_ace, canon_ace **dir_ace,
+                                  bool *got_file_allow, bool *got_dir_allow,
+                                  bool *all_aces_are_inherit_only,
+                                  canon_ace *current_ace)
+{
+
+       /*
+        * Map the given NT permissions into a UNIX mode_t containing only
+        * S_I(R|W|X)USR bits.
+        */
+
+       current_ace->perms |= map_nt_perms( &psa->access_mask, S_IRUSR);
+       current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
+
+       /* Store the ace_flag. */
+       current_ace->ace_flags = psa->flags;
+
+       /*
+        * Now add the created ace to either the file list, the directory
+        * list, or both. We *MUST* preserve the order here (hence we use
+        * DLIST_ADD_END) as NT ACLs are order dependent.
+        */
+
+       if (fsp->is_directory) {
+
+               /*
+                * We can only add to the default POSIX ACE list if the ACE is
+                * designed to be inherited by both files and directories.
+                */
+
+               if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
+                   (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
+
+                       canon_ace *current_dir_ace = current_ace;
+                       DLIST_ADD_END(*dir_ace, current_ace, canon_ace *);
+
+                       /*
+                        * Note if this was an allow ace. We can't process
+                        * any further deny ace's after this.
+                        */
+
+                       if (current_ace->attr == ALLOW_ACE)
+                               *got_dir_allow = True;
+
+                       if ((current_ace->attr == DENY_ACE) && *got_dir_allow) {
+                               DEBUG(0,("add_current_ace_to_acl: "
+                                        "malformed ACL in "
+                                        "inheritable ACL! Deny entry "
+                                        "after Allow entry. Failing "
+                                        "to set on file %s.\n",
+                                        fsp_str_dbg(fsp)));
+                               return False;
+                       }
+
+                       if( DEBUGLVL( 10 )) {
+                               dbgtext("add_current_ace_to_acl: adding dir ACL:\n");
+                               print_canon_ace( current_ace, 0);
+                       }
+
+                       /*
+                        * If this is not an inherit only ACE we need to add a duplicate
+                        * to the file acl.
+                        */
+
+                       if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
+                               canon_ace *dup_ace = dup_canon_ace(current_ace);
+
+                               if (!dup_ace) {
+                                       DEBUG(0,("add_current_ace_to_acl: malloc fail !\n"));
+                                       return False;
+                               }
+
+                               /*
+                                * We must not free current_ace here as its
+                                * 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
+                                * pointer is now owned by the dir_ace list.
+                                */
+                               current_ace = NULL;
+                       }
+
+                       /*
+                        * current_ace is now either owned by file_ace
+                        * or is NULL. We can safely operate on current_dir_ace
+                        * to treat mapping for default acl entries differently
+                        * than access acl entries.
+                        */
+
+                       if (current_dir_ace->owner_type == UID_ACE) {
+                               /*
+                                * We already decided above this is a uid,
+                                * for default acls ace's only CREATOR_OWNER
+                                * maps to ACL_USER_OBJ. All other uid
+                                * ace's are ACL_USER.
+                                */
+                               if (dom_sid_equal(&current_dir_ace->trustee,
+                                                 &global_sid_Creator_Owner)) {
+                                       current_dir_ace->type = SMB_ACL_USER_OBJ;
+                               } else {
+                                       current_dir_ace->type = SMB_ACL_USER;
+                               }
+                       }
+
+                       if (current_dir_ace->owner_type == GID_ACE) {
+                               /*
+                                * We already decided above this is a gid,
+                                * for default acls ace's only CREATOR_GROUP
+                                * maps to ACL_GROUP_OBJ. All other uid
+                                * ace's are ACL_GROUP.
+                                */
+                               if (dom_sid_equal(&current_dir_ace->trustee,
+                                                 &global_sid_Creator_Group)) {
+                                       current_dir_ace->type = SMB_ACL_GROUP_OBJ;
+                               } else {
+                                       current_dir_ace->type = SMB_ACL_GROUP;
+                               }
+                       }
+               }
+       }
+
+       /*
+        * Only add to the file ACL if not inherit only.
+        */
+
+       if (current_ace && !(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
+               DLIST_ADD_END(*file_ace, current_ace, canon_ace *);
+
+               /*
+                * Note if this was an allow ace. We can't process
+                * any further deny ace's after this.
+                */
+
+               if (current_ace->attr == ALLOW_ACE)
+                       *got_file_allow = True;
+
+               if ((current_ace->attr == DENY_ACE) && got_file_allow) {
+                       DEBUG(0,("add_current_ace_to_acl: malformed "
+                                "ACL in file ACL ! Deny entry after "
+                                "Allow entry. Failing to set on file "
+                                "%s.\n", fsp_str_dbg(fsp)));
+                       return False;
+               }
+
+               if( DEBUGLVL( 10 )) {
+                       dbgtext("add_current_ace_to_acl: adding file ACL:\n");
+                       print_canon_ace( current_ace, 0);
+               }
+               *all_aces_are_inherit_only = False;
+               /*
+                * We must not free current_ace here as its
+                * pointer is now owned by the file_ace list.
+                */
+               current_ace = NULL;
+       }
+
+       /*
+        * Free if ACE was not added.
+        */
+
+       TALLOC_FREE(current_ace);
+       return true;
+}
+
 /****************************************************************************
- Unpack a SEC_DESC into two canonical ace lists.
+ Unpack a struct security_descriptor 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,
+                                       const SMB_STRUCT_STAT *pst,
+                                       struct dom_sid *pfile_owner_sid,
+                                       struct dom_sid *pfile_grp_sid,
                                        canon_ace **ppfile_ace,
                                        canon_ace **ppdir_ace,
-                                       const SEC_ACL *dacl)
+                                       const struct security_acl *dacl)
 {
        bool all_aces_are_inherit_only = (fsp->is_directory ? True : False);
        canon_ace *file_ace = NULL;
@@ -1531,7 +1856,7 @@ static bool create_canon_ace_lists(files_struct *fsp,
         */
 
        for(i = 0; i < dacl->num_aces; i++) {
-               SEC_ACE *psa = &dacl->aces[i];
+               struct security_ace *psa = &dacl->aces[i];
 
                if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
                        DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
@@ -1568,15 +1893,15 @@ static bool create_canon_ace_lists(files_struct *fsp,
         */
 
        for(i = 0; i < dacl->num_aces; i++) {
-               SEC_ACE *psa1 = &dacl->aces[i];
+               struct security_ace *psa1 = &dacl->aces[i];
 
                for (j = i + 1; j < dacl->num_aces; j++) {
-                       SEC_ACE *psa2 = &dacl->aces[j];
+                       struct security_ace *psa2 = &dacl->aces[j];
 
                        if (psa1->access_mask != psa2->access_mask)
                                continue;
 
-                       if (!sid_equal(&psa1->trustee, &psa2->trustee))
+                       if (!dom_sid_equal(&psa1->trustee, &psa2->trustee))
                                continue;
 
                        /*
@@ -1599,13 +1924,13 @@ static bool create_canon_ace_lists(files_struct *fsp,
        }
 
        for(i = 0; i < dacl->num_aces; i++) {
-               SEC_ACE *psa = &dacl->aces[i];
+               struct security_ace *psa = &dacl->aces[i];
 
                /*
-                * Create a cannon_ace entry representing this NT DACL ACE.
+                * Create a canon_ace entry representing this NT DACL ACE.
                 */
 
-               if ((current_ace = SMB_MALLOC_P(canon_ace)) == NULL) {
+               if ((current_ace = talloc(talloc_tos(), canon_ace)) == NULL) {
                        free_canon_ace_list(file_ace);
                        free_canon_ace_list(dir_ace);
                        DEBUG(0,("create_canon_ace_lists: malloc fail.\n"));
@@ -1622,202 +1947,167 @@ static bool create_canon_ace_lists(files_struct *fsp,
                 * Note what kind of a POSIX ACL this should map to.
                 */
 
-               if( sid_equal(&current_ace->trustee, &global_sid_World)) {
+               if( dom_sid_equal(&current_ace->trustee, &global_sid_World)) {
                        current_ace->owner_type = WORLD_ACE;
-                       current_ace->unix_ug.world = -1;
+                       current_ace->unix_ug.type = ID_TYPE_NOT_SPECIFIED;
+                       current_ace->unix_ug.id = -1;
                        current_ace->type = SMB_ACL_OTHER;
-               } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Owner)) {
+               } else if (dom_sid_equal(&current_ace->trustee, &global_sid_Creator_Owner)) {
                        current_ace->owner_type = UID_ACE;
-                       current_ace->unix_ug.uid = pst->st_ex_uid;
+                       current_ace->unix_ug.type = ID_TYPE_UID;
+                       current_ace->unix_ug.id = pst->st_ex_uid;
                        current_ace->type = SMB_ACL_USER_OBJ;
 
                        /*
                         * 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;
-               } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Group)) {
+                       psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+
+               } else if (dom_sid_equal(&current_ace->trustee, &global_sid_Creator_Group)) {
                        current_ace->owner_type = GID_ACE;
-                       current_ace->unix_ug.gid = pst->st_ex_gid;
+                       current_ace->unix_ug.type = ID_TYPE_GID;
+                       current_ace->unix_ug.id = pst->st_ex_gid;
                        current_ace->type = SMB_ACL_GROUP_OBJ;
 
                        /*
                         * 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;
-                       /* If it's the owning user, this is a user_obj, not
-                        * a user. */
-                       if (current_ace->unix_ug.uid == pst->st_ex_uid) {
-                               current_ace->type = SMB_ACL_USER_OBJ;
-                       } else {
-                               current_ace->type = SMB_ACL_USER;
-                       }
-               } else if (sid_to_gid( &current_ace->trustee, &current_ace->unix_ug.gid)) {
-                       current_ace->owner_type = GID_ACE;
-                       /* If it's the primary group, this is a group_obj, not
-                        * a group. */
-                       if (current_ace->unix_ug.gid == pst->st_ex_gid) {
-                               current_ace->type = SMB_ACL_GROUP_OBJ;
-                       } else {
-                               current_ace->type = SMB_ACL_GROUP;
-                       }
                } else {
-                       /*
-                        * Silently ignore map failures in non-mappable SIDs (NT Authority, BUILTIN etc).
-                        */
+                       struct unixid unixid;
 
-                       if (non_mappable_sid(&psa->trustee)) {
-                               DEBUG(10, ("create_canon_ace_lists: ignoring "
-                                          "non-mappable SID %s\n",
-                                          sid_string_dbg(&psa->trustee)));
-                               SAFE_FREE(current_ace);
-                               continue;
+                       if (!sids_to_unixids(&current_ace->trustee, 1, &unixid)) {
+                               free_canon_ace_list(file_ace);
+                               free_canon_ace_list(dir_ace);
+                               TALLOC_FREE(current_ace);
+                               DEBUG(0, ("create_canon_ace_lists: sids_to_unixids "
+                                       "failed for %s (allocation failure)\n",
+                                       sid_string_dbg(&current_ace->trustee)));
+                               return false;
                        }
 
-                       free_canon_ace_list(file_ace);
-                       free_canon_ace_list(dir_ace);
-                       DEBUG(0, ("create_canon_ace_lists: unable to map SID "
-                                 "%s to uid or gid.\n",
-                                 sid_string_dbg(&current_ace->trustee)));
-                       SAFE_FREE(current_ace);
-                       return False;
-               }
-
-               /*
-                * Map the given NT permissions into a UNIX mode_t containing only
-                * S_I(R|W|X)USR bits.
-                */
-
-               current_ace->perms |= map_nt_perms( &psa->access_mask, S_IRUSR);
-               current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
-
-               /* Store the ace_flag. */
-               current_ace->ace_flags = psa->flags;
-
-               /*
-                * Now add the created ace to either the file list, the directory
-                * list, or both. We *MUST* preserve the order here (hence we use
-                * DLIST_ADD_END) as NT ACLs are order dependent.
-                */
-
-               if (fsp->is_directory) {
-
-                       /*
-                        * We can only add to the default POSIX ACE list if the ACE is
-                        * designed to be inherited by both files and directories.
-                        */
-
-                       if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
-                               (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
-
-                               DLIST_ADD_END(dir_ace, current_ace, canon_ace *);
-
-                               /*
-                                * Note if this was an allow ace. We can't process
-                                * any further deny ace's after this.
-                                */
-
-                               if (current_ace->attr == ALLOW_ACE)
-                                       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_str_dbg(fsp)));
-                                       free_canon_ace_list(file_ace);
-                                       free_canon_ace_list(dir_ace);
-                                       return False;
-                               }       
-
-                               if( DEBUGLVL( 10 )) {
-                                       dbgtext("create_canon_ace_lists: adding dir ACL:\n");
-                                       print_canon_ace( current_ace, 0);
-                               }
-
-                               /*
-                                * If this is not an inherit only ACE we need to add a duplicate
-                                * to the file acl.
-                                */
-
-                               if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
-                                       canon_ace *dup_ace = dup_canon_ace(current_ace);
+                       if (unixid.type == ID_TYPE_BOTH) {
+                               /* If it's the owning user, this is a
+                                * user_obj, not a user.  This way, we
+                                * get a valid ACL for groups that own
+                                * files, without putting user ACL
+                                * entries in for groups otherwise */
+                               if (unixid.id == pst->st_ex_uid) {
+                                       current_ace->owner_type = UID_ACE;
+                                       current_ace->unix_ug.type = ID_TYPE_UID;
+                                       current_ace->unix_ug.id = unixid.id;
+                                       current_ace->type = SMB_ACL_USER_OBJ;
+
+                                       /* Add the user object to the posix ACL,
+                                          and proceed to the group mapping
+                                          below. This handles the talloc_free
+                                          of current_ace if not added for some
+                                          reason */
+                                       if (!add_current_ace_to_acl(fsp,
+                                                       psa,
+                                                       &file_ace,
+                                                       &dir_ace,
+                                                       &got_file_allow,
+                                                       &got_dir_allow,
+                                                       &all_aces_are_inherit_only,
+                                                       current_ace)) {
+                                               free_canon_ace_list(file_ace);
+                                               free_canon_ace_list(dir_ace);
+                                               return false;
+                                       }
 
-                                       if (!dup_ace) {
-                                               DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
+                                       if ((current_ace = talloc(talloc_tos(),
+                                                       canon_ace)) == NULL) {
                                                free_canon_ace_list(file_ace);
                                                free_canon_ace_list(dir_ace);
+                                               DEBUG(0,("create_canon_ace_lists: "
+                                                       "malloc fail.\n"));
                                                return False;
                                        }
 
-                                       /*
-                                        * We must not free current_ace here as its
-                                        * pointer is now owned by the dir_ace list.
-                                        */
-                                       current_ace = dup_ace;
-                               } else {
-                                       /*
-                                        * We must not free current_ace here as its
-                                        * pointer is now owned by the dir_ace list.
-                                        */
-                                       current_ace = NULL;
+                                       ZERO_STRUCTP(current_ace);
                                }
-                       }
-               }
 
-               /*
-                * Only add to the file ACL if not inherit only.
-                */
+                               sid_copy(&current_ace->trustee, &psa->trustee);
 
-               if (current_ace && !(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
-                       DLIST_ADD_END(file_ace, current_ace, canon_ace *);
+                               current_ace->unix_ug.type = ID_TYPE_GID;
+                               current_ace->unix_ug.id = unixid.id;
+                               current_ace->owner_type = GID_ACE;
+                               /* If it's the primary group, this is a
+                                  group_obj, not a group. */
+                               if (current_ace->unix_ug.id == pst->st_ex_gid) {
+                                       current_ace->type = SMB_ACL_GROUP_OBJ;
+                               } else {
+                                       current_ace->type = SMB_ACL_GROUP;
+                               }
 
-                       /*
-                        * Note if this was an allow ace. We can't process
-                        * any further deny ace's after this.
-                        */
+                       } else if (unixid.type == ID_TYPE_UID) {
+                               current_ace->owner_type = UID_ACE;
+                               current_ace->unix_ug.type = ID_TYPE_UID;
+                               current_ace->unix_ug.id = unixid.id;
+                               /* If it's the owning user, this is a user_obj,
+                                  not a user. */
+                               if (current_ace->unix_ug.id == pst->st_ex_uid) {
+                                       current_ace->type = SMB_ACL_USER_OBJ;
+                               } else {
+                                       current_ace->type = SMB_ACL_USER;
+                               }
+                       } else if (unixid.type == ID_TYPE_GID) {
+                               current_ace->unix_ug.type = ID_TYPE_GID;
+                               current_ace->unix_ug.id = unixid.id;
+                               current_ace->owner_type = GID_ACE;
+                               /* If it's the primary group, this is a
+                                  group_obj, not a group. */
+                               if (current_ace->unix_ug.id == pst->st_ex_gid) {
+                                       current_ace->type = SMB_ACL_GROUP_OBJ;
+                               } else {
+                                       current_ace->type = SMB_ACL_GROUP;
+                               }
+                       } else {
+                               /*
+                                * Silently ignore map failures in non-mappable SIDs (NT Authority, BUILTIN etc).
+                                */
 
-                       if (current_ace->attr == ALLOW_ACE)
-                               got_file_allow = True;
+                               if (non_mappable_sid(&psa->trustee)) {
+                                       DEBUG(10, ("create_canon_ace_lists: ignoring "
+                                                  "non-mappable SID %s\n",
+                                                  sid_string_dbg(&psa->trustee)));
+                                       TALLOC_FREE(current_ace);
+                                       continue;
+                               }
+
+                               if (lp_force_unknown_acl_user(SNUM(fsp->conn))) {
+                                       DEBUG(10, ("create_canon_ace_lists: ignoring "
+                                               "unknown or foreign SID %s\n",
+                                               sid_string_dbg(&psa->trustee)));
+                                       TALLOC_FREE(current_ace);
+                                       continue;
+                               }
 
-                       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_str_dbg(fsp)));
                                free_canon_ace_list(file_ace);
                                free_canon_ace_list(dir_ace);
-                               return False;
-                       }       
-
-                       if( DEBUGLVL( 10 )) {
-                               dbgtext("create_canon_ace_lists: adding file ACL:\n");
-                               print_canon_ace( current_ace, 0);
+                               DEBUG(0, ("create_canon_ace_lists: unable to map SID "
+                                         "%s to uid or gid.\n",
+                                         sid_string_dbg(&current_ace->trustee)));
+                               TALLOC_FREE(current_ace);
+                               return false;
                        }
-                       all_aces_are_inherit_only = False;
-                       /*
-                        * We must not free current_ace here as its
-                        * pointer is now owned by the file_ace list.
-                        */
-                       current_ace = NULL;
                }
 
-               /*
-                * Free if ACE was not added.
-                */
-
-               SAFE_FREE(current_ace);
+               /* handles the talloc_free of current_ace if not added for some reason */
+               if (!add_current_ace_to_acl(fsp, psa, &file_ace, &dir_ace,
+                                           &got_file_allow, &got_dir_allow,
+                                           &all_aces_are_inherit_only, current_ace)) {
+                       free_canon_ace_list(file_ace);
+                       free_canon_ace_list(dir_ace);
+                       return false;
+               }
        }
 
        if (fsp->is_directory && all_aces_are_inherit_only) {
@@ -1834,17 +2124,15 @@ static bool create_canon_ace_lists(files_struct *fsp,
                dir_ace = NULL;
        } else {
                /*
-                * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in each
-                * ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP
-                * entries can be converted to *_OBJ. Usually we will already have these
-                * entries in the Default ACL, and the Access ACL will not have them.
+                * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in
+                * the file ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP
+                * entries can be converted to *_OBJ. Don't do this for the default
+                * ACL, we will create them separately for this if needed inside
+                * ensure_canon_entry_valid().
                 */
                if (file_ace) {
                        check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);
                }
-               if (dir_ace) {
-                       check_owning_objs(dir_ace, pfile_owner_sid, pfile_grp_sid);
-               }
        }
 
        *ppfile_ace = file_ace;
@@ -1957,7 +2245,7 @@ static bool create_canon_ace_lists(files_struct *fsp,
  allow entries.
 ****************************************************************************/
 
-static void process_deny_list( canon_ace **pp_ace_list )
+static void process_deny_list(connection_struct *conn, canon_ace **pp_ace_list )
 {
        canon_ace *ace_list = *pp_ace_list;
        canon_ace *curr_ace = NULL;
@@ -1981,7 +2269,7 @@ static void process_deny_list( canon_ace **pp_ace_list )
                        continue;
                }
 
-               if (!sid_equal(&curr_ace->trustee, &global_sid_World))
+               if (!dom_sid_equal(&curr_ace->trustee, &global_sid_World))
                        continue;
 
                /* JRATEST - assert. */
@@ -1994,11 +2282,11 @@ static void process_deny_list( canon_ace **pp_ace_list )
                         * list at this point including this entry.
                         */
 
-                       canon_ace *prev_entry = curr_ace->prev;
+                       canon_ace *prev_entry = DLIST_PREV(curr_ace);
 
                        free_canon_ace_list( curr_ace );
                        if (prev_entry)
-                               prev_entry->next = NULL;
+                               DLIST_REMOVE(ace_list, prev_entry);
                        else {
                                /* We deleted the entire list. */
                                ace_list = NULL;
@@ -2062,7 +2350,7 @@ static void process_deny_list( canon_ace **pp_ace_list )
                        if (allow_ace_p->owner_type == UID_ACE)
                                continue;
 
-                       if (uid_entry_in_group( curr_ace, allow_ace_p))
+                       if (uid_entry_in_group(conn, curr_ace, allow_ace_p))
                                new_perms |= allow_ace_p->perms;
                }
 
@@ -2106,7 +2394,7 @@ static void process_deny_list( canon_ace **pp_ace_list )
 
                        /* Mask off the deny group perms. */
 
-                       if (uid_entry_in_group( allow_ace_p, curr_ace))
+                       if (uid_entry_in_group(conn, allow_ace_p, curr_ace))
                                allow_ace_p->perms &= ~curr_ace->perms;
                }
 
@@ -2156,7 +2444,7 @@ static void process_deny_list( canon_ace **pp_ace_list )
 
                        /* OR in the group perms. */
 
-                       if (uid_entry_in_group( curr_ace, allow_ace_p))
+                       if (uid_entry_in_group(conn, curr_ace, allow_ace_p))
                                curr_ace->perms |= allow_ace_p->perms;
                }
        }
@@ -2166,56 +2454,18 @@ static void process_deny_list( canon_ace **pp_ace_list )
 }
 
 /****************************************************************************
- Create a default mode that will be used if a security descriptor entry has
- no user/group/world entries.
-****************************************************************************/
-
-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;
-
-       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);
-
-       /*
-        * Now AND with the create mode/directory mode bits then OR with the
-        * force create mode/force directory mode bits.
-        */
-
-       if (fsp->is_directory) {
-               and_bits = lp_dir_security_mask(snum);
-               or_bits = lp_force_dir_security_mode(snum);
-       } else {
-               and_bits = lp_security_mask(snum);
-               or_bits = lp_force_security_mode(snum);
-       }
-
-       return ((mode & and_bits)|or_bits);
-}
-
-/****************************************************************************
- Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
+ Unpack a struct security_descriptor into two canonical ace lists. We don't depend on this
  succeeding.
 ****************************************************************************/
 
 static bool unpack_canon_ace(files_struct *fsp,
-                               SMB_STRUCT_STAT *pst,
-                               DOM_SID *pfile_owner_sid,
-                               DOM_SID *pfile_grp_sid,
+                               const SMB_STRUCT_STAT *pst,
+                               struct dom_sid *pfile_owner_sid,
+                               struct dom_sid *pfile_grp_sid,
                                canon_ace **ppfile_ace,
                                canon_ace **ppdir_ace,
                                uint32 security_info_sent,
-                               const SEC_DESC *psd)
+                               const struct security_descriptor *psd)
 {
        canon_ace *file_ace = NULL;
        canon_ace *dir_ace = NULL;
@@ -2232,7 +2482,7 @@ static bool unpack_canon_ace(files_struct *fsp,
         * If no DACL then this is a chown only security descriptor.
         */
 
-       if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !psd->dacl)
+       if(!(security_info_sent & SECINFO_DACL) || !psd->dacl)
                return True;
 
        /*
@@ -2256,10 +2506,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,10 +2517,10 @@ static bool unpack_canon_ace(files_struct *fsp,
         */
 
        print_canon_ace_list( "file ace - before deny", file_ace);
-       process_deny_list( &file_ace);
+       process_deny_list(fsp->conn, &file_ace);
 
        print_canon_ace_list( "dir ace - before deny", dir_ace);
-       process_deny_list( &dir_ace);
+       process_deny_list(fsp->conn, &dir_ace);
 
        /*
         * A well formed POSIX file or default ACL has at least 3 entries, a 
@@ -2280,14 +2530,8 @@ static bool unpack_canon_ace(files_struct *fsp,
 
        print_canon_ace_list( "file ace - before valid", file_ace);
 
-       /*
-        * 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);
-
-       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(fsp->conn, &file_ace, fsp->conn->params,
+                       fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst, True)) {
                free_canon_ace_list(file_ace);
                free_canon_ace_list(dir_ace);
                return False;
@@ -2295,15 +2539,8 @@ static bool unpack_canon_ace(files_struct *fsp,
 
        print_canon_ace_list( "dir ace - before valid", dir_ace);
 
-       /*
-        * A default inheritable 3 element mode entry for a directory should be the
-        * mode Samba will use to create a file within. Ensure user rwx bits are set if
-        * it's a directory.
-        */
-
-       pst->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(fsp->conn, &dir_ace, fsp->conn->params,
+                       fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst, True)) {
                free_canon_ace_list(file_ace);
                free_canon_ace_list(dir_ace);
                return False;
@@ -2384,7 +2621,7 @@ static void arrange_posix_perms(const char *filename, canon_ace **pp_list_head)
 static canon_ace *canonicalise_acl(struct connection_struct *conn,
                                   const char *fname, SMB_ACL_T posix_acl,
                                   const SMB_STRUCT_STAT *psbuf,
-                                  const DOM_SID *powner, const DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type)
+                                  const struct dom_sid *powner, const struct dom_sid *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type)
 {
        mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
        canon_ace *l_head = NULL;
@@ -2394,20 +2631,20 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn,
        SMB_ACL_ENTRY_T entry;
        size_t ace_count;
 
-       while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
+       while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
                SMB_ACL_TAG_T tagtype;
                SMB_ACL_PERMSET_T permset;
-               DOM_SID sid;
-               posix_id unix_ug;
+               struct dom_sid sid;
+               struct unixid unix_ug;
                enum ace_owner owner_type;
 
                entry_id = SMB_ACL_NEXT_ENTRY;
 
                /* Is this a MASK entry ? */
-               if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
+               if (sys_acl_get_tag_type(entry, &tagtype) == -1)
                        continue;
 
-               if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
+               if (sys_acl_get_permset(entry, &permset) == -1)
                        continue;
 
                /* Decide which SID to use based on the ACL type. */
@@ -2415,50 +2652,43 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn,
                        case SMB_ACL_USER_OBJ:
                                /* Get the SID from the owner. */
                                sid_copy(&sid, powner);
-                               unix_ug.uid = psbuf->st_ex_uid;
+                               unix_ug.type = ID_TYPE_UID;
+                               unix_ug.id = psbuf->st_ex_uid;
                                owner_type = UID_ACE;
                                break;
                        case SMB_ACL_USER:
                                {
-                                       uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
+                                       uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
                                        if (puid == NULL) {
                                                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;
+                                       unix_ug.type = ID_TYPE_UID;
+                                       unix_ug.id = *puid;
                                        owner_type = UID_ACE;
-                                       SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
+                                       sys_acl_free_qualifier((void *)puid,tagtype);
                                        break;
                                }
                        case SMB_ACL_GROUP_OBJ:
                                /* Get the SID from the owning group. */
                                sid_copy(&sid, pgroup);
-                               unix_ug.gid = psbuf->st_ex_gid;
+                               unix_ug.type = ID_TYPE_GID;
+                               unix_ug.id = psbuf->st_ex_gid;
                                owner_type = GID_ACE;
                                break;
                        case SMB_ACL_GROUP:
                                {
-                                       gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
+                                       gid_t *pgid = (gid_t *)sys_acl_get_qualifier(entry);
                                        if (pgid == NULL) {
                                                DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
                                                continue;
                                        }
                                        gid_to_sid( &sid, *pgid);
-                                       unix_ug.gid = *pgid;
+                                       unix_ug.type = ID_TYPE_GID;
+                                       unix_ug.id = *pgid;
                                        owner_type = GID_ACE;
-                                       SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
+                                       sys_acl_free_qualifier((void *)pgid,tagtype);
                                        break;
                                }
                        case SMB_ACL_MASK:
@@ -2467,7 +2697,8 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn,
                        case SMB_ACL_OTHER:
                                /* Use the Everyone SID */
                                sid = global_sid_World;
-                               unix_ug.world = -1;
+                               unix_ug.type = ID_TYPE_NOT_SPECIFIED;
+                               unix_ug.id = -1;
                                owner_type = WORLD_ACE;
                                break;
                        default:
@@ -2479,7 +2710,7 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn,
                 * Add this entry to the list.
                 */
 
-               if ((ace = SMB_MALLOC_P(canon_ace)) == NULL)
+               if ((ace = talloc(talloc_tos(), canon_ace)) == NULL)
                        goto fail;
 
                ZERO_STRUCTP(ace);
@@ -2498,7 +2729,7 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn,
         * This next call will ensure we have at least a user/group/world set.
         */
 
-       if (!ensure_canon_entry_valid(&l_head, conn->params,
+       if (!ensure_canon_entry_valid(conn, &l_head, conn->params,
                                      S_ISDIR(psbuf->st_ex_mode), powner, pgroup,
                                      psbuf, False))
                goto fail;
@@ -2542,12 +2773,13 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn,
  Check if the current user group list contains a given group.
 ****************************************************************************/
 
-static bool current_user_in_group(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);
 
-       for (i = 0; i < current_user.ut.ngroups; i++) {
-               if (current_user.ut.groups[i] == gid) {
+       for (i = 0; i < utok->ngroups; i++) {
+               if (utok->groups[i] == gid) {
                        return True;
                }
        }
@@ -2568,7 +2800,7 @@ static bool acl_group_override(connection_struct *conn,
 
        /* file primary group == user primary or supplementary group */
        if (lp_acl_group_control(SNUM(conn)) &&
-           current_user_in_group(smb_fname->st.st_ex_gid)) {
+           current_user_in_group(conn, smb_fname->st.st_ex_gid)) {
                return true;
        }
 
@@ -2593,7 +2825,7 @@ static bool set_canon_ace_list(files_struct *fsp,
 {
        connection_struct *conn = fsp->conn;
        bool ret = False;
-       SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, (int)count_canon_ace_list(the_ace) + 1);
+       SMB_ACL_T the_acl = sys_acl_init(count_canon_ace_list(the_ace) + 1);
        canon_ace *p_ace;
        int i;
        SMB_ACL_ENTRY_T mask_entry;
@@ -2604,7 +2836,9 @@ static bool set_canon_ace_list(files_struct *fsp,
        mode_t mask_perms = 0;
 
        /* Use the psbuf that was passed in. */
-       fsp->fsp_name->st = *psbuf;
+       if (psbuf != &fsp->fsp_name->st) {
+               fsp->fsp_name->st = *psbuf;
+       }
 
 #if defined(POSIX_ACL_NEEDS_MASK)
        /* HP-UX always wants to have a mask (called "class" there). */
@@ -2654,7 +2888,7 @@ static bool set_canon_ace_list(files_struct *fsp,
                 * Get the entry for this ACE.
                 */
 
-               if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
+               if (sys_acl_create_entry(&the_acl, &the_entry) == -1) {
                        DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
                                i, strerror(errno) ));
                        goto fail;
@@ -2692,7 +2926,7 @@ static bool set_canon_ace_list(files_struct *fsp,
                 */
 
                if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
-                       if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
+                       if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&p_ace->unix_ug.id) == -1) {
                                DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
                                        i, strerror(errno) ));
                                goto fail;
@@ -2703,7 +2937,7 @@ static bool set_canon_ace_list(files_struct *fsp,
                 * Convert the mode_t perms in the canon_ace to a POSIX permset.
                 */
 
-               if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
+               if (sys_acl_get_permset(the_entry, &the_permset) == -1) {
                        DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
                                i, strerror(errno) ));
                        goto fail;
@@ -2731,7 +2965,7 @@ static bool set_canon_ace_list(files_struct *fsp,
        }
 
        if (needs_mask && !got_mask_entry) {
-               if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &mask_entry) == -1) {
+               if (sys_acl_create_entry(&the_acl, &mask_entry) == -1) {
                        DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
                        goto fail;
                }
@@ -2741,7 +2975,7 @@ static bool set_canon_ace_list(files_struct *fsp,
                        goto fail;
                }
 
-               if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, mask_entry, &mask_permset) == -1) {
+               if (sys_acl_get_permset(mask_entry, &mask_permset) == -1) {
                        DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
                        goto fail;
                }
@@ -2841,7 +3075,7 @@ static bool set_canon_ace_list(files_struct *fsp,
   fail:
 
        if (the_acl != NULL) {
-               SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
+               sys_acl_free_acl(the_acl);
        }
 
        return ret;
@@ -2851,12 +3085,12 @@ static bool set_canon_ace_list(files_struct *fsp,
  Find a particular canon_ace entry.
 ****************************************************************************/
 
-static struct canon_ace *canon_ace_entry_for(struct canon_ace *list, SMB_ACL_TAG_T type, posix_id *id)
+static struct canon_ace *canon_ace_entry_for(struct canon_ace *list, SMB_ACL_TAG_T type, struct unixid *id)
 {
        while (list) {
                if (list->type == type && ((type != SMB_ACL_USER && type != SMB_ACL_GROUP) ||
-                               (type == SMB_ACL_USER  && id && id->uid == list->unix_ug.uid) ||
-                               (type == SMB_ACL_GROUP && id && id->gid == list->unix_ug.gid)))
+                               (type == SMB_ACL_USER  && id && id->id == list->unix_ug.id) ||
+                               (type == SMB_ACL_GROUP && id && id->id == list->unix_ug.id)))
                        break;
                list = list->next;
        }
@@ -2873,8 +3107,8 @@ SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl)
 
        if (!the_acl)
                return NULL;
-       if (SMB_VFS_SYS_ACL_GET_ENTRY(conn, the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
-               SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
+       if (sys_acl_get_entry(the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
+               sys_acl_free_acl(the_acl);
                return NULL;
        }
        return the_acl;
@@ -2964,7 +3198,7 @@ static bool convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file
   Based on code from "Jim McDonough" <jmcd@us.ibm.com>.
 ****************************************************************************/
 
-static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
+static size_t merge_default_aces( struct security_ace *nt_ace_list, size_t num_aces)
 {
        size_t i, j;
 
@@ -2979,7 +3213,7 @@ static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
                        if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
                                (nt_ace_list[i].size == nt_ace_list[j].size) &&
                                (nt_ace_list[i].access_mask == nt_ace_list[j].access_mask) &&
-                               sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
+                               dom_sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
                                (i_inh == j_inh) &&
                                (i_flags_ni == 0) &&
                                (j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT|
@@ -2996,7 +3230,7 @@ static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
                                                                (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
                                        if (num_aces - i - 1 > 0)
                                                memmove(&nt_ace_list[i], &nt_ace_list[i+1], (num_aces-i-1) *
-                                                               sizeof(SEC_ACE));
+                                                               sizeof(struct security_ace));
 
                                        DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n",
                                                (unsigned int)i, (unsigned int)j ));
@@ -3010,7 +3244,7 @@ static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
                                                                (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
                                        if (num_aces - j - 1 > 0)
                                                memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) *
-                                                               sizeof(SEC_ACE));
+                                                               sizeof(struct security_ace));
 
                                        DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n",
                                                (unsigned int)j, (unsigned int)i ));
@@ -3035,15 +3269,15 @@ static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
  * any reallocation of memory.
  */
 
-static void add_or_replace_ace(SEC_ACE *nt_ace_list, size_t *num_aces,
-                               const DOM_SID *sid, enum security_ace_type type,
+static void add_or_replace_ace(struct security_ace *nt_ace_list, size_t *num_aces,
+                               const struct dom_sid *sid, enum security_ace_type type,
                                uint32_t mask, uint8_t flags)
 {
        int i;
 
        /* first search for a duplicate */
        for (i = 0; i < *num_aces; i++) {
-               if (sid_equal(&nt_ace_list[i].trustee, sid) &&
+               if (dom_sid_equal(&nt_ace_list[i].trustee, sid) &&
                    (nt_ace_list[i].flags == flags)) break;
        }
 
@@ -3074,21 +3308,21 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
                                      SMB_ACL_T posix_acl,
                                      SMB_ACL_T def_acl,
                                      uint32_t security_info,
-                                     SEC_DESC **ppdesc)
+                                     struct security_descriptor **ppdesc)
 {
-       DOM_SID owner_sid;
-       DOM_SID group_sid;
+       struct dom_sid owner_sid;
+       struct dom_sid group_sid;
        size_t sd_size = 0;
-       SEC_ACL *psa = NULL;
+       struct security_acl *psa = NULL;
        size_t num_acls = 0;
        size_t num_def_acls = 0;
        size_t num_aces = 0;
        canon_ace *file_ace = NULL;
        canon_ace *dir_ace = NULL;
-       SEC_ACE *nt_ace_list = NULL;
+       struct security_ace *nt_ace_list = NULL;
        size_t num_profile_acls = 0;
-       DOM_SID orig_owner_sid;
-       SEC_DESC *psd = NULL;
+       struct dom_sid orig_owner_sid;
+       struct security_descriptor *psd = NULL;
        int i;
 
        /*
@@ -3105,7 +3339,7 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
                num_profile_acls = 3;
        }
 
-       if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) {
+       if ((security_info & SECINFO_DACL) && !(security_info & SECINFO_PROTECTED_DACL)) {
 
                /*
                 * In the optimum case Creator Owner and Creator Group would be used for
@@ -3160,12 +3394,12 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
                                ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL);
                                if (ace && !ace->perms) {
                                        DLIST_REMOVE(dir_ace, ace);
-                                       SAFE_FREE(ace);
+                                       TALLOC_FREE(ace);
 
                                        ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL);
                                        if (ace && !ace->perms) {
                                                DLIST_REMOVE(file_ace, ace);
-                                               SAFE_FREE(ace);
+                                               TALLOC_FREE(ace);
                                        }
                                }
 
@@ -3182,14 +3416,14 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
                                ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL);
                                if (ace && !ace->perms) {
                                        DLIST_REMOVE(dir_ace, ace);
-                                       SAFE_FREE(ace);
+                                       TALLOC_FREE(ace);
                                }
 #endif
 
                                ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL);
                                if (ace && !ace->perms) {
                                        DLIST_REMOVE(file_ace, ace);
-                                       SAFE_FREE(ace);
+                                       TALLOC_FREE(ace);
                                }
                        }
 
@@ -3197,12 +3431,12 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
                        num_def_acls = count_canon_ace_list(dir_ace);
 
                        /* Allocate the ace list. */
-                       if ((nt_ace_list = SMB_MALLOC_ARRAY(SEC_ACE,num_acls + num_profile_acls + num_def_acls)) == NULL) {
+                       if ((nt_ace_list = talloc_array(talloc_tos(), struct security_ace,num_acls + num_profile_acls + num_def_acls)) == NULL) {
                                DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
                                goto done;
                        }
 
-                       memset(nt_ace_list, '\0', (num_acls + num_def_acls) * sizeof(SEC_ACE) );
+                       memset(nt_ace_list, '\0', (num_acls + num_def_acls) * sizeof(struct security_ace) );
 
                        /*
                         * Create the NT ACE list from the canonical ace lists.
@@ -3266,7 +3500,7 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
 
                        if (lp_profile_acls(SNUM(conn))) {
                                for (i = 0; i < num_aces; i++) {
-                                       if (sid_equal(&nt_ace_list[i].trustee, &owner_sid)) {
+                                       if (dom_sid_equal(&nt_ace_list[i].trustee, &owner_sid)) {
                                                add_or_replace_ace(nt_ace_list, &num_aces,
                                                                   &orig_owner_sid,
                                                                   nt_ace_list[i].type,
@@ -3284,11 +3518,11 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
                                goto done;
                        }
                }
-       } /* security_info & DACL_SECURITY_INFORMATION */
+       } /* security_info & SECINFO_DACL */
 
        psd = make_standard_sec_desc( talloc_tos(),
-                       (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL,
-                       (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL,
+                       (security_info & SECINFO_OWNER) ? &owner_sid : NULL,
+                       (security_info & SECINFO_GROUP) ? &group_sid : NULL,
                        psa,
                        &sd_size);
 
@@ -3323,21 +3557,21 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
  done:
 
        if (posix_acl) {
-               SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
+               sys_acl_free_acl(posix_acl);
        }
        if (def_acl) {
-               SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+               sys_acl_free_acl(def_acl);
        }
        free_canon_ace_list(file_ace);
        free_canon_ace_list(dir_ace);
        free_inherited_info(pal);
-       SAFE_FREE(nt_ace_list);
+       TALLOC_FREE(nt_ace_list);
 
        return NT_STATUS_OK;
 }
 
 NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info,
-                          SEC_DESC **ppdesc)
+                          struct security_descriptor **ppdesc)
 {
        SMB_STRUCT_STAT sbuf;
        SMB_ACL_T posix_acl = NULL;
@@ -3370,128 +3604,119 @@ NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info,
 }
 
 NTSTATUS posix_get_nt_acl(struct connection_struct *conn, const char *name,
-                         uint32_t security_info, SEC_DESC **ppdesc)
+                         uint32_t security_info, struct security_descriptor **ppdesc)
 {
        SMB_ACL_T posix_acl = NULL;
        SMB_ACL_T def_acl = NULL;
        struct pai_val *pal;
-       struct smb_filename *smb_fname = NULL;
-       NTSTATUS status;
+       struct smb_filename smb_fname;
+       int ret;
 
        *ppdesc = NULL;
 
        DEBUG(10,("posix_get_nt_acl: called for file %s\n", name ));
 
-       status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL,
-                                           &smb_fname);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
+       ZERO_STRUCT(smb_fname);
+       smb_fname.base_name = discard_const_p(char, name);
 
        /* Get the stat struct for the owner info. */
-       if(SMB_VFS_STAT(conn, smb_fname) != 0) {
-               status = map_nt_error_from_unix(errno);
-               goto out;
+       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);
        }
 
        /* Get the ACL from the path. */
        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(smb_fname->st.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);
 
-       status = posix_get_nt_acl_common(conn, name, &smb_fname->st, pal,
-                                        posix_acl, def_acl, security_info,
-                                        ppdesc);
- out:
-       TALLOC_FREE(smb_fname);
-       return status;
+       return posix_get_nt_acl_common(conn, name, &smb_fname.st, pal,
+                                      posix_acl, def_acl, security_info,
+                                      ppdesc);
 }
 
 /****************************************************************************
  Try to chown a file. We will be able to chown it under the following conditions.
 
   1) If we have root privileges, then it will just work.
-  2) If we have SeTakeOwnershipPrivilege we can change the user to the current user.
-  3) If we have SeRestorePrivilege we can change the user to any other user. 
+  2) If we have SeRestorePrivilege we can change the user + group to any other user. 
+  3) If we have SeTakeOwnershipPrivilege we can change the user to the current user.
   4) If we have write permission to the file and dos_filemodes is set
      then allow chown to the currently authenticated user.
 ****************************************************************************/
 
-int try_chown(connection_struct *conn, struct smb_filename *smb_fname,
-             uid_t uid, gid_t gid)
+NTSTATUS try_chown(files_struct *fsp, uid_t uid, gid_t gid)
 {
-       int ret;
-       files_struct *fsp;
+       NTSTATUS status;
 
-       if(!CAN_WRITE(conn)) {
-               return -1;
+       if(!CAN_WRITE(fsp->conn)) {
+               return NT_STATUS_MEDIA_WRITE_PROTECTED;
        }
 
        /* Case (1). */
-       /* try the direct way first */
-       ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid, gid);
-       if (ret == 0)
-               return 0;
+       status = vfs_chown_fsp(fsp, uid, gid);
+       if (NT_STATUS_IS_OK(status)) {
+               return status;
+       }
 
        /* Case (2) / (3) */
        if (lp_enable_privileges()) {
+               bool has_take_ownership_priv = security_token_has_privilege(
+                                               get_current_nttok(fsp->conn),
+                                               SEC_PRIV_TAKE_OWNERSHIP);
+               bool has_restore_priv = security_token_has_privilege(
+                                               get_current_nttok(fsp->conn),
+                                               SEC_PRIV_RESTORE);
+
+               if (has_restore_priv) {
+                       ; /* Case (2) */
+               } else if (has_take_ownership_priv) {
+                       /* Case (3) */
+                       if (uid == get_current_uid(fsp->conn)) {
+                               gid = (gid_t)-1;
+                       } else {
+                               has_take_ownership_priv = false;
+                       }
+               }
 
-               bool has_take_ownership_priv = user_has_privileges(current_user.nt_user_token,
-                                                             &se_take_ownership);
-               bool has_restore_priv = user_has_privileges(current_user.nt_user_token,
-                                                      &se_restore);
-
-               /* Case (2) */
-               if ( ( has_take_ownership_priv && ( uid == current_user.ut.uid ) ) ||
-               /* Case (3) */
-                    ( has_restore_priv ) ) {
-
+               if (has_take_ownership_priv || has_restore_priv) {
                        become_root();
-                       /* Keep the current file gid the same - take ownership doesn't imply group change. */
-                       ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid,
-                                           (gid_t)-1);
+                       status = vfs_chown_fsp(fsp, uid, gid);
                        unbecome_root();
-                       return ret;
+                       return status;
                }
        }
 
        /* Case (4). */
-       if (!lp_dos_filemode(SNUM(conn))) {
-               errno = EPERM;
-               return -1;
+       if (!lp_dos_filemode(SNUM(fsp->conn))) {
+               return NT_STATUS_ACCESS_DENIED;
        }
 
        /* only allow chown to the current user. This is more secure,
           and also copes with the case where the SID in a take ownership ACL is
           a local SID on the users workstation
        */
-       if (uid != current_user.ut.uid) {
-               errno = EPERM;
-               return -1;
-       }
-
-       if (SMB_VFS_STAT(conn, smb_fname)) {
-               return -1;
-       }
-
-       if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname, &fsp))) {
-               return -1;
+       if (uid != get_current_uid(fsp->conn)) {
+               return NT_STATUS_ACCESS_DENIED;
        }
 
        become_root();
        /* Keep the current file gid the same. */
-       ret = SMB_VFS_FCHOWN(fsp, uid, (gid_t)-1);
+       status = vfs_chown_fsp(fsp, uid, (gid_t)-1);
        unbecome_root();
 
-       close_file_fchmod(NULL, fsp);
-
-       return ret;
+       return status;
 }
 
 #if 0
@@ -3502,20 +3727,20 @@ int try_chown(connection_struct *conn, struct smb_filename *smb_fname,
 ****************************************************************************/
 
 NTSTATUS append_parent_acl(files_struct *fsp,
-                               const SEC_DESC *pcsd,
-                               SEC_DESC **pp_new_sd)
+                               const struct security_descriptor *pcsd,
+                               struct security_descriptor **pp_new_sd)
 {
        struct smb_filename *smb_dname = NULL;
-       SEC_DESC *parent_sd = NULL;
+       struct security_descriptor *parent_sd = NULL;
        files_struct *parent_fsp = NULL;
        TALLOC_CTX *mem_ctx = talloc_tos();
        char *parent_name = NULL;
-       SEC_ACE *new_ace = NULL;
+       struct security_ace *new_ace = NULL;
        unsigned int num_aces = pcsd->dacl->num_aces;
        NTSTATUS status;
        int info;
        unsigned int i, j;
-       SEC_DESC *psd = dup_sec_desc(talloc_tos(), pcsd);
+       struct security_descriptor *psd = dup_sec_desc(talloc_tos(), pcsd);
        bool is_dacl_protected = (pcsd->type & SEC_DESC_DACL_PROTECTED);
 
        if (psd == NULL) {
@@ -3556,7 +3781,7 @@ NTSTATUS append_parent_acl(files_struct *fsp,
        }
 
        status = SMB_VFS_GET_NT_ACL(parent_fsp->conn, smb_dname->base_name,
-                                   DACL_SECURITY_INFORMATION, &parent_sd );
+                                   SECINFO_DACL, &parent_sd );
 
        close_file(NULL, parent_fsp, NORMAL_CLOSE);
        TALLOC_FREE(smb_dname);
@@ -3579,7 +3804,7 @@ NTSTATUS append_parent_acl(files_struct *fsp,
 
        num_aces += parent_sd->dacl->num_aces;
 
-       if((new_ace = TALLOC_ZERO_ARRAY(mem_ctx, SEC_ACE,
+       if((new_ace = talloc_zero_array(mem_ctx, struct security_ace,
                                        num_aces)) == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -3596,7 +3821,7 @@ NTSTATUS append_parent_acl(files_struct *fsp,
 
        /* Finally append any inherited ACEs. */
        for (j = 0; j < parent_sd->dacl->num_aces; j++) {
-               SEC_ACE *se = &parent_sd->dacl->aces[j];
+               struct security_ace *se = &parent_sd->dacl->aces[j];
 
                if (fsp->is_directory) {
                        if (!(se->flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
@@ -3632,7 +3857,7 @@ NTSTATUS append_parent_acl(files_struct *fsp,
                         * same SID. This is order N^2. Ouch :-(. JRA. */
                        unsigned int k;
                        for (k = 0; k < psd->dacl->num_aces; k++) {
-                               if (sid_equal(&psd->dacl->aces[k].trustee,
+                               if (dom_sid_equal(&psd->dacl->aces[k].trustee,
                                                &se->trustee)) {
                                        break;
                                }
@@ -3687,8 +3912,8 @@ NTSTATUS append_parent_acl(files_struct *fsp,
 
        psd->dacl->aces = new_ace;
        psd->dacl->num_aces = i;
-       psd->type &= ~(SE_DESC_DACL_AUTO_INHERITED|
-                         SE_DESC_DACL_AUTO_INHERIT_REQ);
+       psd->type &= ~(SEC_DESC_DACL_AUTO_INHERITED|
+                         SEC_DESC_DACL_AUTO_INHERIT_REQ);
 
        *pp_new_sd = psd;
        return status;
@@ -3699,15 +3924,17 @@ NTSTATUS append_parent_acl(files_struct *fsp,
  Reply to set a security descriptor on an fsp. security_info_sent is the
  description of the following NT ACL.
  This should be the only external function needed for the UNIX style set ACL.
+ We make a copy of psd_orig as internal functions modify the elements inside
+ it, even though it's a const pointer.
 ****************************************************************************/
 
-NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC *psd)
+NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd_orig)
 {
        connection_struct *conn = fsp->conn;
        uid_t user = (uid_t)-1;
        gid_t grp = (gid_t)-1;
-       DOM_SID file_owner_sid;
-       DOM_SID file_grp_sid;
+       struct dom_sid file_owner_sid;
+       struct dom_sid file_grp_sid;
        canon_ace *file_ace_list = NULL;
        canon_ace *dir_ace_list = NULL;
        bool acl_perms = False;
@@ -3716,6 +3943,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
        bool set_acl_as_root = false;
        bool acl_set_support = false;
        bool ret = false;
+       struct security_descriptor *psd = NULL;
 
        DEBUG(10,("set_nt_acl: called for file %s\n",
                  fsp_str_dbg(fsp)));
@@ -3725,18 +3953,22 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
                return NT_STATUS_MEDIA_WRITE_PROTECTED;
        }
 
+       if (!psd_orig) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       psd = dup_sec_desc(talloc_tos(), psd_orig);
+       if (!psd) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
        /*
         * Get the current state of the file.
         */
 
-       if(fsp->is_directory || fsp->fh->fd == -1) {
-               if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name) != 0) {
-                       return map_nt_error_from_unix(errno);
-               }
-       } else {
-               if(SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 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. */
@@ -3746,7 +3978,15 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
         * Unpack the user/group/world id's.
         */
 
-       status = unpack_nt_owners( SNUM(conn), &user, &grp, security_info_sent, psd);
+       /* POSIX can't cope with missing owner/group. */
+       if ((security_info_sent & SECINFO_OWNER) && (psd->owner_sid == NULL)) {
+               security_info_sent &= ~SECINFO_OWNER;
+       }
+       if ((security_info_sent & SECINFO_GROUP) && (psd->group_sid == NULL)) {
+               security_info_sent &= ~SECINFO_GROUP;
+       }
+
+       status = unpack_nt_owners( conn, &user, &grp, security_info_sent, psd);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -3764,15 +4004,14 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
                         fsp_str_dbg(fsp), (unsigned int)user,
                         (unsigned int)grp));
 
-               if(try_chown(fsp->conn, fsp->fsp_name, user, grp) == -1) {
+               status = try_chown(fsp, user, grp);
+               if(!NT_STATUS_IS_OK(status)) {
                        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;
-                       }
-                       return map_nt_error_from_unix(errno);
+                               "= %s.\n", fsp_str_dbg(fsp),
+                               (unsigned int)user,
+                               (unsigned int)grp,
+                               nt_errstr(status)));
+                       return status;
                }
 
                /*
@@ -3780,21 +4019,9 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
                 * (suid/sgid bits, for instance)
                 */
 
-               if(fsp->is_directory) {
-                       if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name) != 0) {
-                               return map_nt_error_from_unix(errno);
-                       }
-               } else {
-
-                       int sret;
-
-                       if(fsp->fh->fd == -1)
-                               sret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name);
-                       else
-                               sret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
-
-                       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. */
@@ -3808,6 +4035,39 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
 
        create_file_sids(&fsp->fsp_name->st, &file_owner_sid, &file_grp_sid);
 
+       if((security_info_sent & SECINFO_DACL) &&
+                       (psd->type & SEC_DESC_DACL_PRESENT) &&
+                       (psd->dacl == NULL)) {
+               struct security_ace ace[3];
+
+               /* We can't have NULL DACL in POSIX.
+                  Use owner/group/Everyone -> full access. */
+
+               init_sec_ace(&ace[0],
+                               &file_owner_sid,
+                               SEC_ACE_TYPE_ACCESS_ALLOWED,
+                               GENERIC_ALL_ACCESS,
+                               0);
+               init_sec_ace(&ace[1],
+                               &file_grp_sid,
+                               SEC_ACE_TYPE_ACCESS_ALLOWED,
+                               GENERIC_ALL_ACCESS,
+                               0);
+               init_sec_ace(&ace[2],
+                               &global_sid_World,
+                               SEC_ACE_TYPE_ACCESS_ALLOWED,
+                               GENERIC_ALL_ACCESS,
+                               0);
+               psd->dacl = make_sec_acl(talloc_tos(),
+                                       NT4_ACL_REVISION,
+                                       3,
+                                       ace);
+               if (psd->dacl == NULL) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               security_acl_map_generic(psd->dacl, &file_generic_mapping);
+       }
+
        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);
@@ -3828,7 +4088,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
         * Only change security if we got a DACL.
         */
 
-       if(!(security_info_sent & DACL_SECURITY_INFORMATION) || (psd->dacl == NULL)) {
+       if(!(security_info_sent & SECINFO_DACL) || (psd->dacl == NULL)) {
                free_canon_ace_list(file_ace_list);
                free_canon_ace_list(dir_ace_list);
                return NT_STATUS_OK;
@@ -3993,6 +4253,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;
 }
 
@@ -4013,29 +4276,29 @@ int get_acl_group_bits( connection_struct *conn, const char *fname, mode_t *mode
        if (posix_acl == (SMB_ACL_T)NULL)
                return -1;
 
-       while (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
+       while (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
                SMB_ACL_TAG_T tagtype;
                SMB_ACL_PERMSET_T permset;
 
                entry_id = SMB_ACL_NEXT_ENTRY;
 
-               if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) ==-1)
+               if (sys_acl_get_tag_type(entry, &tagtype) ==-1)
                        break;
 
                if (tagtype == SMB_ACL_GROUP_OBJ) {
-                       if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
+                       if (sys_acl_get_permset(entry, &permset) == -1) {
                                break;
                        } else {
                                *mode &= ~(S_IRGRP|S_IWGRP|S_IXGRP);
-                               *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRGRP : 0);
-                               *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWGRP : 0);
-                               *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXGRP : 0);
+                               *mode |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? S_IRGRP : 0);
+                               *mode |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? S_IWGRP : 0);
+                               *mode |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? S_IXGRP : 0);
                                result = 0;
                                break;
                        }
                }
        }
-       SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
+       sys_acl_free_acl(posix_acl);
        return result;
 }
 
@@ -4050,17 +4313,17 @@ static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mo
        SMB_ACL_ENTRY_T entry;
        int num_entries = 0;
 
-       while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
+       while ( sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
                SMB_ACL_TAG_T tagtype;
                SMB_ACL_PERMSET_T permset;
                mode_t perms;
 
                entry_id = SMB_ACL_NEXT_ENTRY;
 
-               if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
+               if (sys_acl_get_tag_type(entry, &tagtype) == -1)
                        return -1;
 
-               if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
+               if (sys_acl_get_permset(entry, &permset) == -1)
                        return -1;
 
                num_entries++;
@@ -4127,7 +4390,7 @@ static int copy_access_posix_acl(connection_struct *conn, const char *from, cons
 
  done:
 
-       SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
+       sys_acl_free_acl(posix_acl);
        return ret;
 }
 
@@ -4152,12 +4415,12 @@ static bool directory_has_default_posix_acl(connection_struct *conn, const char
        bool has_acl = False;
        SMB_ACL_ENTRY_T entry;
 
-       if (def_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, def_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) {
+       if (def_acl != NULL && (sys_acl_get_entry(def_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) {
                has_acl = True;
        }
 
        if (def_acl) {
-               SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+               sys_acl_free_acl(def_acl);
        }
         return has_acl;
 }
@@ -4197,7 +4460,7 @@ int fchmod_acl(files_struct *fsp, mode_t mode)
 
   done:
 
-       SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
+       sys_acl_free_acl(posix_acl);
        return ret;
 }
 
@@ -4211,22 +4474,22 @@ static bool unix_ex_wire_to_permset(connection_struct *conn, unsigned char wire_
                return False;
        }
 
-       if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) ==  -1) {
+       if (sys_acl_clear_perms(*p_permset) ==  -1) {
                return False;
        }
 
        if (wire_perm & SMB_POSIX_ACL_READ) {
-               if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1) {
+               if (sys_acl_add_perm(*p_permset, SMB_ACL_READ) == -1) {
                        return False;
                }
        }
        if (wire_perm & SMB_POSIX_ACL_WRITE) {
-               if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1) {
+               if (sys_acl_add_perm(*p_permset, SMB_ACL_WRITE) == -1) {
                        return False;
                }
        }
        if (wire_perm & SMB_POSIX_ACL_EXECUTE) {
-               if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1) {
+               if (sys_acl_add_perm(*p_permset, SMB_ACL_EXECUTE) == -1) {
                        return False;
                }
        }
@@ -4272,7 +4535,7 @@ static bool unix_ex_wire_to_tagtype(unsigned char wire_tt, SMB_ACL_TAG_T *p_tt)
 static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_acls, const char *pdata)
 {
        unsigned int i;
-       SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, num_acls);
+       SMB_ACL_T the_acl = sys_acl_init(num_acls);
 
        if (the_acl == NULL) {
                return NULL;
@@ -4283,7 +4546,7 @@ static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_
                SMB_ACL_PERMSET_T the_permset;
                SMB_ACL_TAG_T tag_type;
 
-               if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
+               if (sys_acl_create_entry(&the_acl, &the_entry) == -1) {
                        DEBUG(0,("create_posix_acl_from_wire: Failed to create entry %u. (%s)\n",
                                i, strerror(errno) ));
                        goto fail;
@@ -4302,7 +4565,7 @@ static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_
                }
 
                /* Get the permset pointer from the new ACL entry. */
-               if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
+               if (sys_acl_get_permset(the_entry, &the_permset) == -1) {
                        DEBUG(0,("create_posix_acl_from_wire: Failed to get permset on entry %u. (%s)\n",
                                 i, strerror(errno) ));
                         goto fail;
@@ -4348,7 +4611,7 @@ static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_
  fail:
 
        if (the_acl != NULL) {
-               SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
+               sys_acl_free_acl(the_acl);
        }
        return NULL;
 }
@@ -4392,12 +4655,12 @@ bool set_unix_posix_default_acl(connection_struct *conn, const char *fname, cons
        if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT, def_acl) == -1) {
                DEBUG(5,("set_unix_posix_default_acl: acl_set_file failed on directory %s (%s)\n",
                        fname, strerror(errno) ));
-               SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+               sys_acl_free_acl(def_acl);
                return False;
        }
 
        DEBUG(10,("set_unix_posix_default_acl: set default acl for file %s\n", fname ));
-       SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+       sys_acl_free_acl(def_acl);
        return True;
 }
 
@@ -4416,7 +4679,7 @@ static bool remove_posix_acl(connection_struct *conn, files_struct *fsp, const c
        SMB_ACL_ENTRY_T entry;
        bool ret = False;
        /* Create a new ACL with only 3 entries, u/g/w. */
-       SMB_ACL_T new_file_acl = SMB_VFS_SYS_ACL_INIT(conn, 3);
+       SMB_ACL_T new_file_acl = sys_acl_init(3);
        SMB_ACL_ENTRY_T user_ent = NULL;
        SMB_ACL_ENTRY_T group_ent = NULL;
        SMB_ACL_ENTRY_T other_ent = NULL;
@@ -4427,7 +4690,7 @@ static bool remove_posix_acl(connection_struct *conn, files_struct *fsp, const c
        }
 
        /* Now create the u/g/w entries. */
-       if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &user_ent) == -1) {
+       if (sys_acl_create_entry(&new_file_acl, &user_ent) == -1) {
                DEBUG(5,("remove_posix_acl: Failed to create user entry for file %s. (%s)\n",
                        fname, strerror(errno) ));
                goto done;
@@ -4438,7 +4701,7 @@ static bool remove_posix_acl(connection_struct *conn, files_struct *fsp, const c
                goto done;
        }
 
-       if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &group_ent) == -1) {
+       if (sys_acl_create_entry(&new_file_acl, &group_ent) == -1) {
                DEBUG(5,("remove_posix_acl: Failed to create group entry for file %s. (%s)\n",
                        fname, strerror(errno) ));
                goto done;
@@ -4449,7 +4712,7 @@ static bool remove_posix_acl(connection_struct *conn, files_struct *fsp, const c
                goto done;
        }
 
-       if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &other_ent) == -1) {
+       if (sys_acl_create_entry(&new_file_acl, &other_ent) == -1) {
                DEBUG(5,("remove_posix_acl: Failed to create other entry for file %s. (%s)\n",
                        fname, strerror(errno) ));
                goto done;
@@ -4475,19 +4738,19 @@ static bool remove_posix_acl(connection_struct *conn, files_struct *fsp, const c
                goto done;
        }
 
-       while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, file_acl, entry_id, &entry) == 1) {
+       while ( sys_acl_get_entry(file_acl, entry_id, &entry) == 1) {
                SMB_ACL_TAG_T tagtype;
                SMB_ACL_PERMSET_T permset;
 
                entry_id = SMB_ACL_NEXT_ENTRY;
 
-               if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
+               if (sys_acl_get_tag_type(entry, &tagtype) == -1) {
                        DEBUG(5,("remove_posix_acl: failed to get tagtype from ACL on file %s (%s).\n",
                                fname, strerror(errno) ));
                        goto done;
                }
 
-               if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
+               if (sys_acl_get_permset(entry, &permset) == -1) {
                        DEBUG(5,("remove_posix_acl: failed to get permset from ACL on file %s (%s).\n",
                                fname, strerror(errno) ));
                        goto done;
@@ -4531,10 +4794,10 @@ static bool remove_posix_acl(connection_struct *conn, files_struct *fsp, const c
  done:
 
        if (file_acl) {
-               SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+               sys_acl_free_acl(file_acl);
        }
        if (new_file_acl) {
-               SMB_VFS_SYS_ACL_FREE_ACL(conn, new_file_acl);
+               sys_acl_free_acl(new_file_acl);
        }
        return ret;
 }
@@ -4563,20 +4826,20 @@ bool set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *
                if (SMB_VFS_SYS_ACL_SET_FD(fsp, file_acl) == -1) {
                        DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
                                fname, strerror(errno) ));
-                       SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+                       sys_acl_free_acl(file_acl);
                        return False;
                }
        } else {
                if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, file_acl) == -1) {
                        DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
                                fname, strerror(errno) ));
-                       SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+                       sys_acl_free_acl(file_acl);
                        return False;
                }
        }
 
        DEBUG(10,("set_unix_posix_acl: set acl for file %s\n", fname ));
-       SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+       sys_acl_free_acl(file_acl);
        return True;
 }
 
@@ -4590,21 +4853,21 @@ bool set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *
  Assume we are dealing with files (for now)
 ********************************************************************/
 
-SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
+struct security_descriptor *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
 {
-       SEC_DESC *psd, *ret_sd;
+       struct security_descriptor *psd, *ret_sd;
        connection_struct *conn;
        files_struct finfo;
        struct fd_handle fh;
        NTSTATUS status;
 
-       conn = TALLOC_ZERO_P(ctx, connection_struct);
+       conn = talloc_zero(ctx, connection_struct);
        if (conn == NULL) {
                DEBUG(0, ("talloc failed\n"));
                return NULL;
        }
 
-       if (!(conn->params = TALLOC_P(conn, struct share_params))) {
+       if (!(conn->params = talloc(conn, struct share_params))) {
                DEBUG(0,("get_nt_acl_no_snum: talloc() failed!\n"));
                TALLOC_FREE(conn);
                return NULL;
@@ -4623,7 +4886,7 @@ SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
        ZERO_STRUCT( finfo );
        ZERO_STRUCT( fh );
 
-       finfo.fnum = -1;
+       finfo.fnum = FNUM_FIELD_INVALID;
        finfo.conn = conn;
        finfo.fh = &fh;
        finfo.fh->fd = -1;
@@ -4635,7 +4898,7 @@ SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
                return NULL;
        }
 
-       if (!NT_STATUS_IS_OK(SMB_VFS_FGET_NT_ACL( &finfo, DACL_SECURITY_INFORMATION, &psd))) {
+       if (!NT_STATUS_IS_OK(SMB_VFS_FGET_NT_ACL( &finfo, SECINFO_DACL, &psd))) {
                DEBUG(0,("get_nt_acl_no_snum: get_nt_acl returned zero.\n"));
                TALLOC_FREE(finfo.fsp_name);
                conn_free(conn);
@@ -4649,3 +4912,113 @@ SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
 
        return ret_sd;
 }
+
+/* Stolen shamelessly from pvfs_default_acl() in source4 :-). */
+
+NTSTATUS make_default_filesystem_acl(TALLOC_CTX *ctx,
+                                       const char *name,
+                                       SMB_STRUCT_STAT *psbuf,
+                                       struct security_descriptor **ppdesc)
+{
+       struct dom_sid owner_sid, group_sid;
+       size_t size = 0;
+       struct security_ace aces[4];
+       uint32_t access_mask = 0;
+       mode_t mode = psbuf->st_ex_mode;
+       struct security_acl *new_dacl = NULL;
+       int idx = 0;
+
+       DEBUG(10,("make_default_filesystem_acl: file %s mode = 0%o\n",
+               name, (int)mode ));
+
+       uid_to_sid(&owner_sid, psbuf->st_ex_uid);
+       gid_to_sid(&group_sid, psbuf->st_ex_gid);
+
+       /*
+        We provide up to 4 ACEs
+               - Owner
+               - Group
+               - Everyone
+               - NT System
+       */
+
+       if (mode & S_IRUSR) {
+               if (mode & S_IWUSR) {
+                       access_mask |= SEC_RIGHTS_FILE_ALL;
+               } else {
+                       access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
+               }
+       }
+       if (mode & S_IWUSR) {
+               access_mask |= SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE;
+       }
+
+       init_sec_ace(&aces[idx],
+                       &owner_sid,
+                       SEC_ACE_TYPE_ACCESS_ALLOWED,
+                       access_mask,
+                       0);
+       idx++;
+
+       access_mask = 0;
+       if (mode & S_IRGRP) {
+               access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
+       }
+       if (mode & S_IWGRP) {
+               /* note that delete is not granted - this matches posix behaviour */
+               access_mask |= SEC_RIGHTS_FILE_WRITE;
+       }
+       if (access_mask) {
+               init_sec_ace(&aces[idx],
+                       &group_sid,
+                       SEC_ACE_TYPE_ACCESS_ALLOWED,
+                       access_mask,
+                       0);
+               idx++;
+       }
+
+       access_mask = 0;
+       if (mode & S_IROTH) {
+               access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
+       }
+       if (mode & S_IWOTH) {
+               access_mask |= SEC_RIGHTS_FILE_WRITE;
+       }
+       if (access_mask) {
+               init_sec_ace(&aces[idx],
+                       &global_sid_World,
+                       SEC_ACE_TYPE_ACCESS_ALLOWED,
+                       access_mask,
+                       0);
+               idx++;
+       }
+
+       init_sec_ace(&aces[idx],
+                       &global_sid_System,
+                       SEC_ACE_TYPE_ACCESS_ALLOWED,
+                       SEC_RIGHTS_FILE_ALL,
+                       0);
+       idx++;
+
+       new_dacl = make_sec_acl(ctx,
+                       NT4_ACL_REVISION,
+                       idx,
+                       aces);
+
+       if (!new_dacl) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       *ppdesc = make_sec_desc(ctx,
+                       SECURITY_DESCRIPTOR_REVISION_1,
+                       SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
+                       &owner_sid,
+                       &group_sid,
+                       NULL,
+                       new_dacl,
+                       &size);
+       if (!*ppdesc) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       return NT_STATUS_OK;
+}