notifyd: Use messaging_register for MSG_SMB_NOTIFY_GET_DB
[vlendec/samba-autobuild/.git] / source3 / smbd / posix_acls.c
index a833fbf1b758035aba68bd5f63efb5e8849edc99..e4403458495493c7e9a419d6bf5053e5abc0df25 100644 (file)
@@ -27,6 +27,8 @@
 #include "passdb/lookup_sid.h"
 #include "auth.h"
 #include "../librpc/gen_ndr/idmap.h"
+#include "../librpc/gen_ndr/ndr_smb_acl.h"
+#include "lib/param/loadparm.h"
 
 extern const struct generic_mapping file_generic_mapping;
 
@@ -40,12 +42,6 @@ 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;
@@ -53,7 +49,7 @@ typedef struct canon_ace {
        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;
 
@@ -122,7 +118,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 {
@@ -134,18 +130,18 @@ struct pai_val {
 };
 
 /************************************************************************
- Return a uint32 of the pai_entry principal.
+ Return a uint32_t of the pai_entry principal.
 ************************************************************************/
 
 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"));
@@ -154,18 +150,18 @@ static uint32_t get_pai_entry_val(struct pai_entry *paie)
 }
 
 /************************************************************************
- Return a uint32 of the entry principal.
+ Return a uint32_t of the entry principal.
 ************************************************************************/
 
 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"));
@@ -279,7 +275,7 @@ static void store_inheritance_attributes(files_struct *fsp,
                ret = SMB_VFS_FSETXATTR(fsp, SAMBA_POSIX_INHERITANCE_EA_NAME,
                                pai_buf, store_size, 0);
        } else {
-               ret = SMB_VFS_SETXATTR(fsp->conn, fsp->fsp_name->base_name,
+               ret = SMB_VFS_SETXATTR(fsp->conn, fsp->fsp_name,
                                       SAMBA_POSIX_INHERITANCE_EA_NAME,
                                       pai_buf, store_size, 0);
        }
@@ -342,8 +338,8 @@ static uint16_t get_pai_flags(struct pai_val *pal, canon_ace *ace_entry, bool de
 
 static bool check_pai_ok_v1(const char *pai_buf, size_t pai_buf_data_size)
 {
-       uint16 num_entries;
-       uint16 num_def_entries;
+       uint16_t num_entries;
+       uint16_t num_def_entries;
 
        if (pai_buf_data_size < PAI_V1_ENTRIES_BASE) {
                /* Corrupted - too small. */
@@ -374,8 +370,8 @@ static bool check_pai_ok_v1(const char *pai_buf, size_t pai_buf_data_size)
 
 static bool check_pai_ok_v2(const char *pai_buf, size_t pai_buf_data_size)
 {
-       uint16 num_entries;
-       uint16 num_def_entries;
+       uint16_t num_entries;
+       uint16_t num_def_entries;
 
        if (pai_buf_data_size < PAI_V2_ENTRIES_BASE) {
                /* Corrupted - too small. */
@@ -409,17 +405,20 @@ 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:
@@ -438,7 +437,7 @@ static const char *create_pai_v1_entries(struct pai_val *paiv,
                                const char *entry_offset,
                                bool def_entry)
 {
-       int i;
+       unsigned int i;
 
        for (i = 0; i < paiv->num_entries; i++) {
                struct pai_entry *paie = talloc(talloc_tos(), struct pai_entry);
@@ -630,7 +629,7 @@ static struct pai_val *fload_inherited_info(files_struct *fsp)
                                        pai_buf, pai_buf_size);
                } else {
                        ret = SMB_VFS_GETXATTR(fsp->conn,
-                                              fsp->fsp_name->base_name,
+                                              fsp->fsp_name,
                                               SAMBA_POSIX_INHERITANCE_EA_NAME,
                                               pai_buf, pai_buf_size);
                }
@@ -682,7 +681,7 @@ static struct pai_val *fload_inherited_info(files_struct *fsp)
 ************************************************************************/
 
 static struct pai_val *load_inherited_info(const struct connection_struct *conn,
-                                          const char *fname)
+                                          const struct smb_filename *smb_fname)
 {
        char *pai_buf;
        size_t pai_buf_size = 1024;
@@ -698,7 +697,7 @@ static struct pai_val *load_inherited_info(const struct connection_struct *conn,
        }
 
        do {
-               ret = SMB_VFS_GETXATTR(conn, fname,
+               ret = SMB_VFS_GETXATTR(conn, smb_fname,
                                       SAMBA_POSIX_INHERITANCE_EA_NAME,
                                       pai_buf, pai_buf_size);
 
@@ -717,7 +716,8 @@ static struct pai_val *load_inherited_info(const struct connection_struct *conn,
                }
        } while (ret == -1);
 
-       DEBUG(10,("load_inherited_info: ret = %lu for file %s\n", (unsigned long)ret, fname));
+       DEBUG(10,("load_inherited_info: ret = %lu for file %s\n",
+                       (unsigned long)ret, smb_fname->base_name));
 
        if (ret == -1) {
                /* No attribute or not supported. */
@@ -737,7 +737,7 @@ static struct pai_val *load_inherited_info(const struct connection_struct *conn,
        if (paiv) {
                DEBUG(10,("load_inherited_info: ACL type 0x%x for file %s\n",
                        (unsigned int)paiv->sd_type,
-                       fname));
+                       smb_fname->base_name));
        }
 
        TALLOC_FREE(pai_buf);
@@ -803,11 +803,9 @@ 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 );
+               dbgtext( "uid %u ", (unsigned int)pace->unix_ug.id);
        } 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 );
+               dbgtext( "gid %u ", (unsigned int)pace->unix_ug.id);
        } else
                dbgtext( "other ");
        switch (pace->type) {
@@ -857,13 +855,13 @@ static void print_canon_ace_list(const char *name, canon_ace *ace_list)
  Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
 ****************************************************************************/
 
-static mode_t convert_permset_to_mode_t(connection_struct *conn, SMB_ACL_PERMSET_T permset)
+static mode_t convert_permset_to_mode_t(SMB_ACL_PERMSET_T 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;
 }
@@ -893,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;
@@ -914,14 +912,16 @@ 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, struct dom_sid *powner_sid, struct dom_sid *pgroup_sid)
+static 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 );
 }
 
 /****************************************************************************
- 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.
 ****************************************************************************/
@@ -957,11 +957,11 @@ static void merge_aces( canon_ace **pp_list_head, bool dir_acl)
                         */
 
                        if (!dir_acl) {
-                               can_merge = (dom_sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
+                               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 = (dom_sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
+                               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));
@@ -1011,7 +1011,7 @@ static void merge_aces( canon_ace **pp_list_head, bool dir_acl)
                         * we've put on the ACL, we know the deny must be the first one.
                         */
 
-                       if (dom_sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
+                       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)) {
 
@@ -1059,24 +1059,6 @@ static void merge_aces( canon_ace **pp_list_head, bool dir_acl)
        *pp_list_head = l_head;
 }
 
-/****************************************************************************
- Check if we need to return NT4.x compatible ACL entries.
-****************************************************************************/
-
-bool nt4_compatible_acls(void)
-{
-       int compat = lp_acl_compatibility();
-
-       if (compat == ACL_COMPAT_AUTO) {
-               enum remote_arch_types ra_type = get_remote_arch();
-
-               /* Automatically adapt to client */
-               return (ra_type <= RA_WINNT);
-       } else
-               return (compat == ACL_COMPAT_WINNT);
-}
-
-
 /****************************************************************************
  Map canon_ace perms to permission bits NT.
  The attr element is not used here - we only process deny entries on set,
@@ -1108,10 +1090,7 @@ uint32_t map_canon_ace_perms(int snum,
                 * to be changed in the future.
                 */
 
-               if (nt4_compatible_acls())
-                       nt_mask = UNIX_ACCESS_NONE;
-               else
-                       nt_mask = 0;
+               nt_mask = 0;
        } else {
                if (directory_ace) {
                        nt_mask |= ((perms & S_IRUSR) ? UNIX_DIRECTORY_ACCESS_R : 0 );
@@ -1142,7 +1121,7 @@ uint32_t map_canon_ace_perms(int snum,
 #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)
+static mode_t map_nt_perms( uint32_t *mask, int type)
 {
        mode_t mode = 0;
 
@@ -1185,12 +1164,9 @@ static mode_t map_nt_perms( uint32 *mask, int type)
 
 NTSTATUS unpack_nt_owners(struct connection_struct *conn,
                        uid_t *puser, gid_t *pgrp,
-                       uint32 security_info_sent, const struct
+                       uint32_t security_info_sent, const struct
                        security_descriptor *psd)
 {
-       struct dom_sid owner_sid;
-       struct dom_sid grp_sid;
-
        *puser = (uid_t)-1;
        *pgrp = (gid_t)-1;
 
@@ -1203,9 +1179,6 @@ NTSTATUS unpack_nt_owners(struct connection_struct *conn,
         * Validate the owner and group SID's.
         */
 
-       memset(&owner_sid, '\0', sizeof(owner_sid));
-       memset(&grp_sid, '\0', sizeof(grp_sid));
-
        DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
 
        /*
@@ -1214,8 +1187,7 @@ NTSTATUS unpack_nt_owners(struct connection_struct *conn,
         */
 
        if (security_info_sent & SECINFO_OWNER) {
-               sid_copy(&owner_sid, psd->owner_sid);
-               if (!sid_to_uid(&owner_sid, puser)) {
+               if (!sid_to_uid(psd->owner_sid, puser)) {
                        if (lp_force_unknown_acl_user(SNUM(conn))) {
                                /* this allows take ownership to work
                                 * reasonably */
@@ -1223,7 +1195,7 @@ NTSTATUS unpack_nt_owners(struct connection_struct *conn,
                        } else {
                                DEBUG(3,("unpack_nt_owners: unable to validate"
                                         " owner sid for %s\n",
-                                        sid_string_dbg(&owner_sid)));
+                                        sid_string_dbg(psd->owner_sid)));
                                return NT_STATUS_INVALID_OWNER;
                        }
                }
@@ -1237,8 +1209,7 @@ NTSTATUS unpack_nt_owners(struct connection_struct *conn,
         */
 
        if (security_info_sent & SECINFO_GROUP) {
-               sid_copy(&grp_sid, psd->group_sid);
-               if (!sid_to_gid( &grp_sid, pgrp)) {
+               if (!sid_to_gid(psd->group_sid, pgrp)) {
                        if (lp_force_unknown_acl_user(SNUM(conn))) {
                                /* this allows take group ownership to work
                                 * reasonably */
@@ -1258,48 +1229,19 @@ NTSTATUS unpack_nt_owners(struct connection_struct *conn,
        return NT_STATUS_OK;
 }
 
-/****************************************************************************
- Ensure the enforced permissions for this share apply.
-****************************************************************************/
 
-static void apply_default_perms(const struct share_params *params,
-                               const bool is_directory, canon_ace *pace,
-                               mode_t type)
+static void trim_ace_perms(canon_ace *pace)
 {
-       mode_t and_bits = (mode_t)0;
-       mode_t or_bits = (mode_t)0;
-
-       /* Get the initial bits to apply. */
+       pace->perms = pace->perms & (S_IXUSR|S_IWUSR|S_IRUSR);
+}
 
+static void ensure_minimal_owner_ace_perms(const bool is_directory,
+                                          canon_ace *pace)
+{
+       pace->perms |= S_IRUSR;
        if (is_directory) {
-               and_bits = lp_dir_security_mask(params->service);
-               or_bits = lp_force_dir_security_mode(params->service);
-       } else {
-               and_bits = lp_security_mask(params->service);
-               or_bits = lp_force_security_mode(params->service);
-       }
-
-       /* Now bounce them into the S_USR space. */     
-       switch(type) {
-       case S_IRUSR:
-               /* Ensure owner has read access. */
-               pace->perms |= S_IRUSR;
-               if (is_directory)
-                       pace->perms |= (S_IWUSR|S_IXUSR);
-               and_bits = unix_perms_to_acl_perms(and_bits, S_IRUSR, S_IWUSR, S_IXUSR);
-               or_bits = unix_perms_to_acl_perms(or_bits, S_IRUSR, S_IWUSR, S_IXUSR);
-               break;
-       case S_IRGRP:
-               and_bits = unix_perms_to_acl_perms(and_bits, S_IRGRP, S_IWGRP, S_IXGRP);
-               or_bits = unix_perms_to_acl_perms(or_bits, S_IRGRP, S_IWGRP, S_IXGRP);
-               break;
-       case S_IROTH:
-               and_bits = unix_perms_to_acl_perms(and_bits, S_IROTH, S_IWOTH, S_IXOTH);
-               or_bits = unix_perms_to_acl_perms(or_bits, S_IROTH, S_IWOTH, S_IXOTH);
-               break;
+               pace->perms |= (S_IWUSR|S_IXUSR);
        }
-
-       pace->perms = ((pace->perms & and_bits)|or_bits);
 }
 
 /****************************************************************************
@@ -1309,8 +1251,6 @@ static void apply_default_perms(const struct share_params *params,
 
 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 (dom_sid_equal(&group_ace->trustee, &global_sid_World))
@@ -1320,162 +1260,224 @@ static bool uid_entry_in_group(connection_struct *conn, canon_ace *uid_ace, cano
         * 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 == get_current_uid(conn)) {
+       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 == get_current_gid(conn)) {
+               if (group_ace->unix_ug.id == get_current_gid(conn)) {
                        return True;
                }
 
                curr_utok = get_current_utok(conn);
                for (i=0; i < curr_utok->ngroups; i++) {
-                       if (group_ace->unix_ug.gid == curr_utok->groups[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);
 }
 
 /****************************************************************************
- A well formed POSIX file or default ACL has at least 3 entries, a 
+ A well formed POSIX file or default ACL has at least 3 entries, a
  SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
  In addition, the owner must always have at least read access.
  When using this call on get_acl, the pst struct is valid and contains
- the mode of the file. When using this call on set_acl, the pst struct has
+ the mode of the file.
+****************************************************************************/
+
+static bool ensure_canon_entry_valid_on_get(connection_struct *conn,
+                                       canon_ace **pp_ace,
+                                       const struct dom_sid *pfile_owner_sid,
+                                       const struct dom_sid *pfile_grp_sid,
+                                       const SMB_STRUCT_STAT *pst)
+{
+       canon_ace *pace;
+       bool got_user = false;
+       bool got_group = false;
+       bool got_other = false;
+
+       for (pace = *pp_ace; pace; pace = pace->next) {
+               if (pace->type == SMB_ACL_USER_OBJ) {
+                       got_user = true;
+               } else if (pace->type == SMB_ACL_GROUP_OBJ) {
+                       got_group = true;
+               } else if (pace->type == SMB_ACL_OTHER) {
+                       got_other = true;
+               }
+       }
+
+       if (!got_user) {
+               if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
+                       DEBUG(0,("malloc fail.\n"));
+                       return false;
+               }
+
+               ZERO_STRUCTP(pace);
+               pace->type = SMB_ACL_USER_OBJ;
+               pace->owner_type = UID_ACE;
+               pace->unix_ug.type = ID_TYPE_UID;
+               pace->unix_ug.id = pst->st_ex_uid;
+               pace->trustee = *pfile_owner_sid;
+               pace->attr = ALLOW_ACE;
+               pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRUSR, S_IWUSR, S_IXUSR);
+               DLIST_ADD(*pp_ace, pace);
+       }
+
+       if (!got_group) {
+               if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
+                       DEBUG(0,("malloc fail.\n"));
+                       return false;
+               }
+
+               ZERO_STRUCTP(pace);
+               pace->type = SMB_ACL_GROUP_OBJ;
+               pace->owner_type = GID_ACE;
+               pace->unix_ug.type = ID_TYPE_GID;
+               pace->unix_ug.id = pst->st_ex_gid;
+               pace->trustee = *pfile_grp_sid;
+               pace->attr = ALLOW_ACE;
+               pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRGRP, S_IWGRP, S_IXGRP);
+               DLIST_ADD(*pp_ace, pace);
+       }
+
+       if (!got_other) {
+               if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
+                       DEBUG(0,("malloc fail.\n"));
+                       return false;
+               }
+
+               ZERO_STRUCTP(pace);
+               pace->type = SMB_ACL_OTHER;
+               pace->owner_type = WORLD_ACE;
+               pace->unix_ug.type = ID_TYPE_NOT_SPECIFIED;
+               pace->unix_ug.id = -1;
+               pace->trustee = global_sid_World;
+               pace->attr = ALLOW_ACE;
+               pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IROTH, S_IWOTH, S_IXOTH);
+               DLIST_ADD(*pp_ace, pace);
+       }
+
+       return true;
+}
+
+/****************************************************************************
+ A well formed POSIX file or default ACL has at least 3 entries, a
+ SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
+ In addition, the owner must always have at least read access.
+ When using this call on set_acl, the pst struct has
  been modified to have a mode containing the default for this file or directory
  type.
 ****************************************************************************/
 
-static bool ensure_canon_entry_valid(connection_struct *conn, canon_ace **pp_ace,
-                                    const struct share_params *params,
-                                    const bool is_directory,
-                                                       const struct dom_sid *pfile_owner_sid,
-                                                       const struct dom_sid *pfile_grp_sid,
-                                                       const SMB_STRUCT_STAT *pst,
-                                                       bool setting_acl)
+static bool ensure_canon_entry_valid_on_set(connection_struct *conn,
+                                       canon_ace **pp_ace,
+                                       bool is_default_acl,
+                                       const struct share_params *params,
+                                       const bool is_directory,
+                                       const struct dom_sid *pfile_owner_sid,
+                                       const struct dom_sid *pfile_grp_sid,
+                                       const SMB_STRUCT_STAT *pst)
 {
        canon_ace *pace;
        canon_ace *pace_user = NULL;
        canon_ace *pace_group = NULL;
        canon_ace *pace_other = NULL;
+       bool got_duplicate_user = false;
+       bool got_duplicate_group = false;
 
        for (pace = *pp_ace; pace; pace = pace->next) {
+               trim_ace_perms(pace);
                if (pace->type == SMB_ACL_USER_OBJ) {
-
-                       if (setting_acl)
-                               apply_default_perms(params, is_directory, pace, S_IRUSR);
+                       ensure_minimal_owner_ace_perms(is_directory, pace);
                        pace_user = pace;
-
                } else if (pace->type == SMB_ACL_GROUP_OBJ) {
-
-                       /*
-                        * Ensure create mask/force create mode is respected on set.
-                        */
-
-                       if (setting_acl)
-                               apply_default_perms(params, is_directory, pace, S_IRGRP);
                        pace_group = pace;
-
                } else if (pace->type == SMB_ACL_OTHER) {
-
-                       /*
-                        * Ensure create mask/force create mode is respected on set.
-                        */
-
-                       if (setting_acl)
-                               apply_default_perms(params, is_directory, pace, S_IROTH);
                        pace_other = pace;
                }
        }
 
        if (!pace_user) {
+               canon_ace *pace_iter;
+
                if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
-                       DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
-                       return False;
+                       DEBUG(0,("talloc fail.\n"));
+                       return false;
                }
 
                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
+               /* Start with existing user permissions, principle of least
                   surprises for the user. */
-               pace->perms = pst->st_ex_mode;
+               pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRUSR, S_IWUSR, S_IXUSR);
 
-               if (setting_acl) {
-                       /* See if the owning user is in any of the other groups in
-                          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. */
+               /* See if the owning user is in any of the other groups in
+                  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. */
 
-                       canon_ace *pace_iter;
 
-                       for (pace_iter = *pp_ace; pace_iter; pace_iter = pace_iter->next) {
-                               if (pace_iter->type == SMB_ACL_USER &&
-                                               pace_iter->unix_ug.uid == pace->unix_ug.uid) {
+               for (pace_iter = *pp_ace; pace_iter; pace_iter = pace_iter->next) {
+                       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;
-                               } 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;
-                                       }
                                }
                        }
+               }
 
-                       if (pace->perms == 0) {
-                               /* If we only got an "everyone" perm, just use that. */
-                               if (pace_other)
-                                       pace->perms = pace_other->perms;
-                       }
-
-                       apply_default_perms(params, is_directory, pace, S_IRUSR);
-               } else {
-                       pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRUSR, S_IWUSR, S_IXUSR);
+               if (pace->perms == 0) {
+                       /* If we only got an "everyone" perm, just use that. */
+                       if (pace_other)
+                               pace->perms = pace_other->perms;
                }
 
+               /*
+                * Ensure we have default parameters for the
+                * user (owner) even on default ACLs.
+                */
+               ensure_minimal_owner_ace_perms(is_directory, pace);
+
                DLIST_ADD(*pp_ace, pace);
                pace_user = pace;
        }
 
        if (!pace_group) {
                if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
-                       DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
-                       return False;
+                       DEBUG(0,("talloc fail.\n"));
+                       return false;
                }
 
                ZERO_STRUCTP(pace);
                pace->type = SMB_ACL_GROUP_OBJ;
                pace->owner_type = GID_ACE;
-               pace->unix_ug.gid = 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 (pace_other)
-                               pace->perms = pace_other->perms;
-                       else
-                               pace->perms = 0;
-                       apply_default_perms(params, is_directory, pace, S_IRGRP);
+
+               /* If we only got an "everyone" perm, just use that. */
+               if (pace_other) {
+                       pace->perms = pace_other->perms;
                } else {
-                       pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRGRP, S_IWGRP, S_IXGRP);
+                       pace->perms = 0;
                }
 
                DLIST_ADD(*pp_ace, pace);
@@ -1484,89 +1486,126 @@ static bool ensure_canon_entry_valid(connection_struct *conn, canon_ace **pp_ace
 
        if (!pace_other) {
                if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
-                       DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
-                       return False;
+                       DEBUG(0,("talloc fail.\n"));
+                       return false;
                }
 
                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) {
-                       pace->perms = 0;
-                       apply_default_perms(params, is_directory, pace, S_IROTH);
-               } else
-                       pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IROTH, S_IWOTH, S_IXOTH);
+               pace->perms = 0;
 
                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.uid == pace_user->unix_ug.uid) {
-                               /* Already got one. */
-                               got_duplicate_user = true;
-                       } else if (pace->type == SMB_ACL_GROUP &&
-                                       pace->unix_ug.gid == pace_user->unix_ug.gid) {
-                               /* Already got one. */
-                               got_duplicate_group = true;
-                       }
+       /* 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. */
+
+       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_group->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 (!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;
-                       }
+       /* 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. */
 
-                       ZERO_STRUCTP(pace);
-                       pace->type = SMB_ACL_USER;;
-                       pace->owner_type = UID_ACE;
-                       pace->unix_ug.uid = pace_user->unix_ug.uid;
-                       pace->trustee = pace_user->trustee;
-                       pace->attr = pace_user->attr;
-                       pace->perms = pace_user->perms;
+               if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
+                       DEBUG(0,("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;
+       }
 
-                       DLIST_ADD(*pp_ace, pace);
+       if (!got_duplicate_user) {
+               /* Add a duplicate SMB_ACL_USER entry. */
+               if ((pace = talloc(talloc_tos(), canon_ace)) == NULL) {
+                       DEBUG(0,("talloc fail.\n"));
+                       return false;
                }
 
-               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_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;
 
-                       ZERO_STRUCTP(pace);
-                       pace->type = SMB_ACL_GROUP;;
-                       pace->owner_type = GID_ACE;
-                       pace->unix_ug.gid = pace_group->unix_ug.gid;
-                       pace->trustee = pace_group->trustee;
-                       pace->attr = pace_group->attr;
-                       pace->perms = pace_group->perms;
+               DLIST_ADD(*pp_ace, pace);
 
-                       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,("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;
+       return true;
 }
 
 /****************************************************************************
@@ -1650,7 +1689,7 @@ static bool add_current_ace_to_acl(files_struct *fsp, struct security_ace *psa,
                    (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 *);
+                       DLIST_ADD_END(*dir_ace, current_ace);
 
                        /*
                         * Note if this was an allow ace. We can't process
@@ -1752,7 +1791,7 @@ static bool add_current_ace_to_acl(files_struct *fsp, struct security_ace *psa,
         */
 
        if (current_ace && !(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
-               DLIST_ADD_END(*file_ace, current_ace, canon_ace *);
+               DLIST_ADD_END(*file_ace, current_ace);
 
                /*
                 * Note if this was an allow ace. We can't process
@@ -1762,7 +1801,7 @@ static bool add_current_ace_to_acl(files_struct *fsp, struct security_ace *psa,
                if (current_ace->attr == ALLOW_ACE)
                        *got_file_allow = True;
 
-               if ((current_ace->attr == DENY_ACE) && got_file_allow) {
+               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 "
@@ -1808,7 +1847,7 @@ static bool create_canon_ace_lists(files_struct *fsp,
        canon_ace *current_ace = NULL;
        bool got_dir_allow = False;
        bool got_file_allow = False;
-       int i, j;
+       uint32_t i, j;
 
        *ppfile_ace = NULL;
        *ppdir_ace = NULL;
@@ -1824,26 +1863,6 @@ static bool create_canon_ace_lists(files_struct *fsp,
                        DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
                        return False;
                }
-
-               if (nt4_compatible_acls()) {
-                       /*
-                        * The security mask may be UNIX_ACCESS_NONE which should map into
-                        * no permissions (we overload the WRITE_OWNER bit for this) or it
-                        * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
-                        * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
-                        */
-
-                       /*
-                        * Convert GENERIC bits to specific bits.
-                        */
-                       se_map_generic(&psa->access_mask, &file_generic_mapping);
-
-                       psa->access_mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS);
-
-                       if(psa->access_mask != UNIX_ACCESS_NONE)
-                               psa->access_mask &= ~UNIX_ACCESS_NONE;
-               }
        }
 
        /*
@@ -1911,11 +1930,13 @@ static bool create_canon_ace_lists(files_struct *fsp,
 
                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 (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;
 
                        /*
@@ -1928,7 +1949,8 @@ static bool create_canon_ace_lists(files_struct *fsp,
 
                } 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;
 
                        /*
@@ -1938,53 +1960,130 @@ static bool create_canon_ace_lists(files_struct *fsp,
                         */
                        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)));
+                       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);
-                               continue;
+                               DEBUG(0, ("create_canon_ace_lists: sids_to_unixids "
+                                       "failed for %s (allocation failure)\n",
+                                       sid_string_dbg(&current_ace->trustee)));
+                               return false;
                        }
 
-                       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)));
+                       if (unixid.type == ID_TYPE_BOTH) {
+                               /*
+                                * We must add both a user and group
+                                * entry POSIX_ACL.
+                                * This is due to the fact that in POSIX
+                                * user entries are more specific than
+                                * groups.
+                                */
+                               current_ace->owner_type = UID_ACE;
+                               current_ace->unix_ug.type = ID_TYPE_UID;
+                               current_ace->unix_ug.id = unixid.id;
+                               current_ace->type =
+                                       (unixid.id == pst->st_ex_uid) ?
+                                               SMB_ACL_USER_OBJ :
+                                               SMB_ACL_USER;
+
+                               /* 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 ((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;
+                               }
+
+                               ZERO_STRUCTP(current_ace);
+
+                               sid_copy(&current_ace->trustee, &psa->trustee);
+
+                               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 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 (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;
+                               }
+
+                               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)));
                                TALLOC_FREE(current_ace);
-                               continue;
+                               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)));
-                       TALLOC_FREE(current_ace);
-                       return false;
                }
+
                /* 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,
@@ -2013,7 +2112,7 @@ static bool create_canon_ace_lists(files_struct *fsp,
                 * 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().
+                * ensure_canon_entry_valid_on_set().
                 */
                if (file_ace) {
                        check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);
@@ -2221,7 +2320,7 @@ static void process_deny_list(connection_struct *conn, canon_ace **pp_ace_list )
 
                        curr_ace->attr = ALLOW_ACE;
                        curr_ace->perms = (mode_t)0;
-                       DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
+                       DLIST_DEMOTE(ace_list, curr_ace);
                        continue;
                }
 
@@ -2246,7 +2345,7 @@ static void process_deny_list(connection_struct *conn, canon_ace **pp_ace_list )
 
                curr_ace->attr = ALLOW_ACE;
                curr_ace->perms = (new_perms & ~curr_ace->perms);
-               DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
+               DLIST_DEMOTE(ace_list, curr_ace);
        }
 
        /* Pass 3 above - deal with deny group entries. */
@@ -2293,7 +2392,7 @@ static void process_deny_list(connection_struct *conn, canon_ace **pp_ace_list )
                        curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms;
                else
                        curr_ace->perms = (mode_t)0;
-               DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
+               DLIST_DEMOTE(ace_list, curr_ace);
        }
 
        /* Doing this fourth pass allows Windows semantics to be layered
@@ -2349,7 +2448,7 @@ static bool unpack_canon_ace(files_struct *fsp,
                                struct dom_sid *pfile_grp_sid,
                                canon_ace **ppfile_ace,
                                canon_ace **ppdir_ace,
-                               uint32 security_info_sent,
+                               uint32_t security_info_sent,
                                const struct security_descriptor *psd)
 {
        canon_ace *file_ace = NULL;
@@ -2374,9 +2473,10 @@ static bool unpack_canon_ace(files_struct *fsp,
         * Now go through the DACL and create the canon_ace lists.
         */
 
-       if (!create_canon_ace_lists( fsp, pst, pfile_owner_sid, pfile_grp_sid,
-                                                               &file_ace, &dir_ace, psd->dacl))
+       if (!create_canon_ace_lists(fsp, pst, pfile_owner_sid, pfile_grp_sid,
+                                   &file_ace, &dir_ace, psd->dacl)) {
                return False;
+       }
 
        if ((file_ace == NULL) && (dir_ace == NULL)) {
                /* W2K traverse DACL set - ignore. */
@@ -2415,8 +2515,8 @@ static bool unpack_canon_ace(files_struct *fsp,
 
        print_canon_ace_list( "file ace - before valid", file_ace);
 
-       if (!ensure_canon_entry_valid(fsp->conn, &file_ace, fsp->conn->params,
-                       fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst, True)) {
+       if (!ensure_canon_entry_valid_on_set(fsp->conn, &file_ace, false, fsp->conn->params,
+                       fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst)) {
                free_canon_ace_list(file_ace);
                free_canon_ace_list(dir_ace);
                return False;
@@ -2424,8 +2524,8 @@ static bool unpack_canon_ace(files_struct *fsp,
 
        print_canon_ace_list( "dir ace - before valid", dir_ace);
 
-       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)) {
+       if (dir_ace && !ensure_canon_entry_valid_on_set(fsp->conn, &dir_ace, true, fsp->conn->params,
+                       fsp->is_directory, pfile_owner_sid, pfile_grp_sid, pst)) {
                free_canon_ace_list(file_ace);
                free_canon_ace_list(dir_ace);
                return False;
@@ -2491,7 +2591,7 @@ static void arrange_posix_perms(const char *filename, canon_ace **pp_list_head)
        }
 
        if (other_ace) {
-               DLIST_DEMOTE(l_head, other_ace, canon_ace *);
+               DLIST_DEMOTE(l_head, other_ace);
        }
 
        /* We have probably changed the head of the list. */
@@ -2513,23 +2613,23 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn,
        canon_ace *ace = NULL;
        canon_ace *next_ace = NULL;
        int entry_id = SMB_ACL_FIRST_ENTRY;
+       bool is_default_acl = (the_acl_type == SMB_ACL_TYPE_DEFAULT);
        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;
                struct dom_sid sid;
-               posix_id unix_ug;
+               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. */
@@ -2537,48 +2637,51 @@ 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;
                                        }
                                        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);
                                        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);
                                        break;
                                }
                        case SMB_ACL_MASK:
-                               acl_mask = convert_permset_to_mode_t(conn, permset);
+                               acl_mask = convert_permset_to_mode_t(permset);
                                continue; /* Don't count the mask as an entry. */
                        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:
@@ -2593,14 +2696,15 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn,
                if ((ace = talloc(talloc_tos(), canon_ace)) == NULL)
                        goto fail;
 
-               ZERO_STRUCTP(ace);
-               ace->type = tagtype;
-               ace->perms = convert_permset_to_mode_t(conn, permset);
-               ace->attr = ALLOW_ACE;
-               ace->trustee = sid;
-               ace->unix_ug = unix_ug;
-               ace->owner_type = owner_type;
-               ace->ace_flags = get_pai_flags(pal, ace, (the_acl_type == SMB_ACL_TYPE_DEFAULT));
+               *ace = (canon_ace) {
+                       .type = tagtype,
+                       .perms = convert_permset_to_mode_t(permset),
+                       .attr = ALLOW_ACE,
+                       .trustee = sid,
+                       .unix_ug = unix_ug,
+                       .owner_type = owner_type
+               };
+               ace->ace_flags = get_pai_flags(pal, ace, is_default_acl);
 
                DLIST_ADD(l_head, ace);
        }
@@ -2609,9 +2713,9 @@ 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(conn, &l_head, conn->params,
-                                     S_ISDIR(psbuf->st_ex_mode), powner, pgroup,
-                                     psbuf, False))
+       if (!ensure_canon_entry_valid_on_get(conn, &l_head,
+                                     powner, pgroup,
+                                     psbuf))
                goto fail;
 
        /*
@@ -2619,7 +2723,7 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn,
         * acl_mask. Ensure all DENY Entries are at the start of the list.
         */
 
-       DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", the_acl_type == SMB_ACL_TYPE_ACCESS ? "Access" : "Default" ));
+       DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", is_default_acl ?  "Default" : "Access"));
 
        for ( ace_count = 0, ace = l_head; ace; ace = next_ace, ace_count++) {
                next_ace = ace->next;
@@ -2655,7 +2759,7 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn,
 
 bool current_user_in_group(connection_struct *conn, gid_t gid)
 {
-       int i;
+       uint32_t i;
        const struct security_unix_token *utok = get_current_utok(conn);
 
        for (i = 0; i < utok->ngroups; i++) {
@@ -2705,7 +2809,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(talloc_tos());
        canon_ace *p_ace;
        int i;
        SMB_ACL_ENTRY_T mask_entry;
@@ -2726,17 +2830,8 @@ static bool set_canon_ace_list(files_struct *fsp,
 #endif
 
        if (the_acl == NULL) {
-
-               if (!no_acl_syscall_error(errno)) {
-                       /*
-                        * Only print this error message if we have some kind of ACL
-                        * support that's not working. Otherwise we would always get this.
-                        */
-                       DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
-                               default_ace ? "default" : "file", strerror(errno) ));
-               }
-               *pacl_set_support = False;
-               goto fail;
+               DEBUG(0, ("sys_acl_init failed to allocate an ACL\n"));
+               return false;
        }
 
        if( DEBUGLVL( 10 )) {
@@ -2768,7 +2863,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;
@@ -2794,7 +2889,7 @@ static bool set_canon_ace_list(files_struct *fsp,
                 * First tell the entry what type of ACE this is.
                 */
 
-               if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, p_ace->type) == -1) {
+               if (sys_acl_set_tag_type(the_entry, p_ace->type) == -1) {
                        DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
                                i, strerror(errno) ));
                        goto fail;
@@ -2806,7 +2901,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 (sys_acl_set_qualifier(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;
@@ -2817,7 +2912,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;
@@ -2833,7 +2928,7 @@ static bool set_canon_ace_list(files_struct *fsp,
                 * ..and apply them to the entry.
                 */
 
-               if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
+               if (sys_acl_set_permset(the_entry, the_permset) == -1) {
                        DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
                                i, strerror(errno) ));
                        goto fail;
@@ -2845,17 +2940,17 @@ 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;
                }
 
-               if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, mask_entry, SMB_ACL_MASK) == -1) {
+               if (sys_acl_set_tag_type(mask_entry, SMB_ACL_MASK) == -1) {
                        DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
                        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;
                }
@@ -2865,7 +2960,7 @@ static bool set_canon_ace_list(files_struct *fsp,
                        goto fail;
                }
 
-               if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, mask_entry, mask_permset) == -1) {
+               if (sys_acl_set_permset(mask_entry, mask_permset) == -1) {
                        DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
                        goto fail;
                }
@@ -2876,7 +2971,7 @@ static bool set_canon_ace_list(files_struct *fsp,
         */
 
        if(default_ace || fsp->is_directory || fsp->fh->fd == -1) {
-               if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name->base_name,
+               if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name,
                                             the_acl_type, the_acl) == -1) {
                        /*
                         * Some systems allow all the above calls and only fail with no ACL support
@@ -2896,7 +2991,7 @@ static bool set_canon_ace_list(files_struct *fsp,
 
                                become_root();
                                sret = SMB_VFS_SYS_ACL_SET_FILE(conn,
-                                   fsp->fsp_name->base_name, the_acl_type,
+                                   fsp->fsp_name, the_acl_type,
                                    the_acl);
                                unbecome_root();
                                if (sret == 0) {
@@ -2955,28 +3050,12 @@ static bool set_canon_ace_list(files_struct *fsp,
   fail:
 
        if (the_acl != NULL) {
-               SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
+               TALLOC_FREE(the_acl);
        }
 
        return ret;
 }
 
-/****************************************************************************
- 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)
-{
-       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)))
-                       break;
-               list = list->next;
-       }
-       return list;
-}
-
 /****************************************************************************
  
 ****************************************************************************/
@@ -2987,8 +3066,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) {
+               TALLOC_FREE(the_acl);
                return NULL;
        }
        return the_acl;
@@ -3002,16 +3081,13 @@ SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl)
 
 static bool convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
 {
-       int snum = SNUM(fsp->conn);
        size_t ace_count = count_canon_ace_list(file_ace_list);
        canon_ace *ace_p;
        canon_ace *owner_ace = NULL;
        canon_ace *group_ace = NULL;
        canon_ace *other_ace = NULL;
-       mode_t and_bits;
-       mode_t or_bits;
 
-       if (ace_count != 3) {
+       if (ace_count > 5) {
                DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE "
                         "entries for file %s to convert to posix perms.\n",
                         fsp_str_dbg(fsp)));
@@ -3033,6 +3109,43 @@ static bool convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file
                return False;
        }
 
+       /*
+        * Ensure all ACE entries are owner, group or other.
+        * We can't set if there are any other SIDs.
+        */
+       for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
+               if (ace_p == owner_ace || ace_p == group_ace ||
+                               ace_p == other_ace) {
+                       continue;
+               }
+               if (ace_p->owner_type == UID_ACE) {
+                       if (ace_p->unix_ug.id != owner_ace->unix_ug.id) {
+                               DEBUG(3,("Invalid uid %u in ACE for file %s.\n",
+                                       (unsigned int)ace_p->unix_ug.id,
+                                       fsp_str_dbg(fsp)));
+                               return false;
+                       }
+               } else if (ace_p->owner_type == GID_ACE) {
+                       if (ace_p->unix_ug.id != group_ace->unix_ug.id) {
+                               DEBUG(3,("Invalid gid %u in ACE for file %s.\n",
+                                       (unsigned int)ace_p->unix_ug.id,
+                                       fsp_str_dbg(fsp)));
+                               return false;
+                       }
+               } else {
+                       /*
+                        * There should be no duplicate WORLD_ACE entries.
+                        */
+
+                       DEBUG(3,("Invalid type %u, uid %u in "
+                               "ACE for file %s.\n",
+                               (unsigned int)ace_p->owner_type,
+                               (unsigned int)ace_p->unix_ug.id,
+                               fsp_str_dbg(fsp)));
+                       return false;
+               }
+       }
+
        *posix_perms = (mode_t)0;
 
        *posix_perms |= owner_ace->perms;
@@ -3049,20 +3162,6 @@ static bool convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file
        if (fsp->is_directory)
                *posix_perms |= (S_IWUSR|S_IXUSR);
 
-       /* If requested apply the masks. */
-
-       /* Get the initial bits to apply. */
-
-       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);
-       }
-
-       *posix_perms = (((*posix_perms) & and_bits)|or_bits);
-
        DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o "
                  "to perm=0%o for file %s.\n", (int)owner_ace->perms,
                  (int)group_ace->perms, (int)other_ace->perms,
@@ -3084,8 +3183,8 @@ static size_t merge_default_aces( struct security_ace *nt_ace_list, size_t num_a
 
        for (i = 0; i < num_aces; i++) {
                for (j = i+1; j < num_aces; j++) {
-                       uint32 i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
-                       uint32 j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
+                       uint32_t i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
+                       uint32_t j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
                        bool i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
                        bool j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
 
@@ -3153,7 +3252,7 @@ static void add_or_replace_ace(struct security_ace *nt_ace_list, size_t *num_ace
                                const struct dom_sid *sid, enum security_ace_type type,
                                uint32_t mask, uint8_t flags)
 {
-       int i;
+       size_t i;
 
        /* first search for a duplicate */
        for (i = 0; i < *num_aces; i++) {
@@ -3164,7 +3263,7 @@ static void add_or_replace_ace(struct security_ace *nt_ace_list, size_t *num_ace
        if (i < *num_aces) { /* found */
                nt_ace_list[i].type = type;
                nt_ace_list[i].access_mask = mask;
-               DEBUG(10, ("Replacing ACE %d with SID %s and flags %02x\n",
+               DEBUG(10, ("Replacing ACE %zu with SID %s and flags %02x\n",
                           i, sid_string_dbg(sid), flags));
                return;
        }
@@ -3188,6 +3287,7 @@ 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,
+                                     TALLOC_CTX *mem_ctx,
                                      struct security_descriptor **ppdesc)
 {
        struct dom_sid owner_sid;
@@ -3203,7 +3303,6 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
        size_t num_profile_acls = 0;
        struct dom_sid orig_owner_sid;
        struct security_descriptor *psd = NULL;
-       int i;
 
        /*
         * Get the owner, group and world SIDs.
@@ -3219,7 +3318,7 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
                num_profile_acls = 3;
        }
 
-       if ((security_info & SECINFO_DACL) && !(security_info & SECINFO_PROTECTED_DACL)) {
+       if (security_info & SECINFO_DACL) {
 
                /*
                 * In the optimum case Creator Owner and Creator Group would be used for
@@ -3227,7 +3326,7 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
                 * would lead to usability problems under Windows: The Creator entries
                 * are only available in browse lists of directories and not for files;
                 * additionally the identity of the owning group couldn't be determined.
-                * We therefore use those identities only for Default ACLs. 
+                * We therefore use those identities only for Default ACLs.
                 */
 
                /* Create the canon_ace lists. */
@@ -3236,7 +3335,7 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
                                            SMB_ACL_TYPE_ACCESS);
 
                /* We must have *some* ACLS. */
-       
+
                if (count_canon_ace_list(file_ace) == 0) {
                        DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", name));
                        goto done;
@@ -3258,66 +3357,18 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
                        canon_ace *ace;
                        enum security_ace_type nt_acl_type;
 
-                       if (nt4_compatible_acls() && dir_ace) {
-                               /*
-                                * NT 4 chokes if an ACL contains an INHERIT_ONLY entry
-                                * but no non-INHERIT_ONLY entry for one SID. So we only
-                                * remove entries from the Access ACL if the
-                                * corresponding Default ACL entries have also been
-                                * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP
-                                * are exceptions. We can do nothing
-                                * intelligent if the Default ACL contains entries that
-                                * are not also contained in the Access ACL, so this
-                                * case will still fail under NT 4.
-                                */
-
-                               ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL);
-                               if (ace && !ace->perms) {
-                                       DLIST_REMOVE(dir_ace, ace);
-                                       TALLOC_FREE(ace);
-
-                                       ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL);
-                                       if (ace && !ace->perms) {
-                                               DLIST_REMOVE(file_ace, ace);
-                                               TALLOC_FREE(ace);
-                                       }
-                               }
-
-                               /*
-                                * WinNT doesn't usually have Creator Group
-                                * in browse lists, so we send this entry to
-                                * WinNT even if it contains no relevant
-                                * permissions. Once we can add
-                                * Creator Group to browse lists we can
-                                * re-enable this.
-                                */
-
-#if 0
-                               ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL);
-                               if (ace && !ace->perms) {
-                                       DLIST_REMOVE(dir_ace, 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);
-                                       TALLOC_FREE(ace);
-                               }
-                       }
-
                        num_acls = count_canon_ace_list(file_ace);
                        num_def_acls = count_canon_ace_list(dir_ace);
 
-                       /* Allocate the ace list. */
-                       if ((nt_ace_list = talloc_array(talloc_tos(), struct security_ace,num_acls + num_profile_acls + num_def_acls)) == NULL) {
+                       nt_ace_list = talloc_zero_array(
+                               talloc_tos(), struct security_ace,
+                               num_acls + num_profile_acls + num_def_acls);
+
+                       if (nt_ace_list == 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(struct security_ace) );
-
                        /*
                         * Create the NT ACE list from the canonical ace lists.
                         */
@@ -3379,6 +3430,8 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
                        num_aces = merge_default_aces(nt_ace_list, num_aces);
 
                        if (lp_profile_acls(SNUM(conn))) {
+                               size_t i;
+
                                for (i = 0; i < num_aces; i++) {
                                        if (dom_sid_equal(&nt_ace_list[i].trustee, &owner_sid)) {
                                                add_or_replace_ace(nt_ace_list, &num_aces,
@@ -3400,7 +3453,7 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
                }
        } /* security_info & SECINFO_DACL */
 
-       psd = make_standard_sec_desc( talloc_tos(),
+       psd = make_standard_sec_desc(mem_ctx,
                        (security_info & SECINFO_OWNER) ? &owner_sid : NULL,
                        (security_info & SECINFO_GROUP) ? &group_sid : NULL,
                        psa,
@@ -3437,10 +3490,10 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
  done:
 
        if (posix_acl) {
-               SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
+               TALLOC_FREE(posix_acl);
        }
        if (def_acl) {
-               SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+               TALLOC_FREE(def_acl);
        }
        free_canon_ace_list(file_ace);
        free_canon_ace_list(dir_ace);
@@ -3451,11 +3504,14 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
 }
 
 NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info,
+                          TALLOC_CTX *mem_ctx,
                           struct security_descriptor **ppdesc)
 {
        SMB_STRUCT_STAT sbuf;
        SMB_ACL_T posix_acl = NULL;
        struct pai_val *pal;
+       TALLOC_CTX *frame = talloc_stackframe();
+       NTSTATUS status;
 
        *ppdesc = NULL;
 
@@ -3464,66 +3520,93 @@ NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info,
 
        /* can it happen that fsp_name == NULL ? */
        if (fsp->is_directory ||  fsp->fh->fd == -1) {
-               return posix_get_nt_acl(fsp->conn, fsp->fsp_name->base_name,
-                                       security_info, ppdesc);
+               status = posix_get_nt_acl(fsp->conn, fsp->fsp_name,
+                                         security_info, mem_ctx, ppdesc);
+               TALLOC_FREE(frame);
+               return status;
        }
 
        /* Get the stat struct for the owner info. */
        if(SMB_VFS_FSTAT(fsp, &sbuf) != 0) {
+               TALLOC_FREE(frame);
                return map_nt_error_from_unix(errno);
        }
 
        /* Get the ACL from the fd. */
-       posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp);
+       posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, frame);
 
        pal = fload_inherited_info(fsp);
 
-       return posix_get_nt_acl_common(fsp->conn, fsp->fsp_name->base_name,
-                                      &sbuf, pal, posix_acl, NULL,
-                                      security_info, ppdesc);
+       status = posix_get_nt_acl_common(fsp->conn, fsp->fsp_name->base_name,
+                                        &sbuf, pal, posix_acl, NULL,
+                                        security_info, mem_ctx, ppdesc);
+       TALLOC_FREE(frame);
+       return status;
 }
 
-NTSTATUS posix_get_nt_acl(struct connection_struct *conn, const char *name,
-                         uint32_t security_info, struct security_descriptor **ppdesc)
+NTSTATUS posix_get_nt_acl(struct connection_struct *conn,
+                       const struct smb_filename *smb_fname_in,
+                       uint32_t security_info,
+                       TALLOC_CTX *mem_ctx,
+                       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;
+       struct smb_filename *smb_fname = NULL;
        int ret;
+       TALLOC_CTX *frame = talloc_stackframe();
+       NTSTATUS status;
 
        *ppdesc = NULL;
 
-       DEBUG(10,("posix_get_nt_acl: called for file %s\n", name ));
+       DEBUG(10,("posix_get_nt_acl: called for file %s\n",
+               smb_fname_in->base_name ));
 
-       ZERO_STRUCT(smb_fname);
-       smb_fname.base_name = discard_const_p(char, name);
+       smb_fname = cp_smb_filename(talloc_tos(), smb_fname_in);
+       if (smb_fname == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
+       }
 
        /* Get the stat struct for the owner info. */
-       if (lp_posix_pathnames()) {
-               ret = SMB_VFS_LSTAT(conn, &smb_fname);
-       } else {
-               ret = SMB_VFS_STAT(conn, &smb_fname);
-       }
+       /*
+        * We can directly use SMB_VFS_STAT here, as if this was a
+        * POSIX call on a symlink, we've already refused it.
+        * For a Windows acl mapped call on a symlink, we want to follow
+        * it.
+        */
+       ret = SMB_VFS_STAT(conn, smb_fname);
 
        if (ret == -1) {
+               TALLOC_FREE(frame);
                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);
+       posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, smb_fname,
+                                            SMB_ACL_TYPE_ACCESS, frame);
 
        /* If it's a directory get the default POSIX ACL. */
-       if(S_ISDIR(smb_fname.st.st_ex_mode)) {
-               def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, name, SMB_ACL_TYPE_DEFAULT);
+       if(S_ISDIR(smb_fname->st.st_ex_mode)) {
+               def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, smb_fname,
+                                                  SMB_ACL_TYPE_DEFAULT, frame);
                def_acl = free_empty_sys_acl(conn, def_acl);
        }
 
-       pal = load_inherited_info(conn, name);
+       pal = load_inherited_info(conn, smb_fname);
 
-       return posix_get_nt_acl_common(conn, name, &smb_fname.st, pal,
-                                      posix_acl, def_acl, security_info,
-                                      ppdesc);
+       status = posix_get_nt_acl_common(conn,
+                                       smb_fname->base_name,
+                                       &smb_fname->st,
+                                       pal,
+                                       posix_acl,
+                                       def_acl,
+                                       security_info,
+                                       mem_ctx,
+                                       ppdesc);
+       TALLOC_FREE(frame);
+       return status;
 }
 
 /****************************************************************************
@@ -3599,207 +3682,6 @@ NTSTATUS try_chown(files_struct *fsp, uid_t uid, gid_t gid)
        return status;
 }
 
-#if 0
-/* Disable this - prevents ACL inheritance from the ACL editor. JRA. */
-
-/****************************************************************************
- Take care of parent ACL inheritance.
-****************************************************************************/
-
-NTSTATUS append_parent_acl(files_struct *fsp,
-                               const struct security_descriptor *pcsd,
-                               struct security_descriptor **pp_new_sd)
-{
-       struct smb_filename *smb_dname = NULL;
-       struct security_descriptor *parent_sd = NULL;
-       files_struct *parent_fsp = NULL;
-       TALLOC_CTX *mem_ctx = talloc_tos();
-       char *parent_name = NULL;
-       struct security_ace *new_ace = NULL;
-       unsigned int num_aces = pcsd->dacl->num_aces;
-       NTSTATUS status;
-       int info;
-       unsigned int i, j;
-       struct security_descriptor *psd = dup_sec_desc(talloc_tos(), pcsd);
-       bool is_dacl_protected = (pcsd->type & SEC_DESC_DACL_PROTECTED);
-
-       if (psd == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       if (!parent_dirname(mem_ctx, fsp->fsp_name->base_name, &parent_name,
-                           NULL)) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       status = create_synthetic_smb_fname(mem_ctx, parent_name, NULL, NULL,
-                                           &smb_dname);
-       if (!NT_STATUS_IS_OK(status)) {
-               goto fail;
-       }
-
-       status = SMB_VFS_CREATE_FILE(
-               fsp->conn,                              /* conn */
-               NULL,                                   /* req */
-               0,                                      /* root_dir_fid */
-               smb_dname,                              /* fname */
-               FILE_READ_ATTRIBUTES,                   /* access_mask */
-               FILE_SHARE_NONE,                        /* share_access */
-               FILE_OPEN,                              /* create_disposition*/
-               FILE_DIRECTORY_FILE,                    /* create_options */
-               0,                                      /* file_attributes */
-               INTERNAL_OPEN_ONLY,                     /* oplock_request */
-               0,                                      /* allocation_size */
-               NULL,                                   /* sd */
-               NULL,                                   /* ea_list */
-               &parent_fsp,                            /* result */
-               &info);                                 /* pinfo */
-
-       if (!NT_STATUS_IS_OK(status)) {
-               TALLOC_FREE(smb_dname);
-               return status;
-       }
-
-       status = SMB_VFS_GET_NT_ACL(parent_fsp->conn, smb_dname->base_name,
-                                   SECINFO_DACL, &parent_sd );
-
-       close_file(NULL, parent_fsp, NORMAL_CLOSE);
-       TALLOC_FREE(smb_dname);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
-       /*
-        * Make room for potentially all the ACLs from
-        * the parent. We used to add the ugw triple here,
-        * as we knew we were dealing with POSIX ACLs.
-        * We no longer need to do so as we can guarentee
-        * that a default ACL from the parent directory will
-        * be well formed for POSIX ACLs if it came from a
-        * POSIX ACL source, and if we're not writing to a
-        * POSIX ACL sink then we don't care if it's not well
-        * formed. JRA.
-        */
-
-       num_aces += parent_sd->dacl->num_aces;
-
-       if((new_ace = talloc_zero_array(mem_ctx, struct security_ace,
-                                       num_aces)) == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       /* Start by copying in all the given ACE entries. */
-       for (i = 0; i < psd->dacl->num_aces; i++) {
-               sec_ace_copy(&new_ace[i], &psd->dacl->aces[i]);
-       }
-
-       /*
-        * Note that we're ignoring "inherit permissions" here
-        * as that really only applies to newly created files. JRA.
-        */
-
-       /* Finally append any inherited ACEs. */
-       for (j = 0; j < parent_sd->dacl->num_aces; j++) {
-               struct security_ace *se = &parent_sd->dacl->aces[j];
-
-               if (fsp->is_directory) {
-                       if (!(se->flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
-                               /* Doesn't apply to a directory - ignore. */
-                               DEBUG(10,("append_parent_acl: directory %s "
-                                       "ignoring non container "
-                                       "inherit flags %u on ACE with sid %s "
-                                       "from parent %s\n",
-                                       fsp_str_dbg(fsp),
-                                       (unsigned int)se->flags,
-                                       sid_string_dbg(&se->trustee),
-                                       parent_name));
-                               continue;
-                       }
-               } else {
-                       if (!(se->flags & SEC_ACE_FLAG_OBJECT_INHERIT)) {
-                               /* Doesn't apply to a file - ignore. */
-                               DEBUG(10,("append_parent_acl: file %s "
-                                       "ignoring non object "
-                                       "inherit flags %u on ACE with sid %s "
-                                       "from parent %s\n",
-                                       fsp_str_dbg(fsp),
-                                       (unsigned int)se->flags,
-                                       sid_string_dbg(&se->trustee),
-                                       parent_name));
-                               continue;
-                       }
-               }
-
-               if (is_dacl_protected) {
-                       /* If the DACL is protected it means we must
-                        * not overwrite an existing ACE entry with the
-                        * same SID. This is order N^2. Ouch :-(. JRA. */
-                       unsigned int k;
-                       for (k = 0; k < psd->dacl->num_aces; k++) {
-                               if (dom_sid_equal(&psd->dacl->aces[k].trustee,
-                                               &se->trustee)) {
-                                       break;
-                               }
-                       }
-                       if (k < psd->dacl->num_aces) {
-                               /* SID matched. Ignore. */
-                               DEBUG(10,("append_parent_acl: path %s "
-                                       "ignoring ACE with protected sid %s "
-                                       "from parent %s\n",
-                                       fsp_str_dbg(fsp),
-                                       sid_string_dbg(&se->trustee),
-                                       parent_name));
-                               continue;
-                       }
-               }
-
-               sec_ace_copy(&new_ace[i], se);
-               if (se->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
-                       new_ace[i].flags &= ~(SEC_ACE_FLAG_VALID_INHERIT);
-               }
-               new_ace[i].flags |= SEC_ACE_FLAG_INHERITED_ACE;
-
-               if (fsp->is_directory) {
-                       /*
-                        * Strip off any inherit only. It's applied.
-                        */
-                       new_ace[i].flags &= ~(SEC_ACE_FLAG_INHERIT_ONLY);
-                       if (se->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
-                               /* No further inheritance. */
-                               new_ace[i].flags &=
-                                       ~(SEC_ACE_FLAG_CONTAINER_INHERIT|
-                                       SEC_ACE_FLAG_OBJECT_INHERIT);
-                       }
-               } else {
-                       /*
-                        * Strip off any container or inherit
-                        * flags, they can't apply to objects.
-                        */
-                       new_ace[i].flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|
-                                               SEC_ACE_FLAG_INHERIT_ONLY|
-                                               SEC_ACE_FLAG_NO_PROPAGATE_INHERIT);
-               }
-               i++;
-
-               DEBUG(10,("append_parent_acl: path %s "
-                       "inheriting ACE with sid %s "
-                       "from parent %s\n",
-                       fsp_str_dbg(fsp),
-                       sid_string_dbg(&se->trustee),
-                       parent_name));
-       }
-
-       psd->dacl->aces = new_ace;
-       psd->dacl->num_aces = i;
-       psd->type &= ~(SEC_DESC_DACL_AUTO_INHERITED|
-                         SEC_DESC_DACL_AUTO_INHERIT_REQ);
-
-       *pp_new_sd = psd;
-       return status;
-}
-#endif
-
 /****************************************************************************
  Reply to set a security descriptor on an fsp. security_info_sent is the
  description of the following NT ACL.
@@ -3808,7 +3690,7 @@ NTSTATUS append_parent_acl(files_struct *fsp,
  it, even though it's a const pointer.
 ****************************************************************************/
 
-NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd_orig)
+NTSTATUS set_nt_acl(files_struct *fsp, uint32_t security_info_sent, const struct security_descriptor *psd_orig)
 {
        connection_struct *conn = fsp->conn;
        uid_t user = (uid_t)-1;
@@ -3833,12 +3715,22 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct s
                return NT_STATUS_MEDIA_WRITE_PROTECTED;
        }
 
-       if (!psd_orig) {
+       if (psd_orig == NULL) {
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       psd = dup_sec_desc(talloc_tos(), psd_orig);
-       if (!psd) {
+       /*
+        * MS NFS mode, here's the deal: the client merely wants to
+        * modify the mode, but roundtripping get_acl/set/acl would
+        * add additional POSIX ACEs.  So in case we get a request
+        * containing a MS NFS mode SID, we do nothing here.
+        */
+       if (security_descriptor_with_ms_nfs(psd_orig)) {
+               return NT_STATUS_OK;
+       }
+
+       psd = security_descriptor_copy(talloc_tos(), psd_orig);
+       if (psd == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
@@ -3866,6 +3758,14 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct s
                security_info_sent &= ~SECINFO_GROUP;
        }
 
+       /* If UNIX owner is inherited and Windows isn't, then
+        * setting the UNIX owner based on Windows owner conflicts
+        * with the inheritance rule
+        */
+       if (lp_inherit_owner(SNUM(conn)) == INHERIT_OWNER_UNIX_ONLY) {
+               security_info_sent &= ~SECINFO_OWNER;
+       }
+
        status = unpack_nt_owners( conn, &user, &grp, security_info_sent, psd);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -4028,7 +3928,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct s
                                become_root();
                        }
                        sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn,
-                           fsp->fsp_name->base_name);
+                           fsp->fsp_name);
                        if (set_acl_as_root) {
                                unbecome_root();
                        }
@@ -4044,7 +3944,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct s
                                        sret =
                                            SMB_VFS_SYS_ACL_DELETE_DEF_FILE(
                                                    conn,
-                                                   fsp->fsp_name->base_name);
+                                                   fsp->fsp_name);
                                        unbecome_root();
                                }
 
@@ -4096,7 +3996,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct s
                        if (set_acl_as_root) {
                                become_root();
                        }
-                       sret = SMB_VFS_CHMOD(conn, fsp->fsp_name->base_name,
+                       sret = SMB_VFS_CHMOD(conn, fsp->fsp_name,
                                             posix_perms);
                        if (set_acl_as_root) {
                                unbecome_root();
@@ -4111,7 +4011,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct s
 
                                        become_root();
                                        sret = SMB_VFS_CHMOD(conn,
-                                           fsp->fsp_name->base_name,
+                                           fsp->fsp_name,
                                            posix_perms);
                                        unbecome_root();
                                }
@@ -4145,40 +4045,43 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct s
  the mask bits, not the real group bits, for a file with an ACL.
 ****************************************************************************/
 
-int get_acl_group_bits( connection_struct *conn, const char *fname, mode_t *mode )
+int get_acl_group_bits( connection_struct *conn,
+                       const struct smb_filename *smb_fname,
+                       mode_t *mode )
 {
        int entry_id = SMB_ACL_FIRST_ENTRY;
        SMB_ACL_ENTRY_T entry;
        SMB_ACL_T posix_acl;
        int result = -1;
 
-       posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS);
+       posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, smb_fname,
+                                            SMB_ACL_TYPE_ACCESS, talloc_tos());
        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);
+       TALLOC_FREE(posix_acl);
        return result;
 }
 
@@ -4193,17 +4096,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++;
@@ -4234,7 +4137,7 @@ static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mo
                if (map_acl_perms_to_permset(conn, perms, &permset) == -1)
                        return -1;
 
-               if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) == -1)
+               if (sys_acl_set_permset(entry, permset) == -1)
                        return -1;
        }
 
@@ -4255,22 +4158,28 @@ static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mo
  resulting ACL on TO.  Note that name is in UNIX character set.
 ****************************************************************************/
 
-static int copy_access_posix_acl(connection_struct *conn, const char *from, const char *to, mode_t mode)
+static int copy_access_posix_acl(connection_struct *conn,
+                               const struct smb_filename *smb_fname_from,
+                               const struct smb_filename *smb_fname_to,
+                               mode_t mode)
 {
        SMB_ACL_T posix_acl = NULL;
        int ret = -1;
 
-       if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL)
+       if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, smb_fname_from,
+                                                 SMB_ACL_TYPE_ACCESS,
+                                                 talloc_tos())) == NULL)
                return -1;
 
        if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
                goto done;
 
-       ret = SMB_VFS_SYS_ACL_SET_FILE(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl);
+       ret = SMB_VFS_SYS_ACL_SET_FILE(conn, smb_fname_to,
+                       SMB_ACL_TYPE_ACCESS, posix_acl);
 
  done:
 
-       SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
+       TALLOC_FREE(posix_acl);
        return ret;
 }
 
@@ -4280,27 +4189,32 @@ static int copy_access_posix_acl(connection_struct *conn, const char *from, cons
  Note that name is in UNIX character set.
 ****************************************************************************/
 
-int chmod_acl(connection_struct *conn, const char *name, mode_t mode)
+int chmod_acl(connection_struct *conn,
+                       const struct smb_filename *smb_fname,
+                       mode_t mode)
 {
-       return copy_access_posix_acl(conn, name, name, mode);
+       return copy_access_posix_acl(conn, smb_fname, smb_fname, mode);
 }
 
 /****************************************************************************
  Check for an existing default POSIX ACL on a directory.
 ****************************************************************************/
 
-static bool directory_has_default_posix_acl(connection_struct *conn, const char *fname)
+static bool directory_has_default_posix_acl(connection_struct *conn,
+                       const struct smb_filename *smb_fname)
 {
-       SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT);
+       SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, smb_fname,
+                                                    SMB_ACL_TYPE_DEFAULT,
+                                                    talloc_tos());
        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);
+               TALLOC_FREE(def_acl);
        }
         return has_acl;
 }
@@ -4310,13 +4224,25 @@ static bool directory_has_default_posix_acl(connection_struct *conn, const char
  inherit this Access ACL to file name.
 ****************************************************************************/
 
-int inherit_access_posix_acl(connection_struct *conn, const char *inherit_from_dir,
-                      const char *name, mode_t mode)
+int inherit_access_posix_acl(connection_struct *conn,
+                       const char *inherit_from_dir,
+                       const struct smb_filename *smb_fname,
+                       mode_t mode)
 {
-       if (directory_has_default_posix_acl(conn, inherit_from_dir))
+       struct smb_filename *inherit_from_fname =
+                       synthetic_smb_fname(talloc_tos(),
+                               smb_fname->base_name,
+                               NULL,
+                               NULL,
+                               smb_fname->flags);
+       if (inherit_from_fname == NULL) {
+               return-1;
+       }
+
+       if (directory_has_default_posix_acl(conn, inherit_from_fname))
                return 0;
 
-       return copy_access_posix_acl(conn, inherit_from_dir, name, mode);
+       return copy_access_posix_acl(conn, inherit_from_fname, smb_fname, mode);
 }
 
 /****************************************************************************
@@ -4330,7 +4256,7 @@ int fchmod_acl(files_struct *fsp, mode_t mode)
        SMB_ACL_T posix_acl = NULL;
        int ret = -1;
 
-       if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp)) == NULL)
+       if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, talloc_tos())) == NULL)
                return -1;
 
        if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
@@ -4340,7 +4266,7 @@ int fchmod_acl(files_struct *fsp, mode_t mode)
 
   done:
 
-       SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
+       TALLOC_FREE(posix_acl);
        return ret;
 }
 
@@ -4354,22 +4280,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;
                }
        }
@@ -4412,10 +4338,13 @@ static bool unix_ex_wire_to_tagtype(unsigned char wire_tt, SMB_ACL_TAG_T *p_tt)
  FIXME ! How does the share mask/mode fit into this.... ?
 ****************************************************************************/
 
-static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_acls, const char *pdata)
+static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn,
+                                           uint16_t num_acls,
+                                           const char *pdata,
+                                           TALLOC_CTX *mem_ctx)
 {
        unsigned int i;
-       SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, num_acls);
+       SMB_ACL_T the_acl = sys_acl_init(mem_ctx);
 
        if (the_acl == NULL) {
                return NULL;
@@ -4426,7 +4355,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;
@@ -4438,14 +4367,14 @@ static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_
                        goto fail;
                }
 
-               if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, tag_type) == -1) {
+               if (sys_acl_set_tag_type(the_entry, tag_type) == -1) {
                        DEBUG(0,("create_posix_acl_from_wire: Failed to set tagtype on entry %u. (%s)\n",
                                i, strerror(errno) ));
                        goto fail;
                }
 
                /* 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;
@@ -4459,16 +4388,16 @@ static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_
                }
 
                /* Now apply to the new ACL entry. */
-               if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
+               if (sys_acl_set_permset(the_entry, the_permset) == -1) {
                        DEBUG(0,("create_posix_acl_from_wire: Failed to add permset on entry %u. (%s)\n",
                                i, strerror(errno) ));
                        goto fail;
                }
 
                if (tag_type == SMB_ACL_USER) {
-                       uint32 uidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
+                       uint32_t uidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
                        uid_t uid = (uid_t)uidval;
-                       if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&uid) == -1) {
+                       if (sys_acl_set_qualifier(the_entry,(void *)&uid) == -1) {
                                DEBUG(0,("create_posix_acl_from_wire: Failed to set uid %u on entry %u. (%s)\n",
                                        (unsigned int)uid, i, strerror(errno) ));
                                goto fail;
@@ -4476,9 +4405,9 @@ static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_
                }
 
                if (tag_type == SMB_ACL_GROUP) {
-                       uint32 gidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
+                       uint32_t gidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
                        gid_t gid = (uid_t)gidval;
-                       if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&gid) == -1) {
+                       if (sys_acl_set_qualifier(the_entry,(void *)&gid) == -1) {
                                DEBUG(0,("create_posix_acl_from_wire: Failed to set gid %u on entry %u. (%s)\n",
                                        (unsigned int)gid, i, strerror(errno) ));
                                goto fail;
@@ -4491,7 +4420,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);
+               TALLOC_FREE(the_acl);
        }
        return NULL;
 }
@@ -4503,14 +4432,18 @@ static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_
  on the directory.
 ****************************************************************************/
 
-bool set_unix_posix_default_acl(connection_struct *conn, const char *fname, const SMB_STRUCT_STAT *psbuf,
-                               uint16 num_def_acls, const char *pdata)
+bool set_unix_posix_default_acl(connection_struct *conn,
+                               const struct smb_filename *smb_fname,
+                               uint16_t num_def_acls,
+                               const char *pdata)
 {
        SMB_ACL_T def_acl = NULL;
 
-       if (!S_ISDIR(psbuf->st_ex_mode)) {
+       if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
                if (num_def_acls) {
-                       DEBUG(5,("set_unix_posix_default_acl: Can't set default ACL on non-directory file %s\n", fname ));
+                       DEBUG(5,("set_unix_posix_default_acl: Can't "
+                               "set default ACL on non-directory file %s\n",
+                               smb_fname->base_name ));
                        errno = EISDIR;
                        return False;
                } else {
@@ -4520,27 +4453,31 @@ bool set_unix_posix_default_acl(connection_struct *conn, const char *fname, cons
 
        if (!num_def_acls) {
                /* Remove the default ACL. */
-               if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fname) == -1) {
+               if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, smb_fname) == -1) {
                        DEBUG(5,("set_unix_posix_default_acl: acl_delete_def_file failed on directory %s (%s)\n",
-                               fname, strerror(errno) ));
+                               smb_fname->base_name, strerror(errno) ));
                        return False;
                }
                return True;
        }
 
-       if ((def_acl = create_posix_acl_from_wire(conn, num_def_acls, pdata)) == NULL) {
+       if ((def_acl = create_posix_acl_from_wire(conn, num_def_acls,
+                                                 pdata,
+                                                 talloc_tos())) == NULL) {
                return False;
        }
 
-       if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT, def_acl) == -1) {
+       if (SMB_VFS_SYS_ACL_SET_FILE(conn, smb_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);
+                       smb_fname->base_name, strerror(errno) ));
+               TALLOC_FREE(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);
+       DEBUG(10,("set_unix_posix_default_acl: set default acl for file %s\n",
+               smb_fname->base_name ));
+       TALLOC_FREE(def_acl);
        return True;
 }
 
@@ -4552,14 +4489,17 @@ bool set_unix_posix_default_acl(connection_struct *conn, const char *fname, cons
  FIXME ! How does the share mask/mode fit into this.... ?
 ****************************************************************************/
 
-static bool remove_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname)
+static bool remove_posix_acl(connection_struct *conn,
+                       files_struct *fsp,
+                       const struct smb_filename *smb_fname)
 {
        SMB_ACL_T file_acl = NULL;
        int entry_id = SMB_ACL_FIRST_ENTRY;
        SMB_ACL_ENTRY_T entry;
        bool ret = False;
+       const char *fname = smb_fname->base_name;
        /* 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(talloc_tos());
        SMB_ACL_ENTRY_T user_ent = NULL;
        SMB_ACL_ENTRY_T group_ent = NULL;
        SMB_ACL_ENTRY_T other_ent = NULL;
@@ -4570,34 +4510,34 @@ 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;
        }
-       if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, user_ent, SMB_ACL_USER_OBJ) == -1) {
+       if (sys_acl_set_tag_type(user_ent, SMB_ACL_USER_OBJ) == -1) {
                DEBUG(5,("remove_posix_acl: Failed to set user entry for file %s. (%s)\n",
                        fname, strerror(errno) ));
                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;
        }
-       if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, group_ent, SMB_ACL_GROUP_OBJ) == -1) {
+       if (sys_acl_set_tag_type(group_ent, SMB_ACL_GROUP_OBJ) == -1) {
                DEBUG(5,("remove_posix_acl: Failed to set group entry for file %s. (%s)\n",
                        fname, strerror(errno) ));
                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;
        }
-       if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, other_ent, SMB_ACL_OTHER) == -1) {
+       if (sys_acl_set_tag_type(other_ent, SMB_ACL_OTHER) == -1) {
                DEBUG(5,("remove_posix_acl: Failed to set other entry for file %s. (%s)\n",
                        fname, strerror(errno) ));
                goto done;
@@ -4605,9 +4545,11 @@ static bool remove_posix_acl(connection_struct *conn, files_struct *fsp, const c
 
        /* Get the current file ACL. */
        if (fsp && fsp->fh->fd != -1) {
-               file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp);
+               file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, talloc_tos());
        } else {
-               file_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_ACCESS);
+               file_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, smb_fname,
+                                                   SMB_ACL_TYPE_ACCESS,
+                                                   talloc_tos());
        }
 
        if (file_acl == NULL) {
@@ -4618,36 +4560,36 @@ 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;
                }
 
                if (tagtype == SMB_ACL_USER_OBJ) {
-                       if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, user_ent, permset) == -1) {
+                       if (sys_acl_set_permset(user_ent, permset) == -1) {
                                DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
                                        fname, strerror(errno) ));
                        }
                } else if (tagtype == SMB_ACL_GROUP_OBJ) {
-                       if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, group_ent, permset) == -1) {
+                       if (sys_acl_set_permset(group_ent, permset) == -1) {
                                DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
                                        fname, strerror(errno) ));
                        }
                } else if (tagtype == SMB_ACL_OTHER) {
-                       if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, other_ent, permset) == -1) {
+                       if (sys_acl_set_permset(other_ent, permset) == -1) {
                                DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
                                        fname, strerror(errno) ));
                        }
@@ -4662,7 +4604,10 @@ static bool remove_posix_acl(connection_struct *conn, files_struct *fsp, const c
                        goto done;
                }
        } else {
-               if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, new_file_acl) == -1) {
+               if (SMB_VFS_SYS_ACL_SET_FILE(conn,
+                                       smb_fname,
+                                       SMB_ACL_TYPE_ACCESS,
+                                       new_file_acl) == -1) {
                        DEBUG(5,("remove_posix_acl: acl_set_file failed on %s (%s)\n",
                                fname, strerror(errno) ));
                        goto done;
@@ -4674,10 +4619,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);
+               TALLOC_FREE(file_acl);
        }
        if (new_file_acl) {
-               SMB_VFS_SYS_ACL_FREE_ACL(conn, new_file_acl);
+               TALLOC_FREE(new_file_acl);
        }
        return ret;
 }
@@ -4688,16 +4633,22 @@ static bool remove_posix_acl(connection_struct *conn, files_struct *fsp, const c
  except SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER.
 ****************************************************************************/
 
-bool set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname, uint16 num_acls, const char *pdata)
+bool set_unix_posix_acl(connection_struct *conn, files_struct *fsp,
+                       const struct smb_filename *smb_fname,
+                       uint16_t num_acls,
+                       const char *pdata)
 {
        SMB_ACL_T file_acl = NULL;
+       const char *fname = smb_fname->base_name;
 
        if (!num_acls) {
                /* Remove the ACL from the file. */
-               return remove_posix_acl(conn, fsp, fname);
+               return remove_posix_acl(conn, fsp, smb_fname);
        }
 
-       if ((file_acl = create_posix_acl_from_wire(conn, num_acls, pdata)) == NULL) {
+       if ((file_acl = create_posix_acl_from_wire(conn, num_acls,
+                                                  pdata,
+                                                  talloc_tos())) == NULL) {
                return False;
        }
 
@@ -4706,20 +4657,21 @@ 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);
+                       TALLOC_FREE(file_acl);
                        return False;
                }
        } else {
-               if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, file_acl) == -1) {
+               if (SMB_VFS_SYS_ACL_SET_FILE(conn, smb_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);
+                       TALLOC_FREE(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);
+       TALLOC_FREE(file_acl);
        return True;
 }
 
@@ -4728,177 +4680,180 @@ bool set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *
  check.  Caller is responsible for freeing the returned security
  descriptor via TALLOC_FREE().  This is designed for dealing with 
  user space access checks in smbd outside of the VFS.  For example,
- checking access rights in OpenEventlog().
+ checking access rights in OpenEventlog() or from python.
 
- Assume we are dealing with files (for now)
 ********************************************************************/
 
-struct security_descriptor *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
+NTSTATUS get_nt_acl_no_snum(TALLOC_CTX *ctx, const char *fname,
+                               uint32_t security_info_wanted,
+                               struct security_descriptor **sd)
 {
-       struct security_descriptor *psd, *ret_sd;
+       TALLOC_CTX *frame = talloc_stackframe();
        connection_struct *conn;
-       files_struct finfo;
-       struct fd_handle fh;
-       NTSTATUS status;
+       NTSTATUS status = NT_STATUS_OK;
+       struct smb_filename *smb_fname = synthetic_smb_fname(talloc_tos(),
+                                               fname,
+                                               NULL,
+                                               NULL,
+                                               0);
+
+       if (smb_fname == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
+       }
 
-       conn = talloc_zero(ctx, connection_struct);
-       if (conn == NULL) {
-               DEBUG(0, ("talloc failed\n"));
-               return NULL;
+       if (!posix_locking_init(false)) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
        }
 
-       if (!(conn->params = talloc(conn, struct share_params))) {
-               DEBUG(0,("get_nt_acl_no_snum: talloc() failed!\n"));
-               TALLOC_FREE(conn);
-               return NULL;
+       status = create_conn_struct(ctx,
+                               server_event_context(),
+                               server_messaging_context(),
+                               &conn,
+                               -1,
+                               "/",
+                               NULL);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,("create_conn_struct returned %s.\n",
+                       nt_errstr(status)));
+               TALLOC_FREE(frame);
+               return status;
        }
 
-       conn->params->service = -1;
+       status = SMB_VFS_GET_NT_ACL(conn,
+                               smb_fname,
+                               security_info_wanted,
+                               ctx,
+                               sd);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("get_nt_acl_no_snum: SMB_VFS_GET_NT_ACL returned %s.\n",
+                         nt_errstr(status)));
+       }
 
-       set_conn_connectpath(conn, "/");
+       conn_free(conn);
+       TALLOC_FREE(frame);
 
-       if (!smbd_vfs_init(conn)) {
-               DEBUG(0,("get_nt_acl_no_snum: Unable to create a fake connection struct!\n"));
-               conn_free(conn);
-               return NULL;
-        }
+       return status;
+}
 
-       ZERO_STRUCT( finfo );
-       ZERO_STRUCT( fh );
+int posix_sys_acl_blob_get_file(vfs_handle_struct *handle,
+                               const struct smb_filename *smb_fname_in,
+                               TALLOC_CTX *mem_ctx,
+                               char **blob_description,
+                               DATA_BLOB *blob)
+{
+       int ret;
+       TALLOC_CTX *frame = talloc_stackframe();
+       /* Initialise this to zero, in a portable way */
+       struct smb_acl_wrapper acl_wrapper = {
+               NULL
+       };
+       struct smb_filename *smb_fname = cp_smb_filename_nostream(frame,
+                                               smb_fname_in);
+       if (smb_fname == NULL) {
+               TALLOC_FREE(frame);
+               errno = ENOMEM;
+               return -1;
+       }
 
-       finfo.fnum = -1;
-       finfo.conn = conn;
-       finfo.fh = &fh;
-       finfo.fh->fd = -1;
+       acl_wrapper.access_acl
+               = smb_vfs_call_sys_acl_get_file(handle,
+                                               smb_fname,
+                                               SMB_ACL_TYPE_ACCESS,
+                                               frame);
 
-       status = create_synthetic_smb_fname(talloc_tos(), fname, NULL, NULL,
-                                           &finfo.fsp_name);
-       if (!NT_STATUS_IS_OK(status)) {
-               conn_free(conn);
-               return NULL;
+       ret = smb_vfs_call_stat(handle, smb_fname);
+       if (ret == -1) {
+               TALLOC_FREE(frame);
+               return -1;
        }
 
-       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);
-               return NULL;
+       if (S_ISDIR(smb_fname->st.st_ex_mode)) {
+               acl_wrapper.default_acl
+                       = smb_vfs_call_sys_acl_get_file(handle,
+                                                       smb_fname,
+                                                       SMB_ACL_TYPE_DEFAULT,
+                                                       frame);
        }
 
-       ret_sd = dup_sec_desc( ctx, psd );
+       acl_wrapper.owner = smb_fname->st.st_ex_uid;
+       acl_wrapper.group = smb_fname->st.st_ex_gid;
+       acl_wrapper.mode = smb_fname->st.st_ex_mode;
 
-       TALLOC_FREE(finfo.fsp_name);
-       conn_free(conn);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_struct_blob(blob, mem_ctx,
+                                                         &acl_wrapper,
+                                                         (ndr_push_flags_fn_t)ndr_push_smb_acl_wrapper))) {
+               errno = EINVAL;
+               TALLOC_FREE(frame);
+               return -1;
+       }
 
-       return ret_sd;
-}
+       *blob_description = talloc_strdup(mem_ctx, "posix_acl");
+       if (!*blob_description) {
+               errno = EINVAL;
+               TALLOC_FREE(frame);
+               return -1;
+       }
 
-/* Stolen shamelessly from pvfs_default_acl() in source4 :-). */
+       TALLOC_FREE(frame);
+       return 0;
+}
 
-NTSTATUS make_default_filesystem_acl(TALLOC_CTX *ctx,
-                                       const char *name,
-                                       SMB_STRUCT_STAT *psbuf,
-                                       struct security_descriptor **ppdesc)
+int posix_sys_acl_blob_get_fd(vfs_handle_struct *handle,
+                             files_struct *fsp,
+                             TALLOC_CTX *mem_ctx,
+                             char **blob_description,
+                             DATA_BLOB *blob)
 {
-       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;
+       SMB_STRUCT_STAT sbuf;
+       TALLOC_CTX *frame;
+       struct smb_acl_wrapper acl_wrapper;
+       int ret;
 
-       DEBUG(10,("make_default_filesystem_acl: file %s mode = 0%o\n",
-               name, (int)mode ));
+       /* This ensures that we also consider the default ACL */
+       if (fsp->is_directory ||  fsp->fh->fd == -1) {
+               return posix_sys_acl_blob_get_file(handle,
+                                               fsp->fsp_name,
+                                               mem_ctx,
+                                               blob_description,
+                                               blob);
+       }
+       frame = talloc_stackframe();
 
-       uid_to_sid(&owner_sid, psbuf->st_ex_uid);
-       gid_to_sid(&group_sid, psbuf->st_ex_gid);
+       acl_wrapper.default_acl = NULL;
 
-       /*
-        We provide up to 4 ACEs
-               - Owner
-               - Group
-               - Everyone
-               - NT System
-       */
+       acl_wrapper.access_acl = smb_vfs_call_sys_acl_get_file(handle,
+                                       fsp->fsp_name,
+                                       SMB_ACL_TYPE_ACCESS,
+                                       frame);
 
-       if (mode & S_IRUSR) {
-               if (mode & S_IWUSR) {
-                       access_mask |= SEC_RIGHTS_FILE_ALL;
-               } else {
-                       access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
-               }
+       ret = smb_vfs_call_fstat(handle, fsp, &sbuf);
+       if (ret == -1) {
+               TALLOC_FREE(frame);
+               return -1;
        }
-       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;
+
+       acl_wrapper.owner = sbuf.st_ex_uid;
+       acl_wrapper.group = sbuf.st_ex_gid;
+       acl_wrapper.mode = sbuf.st_ex_mode;
+
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_push_struct_blob(blob, mem_ctx,
+                                                         &acl_wrapper,
+                                                         (ndr_push_flags_fn_t)ndr_push_smb_acl_wrapper))) {
+               errno = EINVAL;
+               TALLOC_FREE(frame);
+               return -1;
        }
 
-       *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;
+       *blob_description = talloc_strdup(mem_ctx, "posix_acl");
+       if (!*blob_description) {
+               errno = EINVAL;
+               TALLOC_FREE(frame);
+               return -1;
        }
-       return NT_STATUS_OK;
+
+       TALLOC_FREE(frame);
+       return 0;
 }