s3: include smbd/smbd.h where needed.
[kai/samba-autobuild/.git] / source3 / smbd / posix_acls.c
index 36d18b013c01cb4f72d7adacd444265674390962..1544ca88b57ee7d9ef7549f3a378dde58fd91bb9 100644 (file)
 */
 
 #include "includes.h"
+#include "smbd/smbd.h"
+#include "system/filesys.h"
+#include "../libcli/security/security.h"
+#include "trans2.h"
+#include "passdb/lookup_sid.h"
 
 extern const struct generic_mapping file_generic_mapping;
 
@@ -441,6 +446,7 @@ static const char *create_pai_v1_entries(struct pai_val *paiv,
 
                paie->ace_flags = SEC_ACE_FLAG_INHERITED_ACE;
                if (!get_pai_owner_type(paie, entry_offset)) {
+                       SAFE_FREE(paie);
                        return NULL;
                }
 
@@ -519,6 +525,7 @@ static const char *create_pai_v2_entries(struct pai_val *paiv,
                paie->ace_flags = CVAL(entry_offset,0);
 
                if (!get_pai_owner_type(paie, entry_offset+1)) {
+                       SAFE_FREE(paie);
                        return NULL;
                }
                if (!def_entry) {
@@ -944,10 +951,10 @@ static void merge_aces( canon_ace **pp_list_head, bool dir_acl)
                         * ensure the POSIX ACL types are the same. */
 
                        if (!dir_acl) {
-                               can_merge = (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
+                               can_merge = (dom_sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
                                                (curr_ace->attr == curr_ace_outer->attr));
                        } else {
-                               can_merge = (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
+                               can_merge = (dom_sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
                                                (curr_ace->type == curr_ace_outer->type) &&
                                                (curr_ace->attr == curr_ace_outer->attr));
                        }
@@ -996,7 +1003,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 (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
+                       if (dom_sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
                                (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
 
                                if( DEBUGLVL( 10 )) {
@@ -1197,7 +1204,7 @@ NTSTATUS unpack_nt_owners(struct connection_struct *conn,
         * This may be a group chown only set.
         */
 
-       if (security_info_sent & OWNER_SECURITY_INFORMATION) {
+       if (security_info_sent & SECINFO_OWNER) {
                sid_copy(&owner_sid, psd->owner_sid);
                if (!sid_to_uid(&owner_sid, puser)) {
                        if (lp_force_unknown_acl_user(SNUM(conn))) {
@@ -1220,7 +1227,7 @@ NTSTATUS unpack_nt_owners(struct connection_struct *conn,
         * This may be an owner chown only set.
         */
 
-       if (security_info_sent & GROUP_SECURITY_INFORMATION) {
+       if (security_info_sent & SECINFO_GROUP) {
                sid_copy(&grp_sid, psd->group_sid);
                if (!sid_to_gid( &grp_sid, pgrp)) {
                        if (lp_force_unknown_acl_user(SNUM(conn))) {
@@ -1297,7 +1304,7 @@ static bool uid_entry_in_group(connection_struct *conn, canon_ace *uid_ace, cano
 
        /* "Everyone" always matches every uid. */
 
-       if (sid_equal(&group_ace->trustee, &global_sid_World))
+       if (dom_sid_equal(&group_ace->trustee, &global_sid_World))
                return True;
 
        /*
@@ -1305,7 +1312,7 @@ static bool uid_entry_in_group(connection_struct *conn, canon_ace *uid_ace, cano
         * and don't need to do the complex user_in_group_sid() call
         */
        if (uid_ace->unix_ug.uid == get_current_uid(conn)) {
-               const UNIX_USER_TOKEN *curr_utok = NULL;
+               const struct security_unix_token *curr_utok = NULL;
                size_t i;
 
                if (group_ace->unix_ug.gid == get_current_gid(conn)) {
@@ -1513,12 +1520,12 @@ static void check_owning_objs(canon_ace *ace, struct dom_sid *pfile_owner_sid, s
 
        for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
                if (!got_user_obj && current_ace->owner_type == UID_ACE &&
-                               sid_equal(&current_ace->trustee, pfile_owner_sid)) {
+                               dom_sid_equal(&current_ace->trustee, pfile_owner_sid)) {
                        current_ace->type = SMB_ACL_USER_OBJ;
                        got_user_obj = True;
                }
                if (!got_group_obj && current_ace->owner_type == GID_ACE &&
-                               sid_equal(&current_ace->trustee, pfile_grp_sid)) {
+                               dom_sid_equal(&current_ace->trustee, pfile_grp_sid)) {
                        current_ace->type = SMB_ACL_GROUP_OBJ;
                        got_group_obj = True;
                }
@@ -1549,7 +1556,7 @@ static bool dup_owning_ace(canon_ace *dir_ace, canon_ace *ace)
        */
 
        if (ace->type == SMB_ACL_USER_OBJ &&
-                       !(sid_equal(&ace->trustee, &global_sid_Creator_Owner))) {
+                       !(dom_sid_equal(&ace->trustee, &global_sid_Creator_Owner))) {
                canon_ace *dup_ace = dup_canon_ace(ace);
 
                if (dup_ace == NULL) {
@@ -1560,7 +1567,7 @@ static bool dup_owning_ace(canon_ace *dir_ace, canon_ace *ace)
        }
 
        if (ace->type == SMB_ACL_GROUP_OBJ &&
-                       !(sid_equal(&ace->trustee, &global_sid_Creator_Group))) {
+                       !(dom_sid_equal(&ace->trustee, &global_sid_Creator_Group))) {
                canon_ace *dup_ace = dup_canon_ace(ace);
 
                if (dup_ace == NULL) {
@@ -1646,7 +1653,7 @@ static bool create_canon_ace_lists(files_struct *fsp,
                        if (psa1->access_mask != psa2->access_mask)
                                continue;
 
-                       if (!sid_equal(&psa1->trustee, &psa2->trustee))
+                       if (!dom_sid_equal(&psa1->trustee, &psa2->trustee))
                                continue;
 
                        /*
@@ -1672,7 +1679,7 @@ static bool create_canon_ace_lists(files_struct *fsp,
                struct security_ace *psa = &dacl->aces[i];
 
                /*
-                * Create a cannon_ace entry representing this NT DACL ACE.
+                * Create a canon_ace entry representing this NT DACL ACE.
                 */
 
                if ((current_ace = SMB_MALLOC_P(canon_ace)) == NULL) {
@@ -1692,11 +1699,11 @@ static bool create_canon_ace_lists(files_struct *fsp,
                 * Note what kind of a POSIX ACL this should map to.
                 */
 
-               if( sid_equal(&current_ace->trustee, &global_sid_World)) {
+               if( dom_sid_equal(&current_ace->trustee, &global_sid_World)) {
                        current_ace->owner_type = WORLD_ACE;
                        current_ace->unix_ug.world = -1;
                        current_ace->type = SMB_ACL_OTHER;
-               } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Owner)) {
+               } else if (dom_sid_equal(&current_ace->trustee, &global_sid_Creator_Owner)) {
                        current_ace->owner_type = UID_ACE;
                        current_ace->unix_ug.uid = pst->st_ex_uid;
                        current_ace->type = SMB_ACL_USER_OBJ;
@@ -1709,7 +1716,7 @@ static bool create_canon_ace_lists(files_struct *fsp,
 
                        psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
 
-               } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Group)) {
+               } 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->type = SMB_ACL_GROUP_OBJ;
@@ -1752,6 +1759,14 @@ static bool create_canon_ace_lists(files_struct *fsp,
                                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)));
+                               SAFE_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 "
@@ -2085,7 +2100,7 @@ static void process_deny_list(connection_struct *conn, canon_ace **pp_ace_list )
                        continue;
                }
 
-               if (!sid_equal(&curr_ace->trustee, &global_sid_World))
+               if (!dom_sid_equal(&curr_ace->trustee, &global_sid_World))
                        continue;
 
                /* JRATEST - assert. */
@@ -2337,7 +2352,7 @@ static bool unpack_canon_ace(files_struct *fsp,
         * If no DACL then this is a chown only security descriptor.
         */
 
-       if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !psd->dacl)
+       if(!(security_info_sent & SECINFO_DACL) || !psd->dacl)
                return True;
 
        /*
@@ -2643,7 +2658,7 @@ static canon_ace *canonicalise_acl(struct connection_struct *conn,
 static bool current_user_in_group(connection_struct *conn, gid_t gid)
 {
        int i;
-       const UNIX_USER_TOKEN *utok = get_current_utok(conn);
+       const struct security_unix_token *utok = get_current_utok(conn);
 
        for (i = 0; i < utok->ngroups; i++) {
                if (utok->groups[i] == gid) {
@@ -3080,7 +3095,7 @@ static size_t merge_default_aces( struct security_ace *nt_ace_list, size_t num_a
                        if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
                                (nt_ace_list[i].size == nt_ace_list[j].size) &&
                                (nt_ace_list[i].access_mask == nt_ace_list[j].access_mask) &&
-                               sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
+                               dom_sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
                                (i_inh == j_inh) &&
                                (i_flags_ni == 0) &&
                                (j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT|
@@ -3144,7 +3159,7 @@ static void add_or_replace_ace(struct security_ace *nt_ace_list, size_t *num_ace
 
        /* first search for a duplicate */
        for (i = 0; i < *num_aces; i++) {
-               if (sid_equal(&nt_ace_list[i].trustee, sid) &&
+               if (dom_sid_equal(&nt_ace_list[i].trustee, sid) &&
                    (nt_ace_list[i].flags == flags)) break;
        }
 
@@ -3206,7 +3221,7 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
                num_profile_acls = 3;
        }
 
-       if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) {
+       if ((security_info & SECINFO_DACL) && !(security_info & SECINFO_PROTECTED_DACL)) {
 
                /*
                 * In the optimum case Creator Owner and Creator Group would be used for
@@ -3367,7 +3382,7 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
 
                        if (lp_profile_acls(SNUM(conn))) {
                                for (i = 0; i < num_aces; i++) {
-                                       if (sid_equal(&nt_ace_list[i].trustee, &owner_sid)) {
+                                       if (dom_sid_equal(&nt_ace_list[i].trustee, &owner_sid)) {
                                                add_or_replace_ace(nt_ace_list, &num_aces,
                                                                   &orig_owner_sid,
                                                                   nt_ace_list[i].type,
@@ -3385,11 +3400,11 @@ static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
                                goto done;
                        }
                }
-       } /* security_info & DACL_SECURITY_INFORMATION */
+       } /* security_info & SECINFO_DACL */
 
        psd = make_standard_sec_desc( talloc_tos(),
-                       (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL,
-                       (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL,
+                       (security_info & SECINFO_OWNER) ? &owner_sid : NULL,
+                       (security_info & SECINFO_GROUP) ? &group_sid : NULL,
                        psa,
                        &sd_size);
 
@@ -3517,107 +3532,73 @@ NTSTATUS posix_get_nt_acl(struct connection_struct *conn, const char *name,
  Try to chown a file. We will be able to chown it under the following conditions.
 
   1) If we have root privileges, then it will just work.
-  2) If we have SeTakeOwnershipPrivilege we can change the user to the current user.
-  3) If we have SeRestorePrivilege we can change the user to any other user. 
+  2) If we have SeRestorePrivilege we can change the user + group to any other user. 
+  3) If we have SeTakeOwnershipPrivilege we can change the user to the current user.
   4) If we have write permission to the file and dos_filemodes is set
      then allow chown to the currently authenticated user.
 ****************************************************************************/
 
-int try_chown(connection_struct *conn, struct smb_filename *smb_fname,
-             uid_t uid, gid_t gid)
+NTSTATUS try_chown(files_struct *fsp, uid_t uid, gid_t gid)
 {
-       int ret;
-       files_struct *fsp;
+       NTSTATUS status;
 
-       if(!CAN_WRITE(conn)) {
-               return -1;
+       if(!CAN_WRITE(fsp->conn)) {
+               return NT_STATUS_MEDIA_WRITE_PROTECTED;
        }
 
        /* Case (1). */
-       /* try the direct way first */
-       if (lp_posix_pathnames()) {
-               ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, uid, gid);
-       } else {
-               ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid, gid);
+       status = vfs_chown_fsp(fsp, uid, gid);
+       if (NT_STATUS_IS_OK(status)) {
+               return status;
        }
 
-       if (ret == 0)
-               return 0;
-
        /* Case (2) / (3) */
        if (lp_enable_privileges()) {
-
-               bool has_take_ownership_priv = user_has_privileges(get_current_nttok(conn),
-                                                             &se_take_ownership);
-               bool has_restore_priv = user_has_privileges(get_current_nttok(conn),
-                                                      &se_restore);
-
-               /* Case (2) */
-               if ( ( has_take_ownership_priv && ( uid == get_current_uid(conn) ) ) ||
-               /* Case (3) */
-                    ( has_restore_priv ) ) {
-
-                       become_root();
-                       /* Keep the current file gid the same - take ownership doesn't imply group change. */
-                       if (lp_posix_pathnames()) {
-                               ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, uid,
-                                                   (gid_t)-1);
+               bool has_take_ownership_priv = security_token_has_privilege(
+                                               get_current_nttok(fsp->conn),
+                                               SEC_PRIV_TAKE_OWNERSHIP);
+               bool has_restore_priv = security_token_has_privilege(
+                                               get_current_nttok(fsp->conn),
+                                               SEC_PRIV_RESTORE);
+
+               if (has_restore_priv) {
+                       ; /* Case (2) */
+               } else if (has_take_ownership_priv) {
+                       /* Case (3) */
+                       if (uid == get_current_uid(fsp->conn)) {
+                               gid = (gid_t)-1;
                        } else {
-                               ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid,
-                                                   (gid_t)-1);
+                               has_take_ownership_priv = false;
                        }
+               }
+
+               if (has_take_ownership_priv || has_restore_priv) {
+                       become_root();
+                       status = vfs_chown_fsp(fsp, uid, gid);
                        unbecome_root();
-                       return ret;
+                       return status;
                }
        }
 
        /* Case (4). */
-       if (!lp_dos_filemode(SNUM(conn))) {
-               errno = EPERM;
-               return -1;
+       if (!lp_dos_filemode(SNUM(fsp->conn))) {
+               return NT_STATUS_ACCESS_DENIED;
        }
 
        /* only allow chown to the current user. This is more secure,
           and also copes with the case where the SID in a take ownership ACL is
           a local SID on the users workstation
        */
-       if (uid != get_current_uid(conn)) {
-               errno = EPERM;
-               return -1;
-       }
-
-       if (lp_posix_pathnames()) {
-               ret = SMB_VFS_LSTAT(conn, smb_fname);
-       } else {
-               ret = SMB_VFS_STAT(conn, smb_fname);
-       }
-
-       if (ret == -1) {
-               return -1;
-       }
-
-       if (!NT_STATUS_IS_OK(open_file_fchmod(NULL, conn, smb_fname, &fsp))) {
-               return -1;
+       if (uid != get_current_uid(fsp->conn)) {
+               return NT_STATUS_ACCESS_DENIED;
        }
 
        become_root();
        /* Keep the current file gid the same. */
-       if (fsp->fh->fd == -1) {
-               if (lp_posix_pathnames()) {
-                       ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, uid,
-                                           (gid_t)-1);
-               } else {
-                       ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid,
-                                           (gid_t)-1);
-               }
-       } else {
-               ret = SMB_VFS_FCHOWN(fsp, uid, (gid_t)-1);
-       }
+       status = vfs_chown_fsp(fsp, uid, (gid_t)-1);
        unbecome_root();
 
-       close_file_fchmod(NULL, fsp);
-
-       return ret;
+       return status;
 }
 
 #if 0
@@ -3682,7 +3663,7 @@ NTSTATUS append_parent_acl(files_struct *fsp,
        }
 
        status = SMB_VFS_GET_NT_ACL(parent_fsp->conn, smb_dname->base_name,
-                                   DACL_SECURITY_INFORMATION, &parent_sd );
+                                   SECINFO_DACL, &parent_sd );
 
        close_file(NULL, parent_fsp, NORMAL_CLOSE);
        TALLOC_FREE(smb_dname);
@@ -3758,7 +3739,7 @@ NTSTATUS append_parent_acl(files_struct *fsp,
                         * same SID. This is order N^2. Ouch :-(. JRA. */
                        unsigned int k;
                        for (k = 0; k < psd->dacl->num_aces; k++) {
-                               if (sid_equal(&psd->dacl->aces[k].trustee,
+                               if (dom_sid_equal(&psd->dacl->aces[k].trustee,
                                                &se->trustee)) {
                                        break;
                                }
@@ -3825,9 +3806,11 @@ NTSTATUS append_parent_acl(files_struct *fsp,
  Reply to set a security descriptor on an fsp. security_info_sent is the
  description of the following NT ACL.
  This should be the only external function needed for the UNIX style set ACL.
+ We make a copy of psd_orig as internal functions modify the elements inside
+ it, even though it's a const pointer.
 ****************************************************************************/
 
-NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd)
+NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct security_descriptor *psd_orig)
 {
        connection_struct *conn = fsp->conn;
        uid_t user = (uid_t)-1;
@@ -3842,6 +3825,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct s
        bool set_acl_as_root = false;
        bool acl_set_support = false;
        bool ret = false;
+       struct security_descriptor *psd = NULL;
 
        DEBUG(10,("set_nt_acl: called for file %s\n",
                  fsp_str_dbg(fsp)));
@@ -3851,6 +3835,15 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct s
                return NT_STATUS_MEDIA_WRITE_PROTECTED;
        }
 
+       if (!psd_orig) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       psd = dup_sec_desc(talloc_tos(), psd_orig);
+       if (!psd) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
        /*
         * Get the current state of the file.
         */
@@ -3867,6 +3860,14 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct s
         * Unpack the user/group/world id's.
         */
 
+       /* POSIX can't cope with missing owner/group. */
+       if ((security_info_sent & SECINFO_OWNER) && (psd->owner_sid == NULL)) {
+               security_info_sent &= ~SECINFO_OWNER;
+       }
+       if ((security_info_sent & SECINFO_GROUP) && (psd->group_sid == NULL)) {
+               security_info_sent &= ~SECINFO_GROUP;
+       }
+
        status = unpack_nt_owners( conn, &user, &grp, security_info_sent, psd);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -3885,15 +3886,14 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct s
                         fsp_str_dbg(fsp), (unsigned int)user,
                         (unsigned int)grp));
 
-               if(try_chown(fsp->conn, fsp->fsp_name, user, grp) == -1) {
+               status = try_chown(fsp, user, grp);
+               if(!NT_STATUS_IS_OK(status)) {
                        DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error "
-                                "= %s.\n", fsp_str_dbg(fsp),
-                                (unsigned int)user, (unsigned int)grp,
-                                strerror(errno)));
-                       if (errno == EPERM) {
-                               return NT_STATUS_INVALID_OWNER;
-                       }
-                       return map_nt_error_from_unix(errno);
+                               "= %s.\n", fsp_str_dbg(fsp),
+                               (unsigned int)user,
+                               (unsigned int)grp,
+                               nt_errstr(status)));
+                       return status;
                }
 
                /*
@@ -3917,6 +3917,39 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct s
 
        create_file_sids(&fsp->fsp_name->st, &file_owner_sid, &file_grp_sid);
 
+       if((security_info_sent & SECINFO_DACL) &&
+                       (psd->type & SEC_DESC_DACL_PRESENT) &&
+                       (psd->dacl == NULL)) {
+               struct security_ace ace[3];
+
+               /* We can't have NULL DACL in POSIX.
+                  Use owner/group/Everyone -> full access. */
+
+               init_sec_ace(&ace[0],
+                               &file_owner_sid,
+                               SEC_ACE_TYPE_ACCESS_ALLOWED,
+                               GENERIC_ALL_ACCESS,
+                               0);
+               init_sec_ace(&ace[1],
+                               &file_grp_sid,
+                               SEC_ACE_TYPE_ACCESS_ALLOWED,
+                               GENERIC_ALL_ACCESS,
+                               0);
+               init_sec_ace(&ace[2],
+                               &global_sid_World,
+                               SEC_ACE_TYPE_ACCESS_ALLOWED,
+                               GENERIC_ALL_ACCESS,
+                               0);
+               psd->dacl = make_sec_acl(talloc_tos(),
+                                       NT4_ACL_REVISION,
+                                       3,
+                                       ace);
+               if (psd->dacl == NULL) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               security_acl_map_generic(psd->dacl, &file_generic_mapping);
+       }
+
        acl_perms = unpack_canon_ace(fsp, &fsp->fsp_name->st, &file_owner_sid,
                                     &file_grp_sid, &file_ace_list,
                                     &dir_ace_list, security_info_sent, psd);
@@ -3937,7 +3970,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const struct s
         * Only change security if we got a DACL.
         */
 
-       if(!(security_info_sent & DACL_SECURITY_INFORMATION) || (psd->dacl == NULL)) {
+       if(!(security_info_sent & SECINFO_DACL) || (psd->dacl == NULL)) {
                free_canon_ace_list(file_ace_list);
                free_canon_ace_list(dir_ace_list);
                return NT_STATUS_OK;
@@ -4747,7 +4780,7 @@ struct security_descriptor *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fna
                return NULL;
        }
 
-       if (!NT_STATUS_IS_OK(SMB_VFS_FGET_NT_ACL( &finfo, DACL_SECURITY_INFORMATION, &psd))) {
+       if (!NT_STATUS_IS_OK(SMB_VFS_FGET_NT_ACL( &finfo, SECINFO_DACL, &psd))) {
                DEBUG(0,("get_nt_acl_no_snum: get_nt_acl returned zero.\n"));
                TALLOC_FREE(finfo.fsp_name);
                conn_free(conn);
@@ -4761,3 +4794,113 @@ struct security_descriptor *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fna
 
        return ret_sd;
 }
+
+/* Stolen shamelessly from pvfs_default_acl() in source4 :-). */
+
+NTSTATUS make_default_filesystem_acl(TALLOC_CTX *ctx,
+                                       const char *name,
+                                       SMB_STRUCT_STAT *psbuf,
+                                       struct security_descriptor **ppdesc)
+{
+       struct dom_sid owner_sid, group_sid;
+       size_t size = 0;
+       struct security_ace aces[4];
+       uint32_t access_mask = 0;
+       mode_t mode = psbuf->st_ex_mode;
+       struct security_acl *new_dacl = NULL;
+       int idx = 0;
+
+       DEBUG(10,("make_default_filesystem_acl: file %s mode = 0%o\n",
+               name, (int)mode ));
+
+       uid_to_sid(&owner_sid, psbuf->st_ex_uid);
+       gid_to_sid(&group_sid, psbuf->st_ex_gid);
+
+       /*
+        We provide up to 4 ACEs
+               - Owner
+               - Group
+               - Everyone
+               - NT System
+       */
+
+       if (mode & S_IRUSR) {
+               if (mode & S_IWUSR) {
+                       access_mask |= SEC_RIGHTS_FILE_ALL;
+               } else {
+                       access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
+               }
+       }
+       if (mode & S_IWUSR) {
+               access_mask |= SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE;
+       }
+
+       init_sec_ace(&aces[idx],
+                       &owner_sid,
+                       SEC_ACE_TYPE_ACCESS_ALLOWED,
+                       access_mask,
+                       0);
+       idx++;
+
+       access_mask = 0;
+       if (mode & S_IRGRP) {
+               access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
+       }
+       if (mode & S_IWGRP) {
+               /* note that delete is not granted - this matches posix behaviour */
+               access_mask |= SEC_RIGHTS_FILE_WRITE;
+       }
+       if (access_mask) {
+               init_sec_ace(&aces[idx],
+                       &group_sid,
+                       SEC_ACE_TYPE_ACCESS_ALLOWED,
+                       access_mask,
+                       0);
+               idx++;
+       }
+
+       access_mask = 0;
+       if (mode & S_IROTH) {
+               access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
+       }
+       if (mode & S_IWOTH) {
+               access_mask |= SEC_RIGHTS_FILE_WRITE;
+       }
+       if (access_mask) {
+               init_sec_ace(&aces[idx],
+                       &global_sid_World,
+                       SEC_ACE_TYPE_ACCESS_ALLOWED,
+                       access_mask,
+                       0);
+               idx++;
+       }
+
+       init_sec_ace(&aces[idx],
+                       &global_sid_System,
+                       SEC_ACE_TYPE_ACCESS_ALLOWED,
+                       SEC_RIGHTS_FILE_ALL,
+                       0);
+       idx++;
+
+       new_dacl = make_sec_acl(ctx,
+                       NT4_ACL_REVISION,
+                       idx,
+                       aces);
+
+       if (!new_dacl) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       *ppdesc = make_sec_desc(ctx,
+                       SECURITY_DESCRIPTOR_REVISION_1,
+                       SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
+                       &owner_sid,
+                       &group_sid,
+                       NULL,
+                       new_dacl,
+                       &size);
+       if (!*ppdesc) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       return NT_STATUS_OK;
+}