This is a proposed patch for Bug #5023.
[obnox/samba/samba-obnox.git] / source / smbd / posix_acls.c
index 87b456a2f70a993da2ff073ee8d6a39f5097ade5..73c2e65c64ae38858866a243708ec5c2c506bfff 100644 (file)
@@ -21,7 +21,7 @@
 #include "includes.h"
 
 extern struct current_user current_user;
-extern struct generic_mapping file_generic_mapping;
+extern const struct generic_mapping file_generic_mapping;
 
 #undef  DBGC_CLASS
 #define DBGC_CLASS DBGC_ACLS
@@ -47,7 +47,7 @@ typedef struct canon_ace {
        enum ace_owner owner_type;
        enum ace_attribute attr;
        posix_id unix_ug;
-       BOOL inherited;
+       bool inherited;
 } canon_ace;
 
 #define ALL_ACE_PERMS (S_IRUSR|S_IWUSR|S_IXUSR)
@@ -79,11 +79,11 @@ typedef struct canon_ace {
 struct pai_entry {
        struct pai_entry *next, *prev;
        enum ace_owner owner_type;
-       posix_id unix_ug; 
+       posix_id unix_ug;
 };
-       
+
 struct pai_val {
-       BOOL pai_protected;
+       bool pai_protected;
        unsigned int num_entries;
        struct pai_entry *entry_list;
        unsigned int num_def_entries;
@@ -148,7 +148,7 @@ static unsigned int num_inherited_entries(canon_ace *ace_list)
  Create the on-disk format. Caller must free.
 ************************************************************************/
 
-static char *create_pai_buf(canon_ace *file_ace_list, canon_ace *dir_ace_list, BOOL pai_protected, size_t *store_size)
+static char *create_pai_buf(canon_ace *file_ace_list, canon_ace *dir_ace_list, bool pai_protected, size_t *store_size)
 {
        char *pai_buf = NULL;
        canon_ace *ace_list = NULL;
@@ -212,7 +212,7 @@ static char *create_pai_buf(canon_ace *file_ace_list, canon_ace *dir_ace_list, B
 ************************************************************************/
 
 static void store_inheritance_attributes(files_struct *fsp, canon_ace *file_ace_list,
-                                       canon_ace *dir_ace_list, BOOL pai_protected)
+                                       canon_ace *dir_ace_list, bool pai_protected)
 {
        int ret;
        size_t store_size;
@@ -275,7 +275,7 @@ static void free_inherited_info(struct pai_val *pal)
  Was this ACL protected ?
 ************************************************************************/
 
-static BOOL get_protected_flag(struct pai_val *pal)
+static bool get_protected_flag(struct pai_val *pal)
 {
        if (!pal)
                return False;
@@ -286,7 +286,7 @@ static BOOL get_protected_flag(struct pai_val *pal)
  Was this ACE inherited ?
 ************************************************************************/
 
-static BOOL get_inherited_flag(struct pai_val *pal, canon_ace *ace_entry, BOOL default_ace)
+static bool get_inherited_flag(struct pai_val *pal, canon_ace *ace_entry, bool default_ace)
 {
        struct pai_entry *paie;
 
@@ -306,7 +306,7 @@ static BOOL get_inherited_flag(struct pai_val *pal, canon_ace *ace_entry, BOOL d
  Ensure an attribute just read is valid.
 ************************************************************************/
 
-static BOOL check_pai_ok(char *pai_buf, size_t pai_buf_data_size)
+static bool check_pai_ok(char *pai_buf, size_t pai_buf_data_size)
 {
        uint16 num_entries;
        uint16 num_def_entries;
@@ -672,7 +672,7 @@ static void create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SI
  Is the identity in two ACEs equal ? Check both SID and uid/gid.
 ****************************************************************************/
 
-static BOOL identity_in_ace_equal(canon_ace *ace1, canon_ace *ace2)
+static bool identity_in_ace_equal(canon_ace *ace1, canon_ace *ace2)
 {
        if (sid_equal(&ace1->trustee, &ace2->trustee)) {
                return True;
@@ -807,7 +807,7 @@ static void merge_aces( canon_ace **pp_list_head )
  Check if we need to return NT4.x compatible ACL entries.
 ****************************************************************************/
 
-static BOOL nt4_compatible_acls(void)
+static bool nt4_compatible_acls(void)
 {
        int compat = lp_acl_compatibility();
 
@@ -830,7 +830,7 @@ static BOOL nt4_compatible_acls(void)
 static SEC_ACCESS map_canon_ace_perms(int snum,
                                int *pacl_type,
                                mode_t perms,
-                               BOOL directory_ace)
+                               bool directory_ace)
 {
        SEC_ACCESS sa;
        uint32 nt_mask = 0;
@@ -1001,7 +1001,7 @@ NTSTATUS unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_i
  Ensure the enforced permissions for this share apply.
 ****************************************************************************/
 
-static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type)
+static void apply_default_perms(const files_struct *fsp, canon_ace *pace, mode_t type)
 {
        int snum = SNUM(fsp->conn);
        mode_t and_bits = (mode_t)0;
@@ -1045,9 +1045,9 @@ static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type)
  expensive and will need optimisation. A *lot* of optimisation :-). JRA.
 ****************************************************************************/
 
-static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
+static bool uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
 {
-       fstring u_name;
+       const char *u_name = NULL;
 
        /* "Everyone" always matches every uid. */
 
@@ -1059,7 +1059,11 @@ static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
        if (uid_ace->unix_ug.uid == current_user.ut.uid && group_ace->unix_ug.gid == current_user.ut.gid)
                return True;
 
-       fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid));
+       /* u_name talloc'ed off tos. */
+       u_name = uidtoname(uid_ace->unix_ug.uid);
+       if (!u_name) {
+               return False;
+       }
        return user_in_group_sid(u_name, &group_ace->trustee);
 }
 
@@ -1073,17 +1077,17 @@ static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
  type.
 ****************************************************************************/
 
-static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
-                                                       files_struct *fsp,
+static bool ensure_canon_entry_valid(canon_ace **pp_ace,
+                                                       const files_struct *fsp,
                                                        const DOM_SID *pfile_owner_sid,
                                                        const DOM_SID *pfile_grp_sid,
                                                        SMB_STRUCT_STAT *pst,
-                                                       BOOL setting_acl)
+                                                       bool setting_acl)
 {
        canon_ace *pace;
-       BOOL got_user = False;
-       BOOL got_grp = False;
-       BOOL got_other = False;
+       bool got_user = False;
+       bool got_grp = False;
+       bool got_other = False;
        canon_ace *pace_other = NULL;
 
        for (pace = *pp_ace; pace; pace = pace->next) {
@@ -1133,7 +1137,7 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
                        /* See if the owning user is in any of the other groups in
                           the ACE. If so, OR in the permissions from that group. */
 
-                       BOOL group_matched = False;
+                       bool group_matched = False;
                        canon_ace *pace_iter;
 
                        for (pace_iter = *pp_ace; pace_iter; pace_iter = pace_iter->next) {
@@ -1219,7 +1223,7 @@ static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
 
 static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid)
 {
-       BOOL got_user_obj, got_group_obj;
+       bool got_user_obj, got_group_obj;
        canon_ace *current_ace;
        int i, entries;
 
@@ -1260,18 +1264,18 @@ static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID
  Unpack a SEC_DESC into two canonical ace lists.
 ****************************************************************************/
 
-static BOOL create_canon_ace_lists(files_struct *fsp, SMB_STRUCT_STAT *pst,
+static bool create_canon_ace_lists(files_struct *fsp, SMB_STRUCT_STAT *pst,
                                                        DOM_SID *pfile_owner_sid,
                                                        DOM_SID *pfile_grp_sid,
                                                        canon_ace **ppfile_ace, canon_ace **ppdir_ace,
                                                        SEC_ACL *dacl)
 {
-       BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
+       bool all_aces_are_inherit_only = (fsp->is_directory ? True : False);
        canon_ace *file_ace = NULL;
        canon_ace *dir_ace = NULL;
        canon_ace *current_ace = NULL;
-       BOOL got_dir_allow = False;
-       BOOL got_file_allow = False;
+       bool got_dir_allow = False;
+       bool got_file_allow = False;
        int i, j;
 
        *ppfile_ace = NULL;
@@ -1901,7 +1905,7 @@ static void process_deny_list( canon_ace **pp_ace_list )
  no user/group/world entries.
 ****************************************************************************/
 
-static mode_t create_default_mode(files_struct *fsp, BOOL interitable_mode)
+static mode_t create_default_mode(files_struct *fsp, bool interitable_mode)
 {
        int snum = SNUM(fsp->conn);
        mode_t and_bits = (mode_t)0;
@@ -1935,7 +1939,7 @@ static mode_t create_default_mode(files_struct *fsp, BOOL interitable_mode)
  succeeding.
 ****************************************************************************/
 
-static BOOL unpack_canon_ace(files_struct *fsp, 
+static bool unpack_canon_ace(files_struct *fsp, 
                                                        SMB_STRUCT_STAT *pst,
                                                        DOM_SID *pfile_owner_sid,
                                                        DOM_SID *pfile_grp_sid,
@@ -2106,7 +2110,7 @@ static void arrange_posix_perms( char *filename, canon_ace **pp_list_head)
  Create a linked list of canonical ACE entries.
 ****************************************************************************/
 
-static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf,
+static canon_ace *canonicalise_acl( const files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf,
                                        const DOM_SID *powner, const DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type)
 {
        connection_struct *conn = fsp->conn;
@@ -2266,7 +2270,7 @@ static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_
  Check if the current user group list contains a given group.
 ****************************************************************************/
 
-static BOOL current_user_in_group(gid_t gid)
+static bool current_user_in_group(gid_t gid)
 {
        int i;
 
@@ -2284,7 +2288,7 @@ static BOOL current_user_in_group(gid_t gid)
  and 'dos filemode'
 ****************************************************************************/
 
-static BOOL acl_group_override(connection_struct *conn, gid_t prim_gid)
+static bool acl_group_override(connection_struct *conn, gid_t prim_gid)
 {
        if ( (errno == EACCES || errno == EPERM) 
                && (lp_acl_group_control(SNUM(conn)) || lp_dos_filemode(SNUM(conn)))
@@ -2300,18 +2304,18 @@ static BOOL acl_group_override(connection_struct *conn, gid_t prim_gid)
  Attempt to apply an ACL to a file or directory.
 ****************************************************************************/
 
-static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, gid_t prim_gid, BOOL *pacl_set_support)
+static bool set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, bool default_ace, gid_t prim_gid, bool *pacl_set_support)
 {
        connection_struct *conn = fsp->conn;
-       BOOL ret = False;
+       bool ret = False;
        SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, (int)count_canon_ace_list(the_ace) + 1);
        canon_ace *p_ace;
        int i;
        SMB_ACL_ENTRY_T mask_entry;
-       BOOL got_mask_entry = False;
+       bool got_mask_entry = False;
        SMB_ACL_PERMSET_T mask_permset;
        SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
-       BOOL needs_mask = False;
+       bool needs_mask = False;
        mode_t mask_perms = 0;
 
 #if defined(POSIX_ACL_NEEDS_MASK)
@@ -2582,7 +2586,7 @@ SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl)
 
 #define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
 
-static BOOL convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
+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);
@@ -2666,8 +2670,8 @@ static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
                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);
-                       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;
+                       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;
 
                        /* We know the lower number ACE's are file entries. */
                        if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
@@ -2971,14 +2975,14 @@ size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
                }
 
                if (num_aces) {
-                       if((psa = make_sec_acl( main_loop_talloc_get(), NT4_ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
+                       if((psa = make_sec_acl( talloc_tos(), NT4_ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
                                DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
                                goto done;
                        }
                }
        } /* security_info & DACL_SECURITY_INFORMATION */
 
-       psd = make_standard_sec_desc( main_loop_talloc_get(),
+       psd = make_standard_sec_desc( talloc_tos(),
                        (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL,
                        (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL,
                        psa,
@@ -3055,9 +3059,9 @@ int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
        /* Case (2) / (3) */
        if (lp_enable_privileges()) {
 
-               BOOL has_take_ownership_priv = user_has_privileges(current_user.nt_user_token,
+               bool has_take_ownership_priv = user_has_privileges(current_user.nt_user_token,
                                                              &se_take_ownership);
-               BOOL has_restore_priv = user_has_privileges(current_user.nt_user_token,
+               bool has_restore_priv = user_has_privileges(current_user.nt_user_token,
                                                       &se_restore);
 
                /* Case (2) */
@@ -3111,7 +3115,7 @@ static NTSTATUS append_ugw_ace(files_struct *fsp,
 {
        mode_t perms;
        SEC_ACCESS acc;
-       int acl_type;
+       int nt_acl_type;
        DOM_SID trustee;
 
        switch (ugw) {
@@ -3140,13 +3144,13 @@ static NTSTATUS append_ugw_ace(files_struct *fsp,
                        return NT_STATUS_INVALID_PARAMETER;
        }
        acc = map_canon_ace_perms(SNUM(fsp->conn),
-                               &acl_type,
+                               &nt_acl_type,
                                perms,
                                fsp->is_directory);
 
        init_sec_ace(se,
                &trustee,
-               acl_type,
+               nt_acl_type,
                acc,
                0);
        return NT_STATUS_OK;
@@ -3312,7 +3316,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
        DOM_SID file_grp_sid;
        canon_ace *file_ace_list = NULL;
        canon_ace *dir_ace_list = NULL;
-       BOOL acl_perms = False;
+       bool acl_perms = False;
        mode_t orig_mode = (mode_t)0;
        NTSTATUS status;
 
@@ -3424,8 +3428,8 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
 
                if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
 
-                       BOOL acl_set_support = False;
-                       BOOL ret = False;
+                       bool acl_set_support = False;
+                       bool ret = False;
 
                        /*
                         * Try using the POSIX ACL set first. Fall back to chmod if
@@ -3728,10 +3732,10 @@ int fchmod_acl(files_struct *fsp, int fd, mode_t mode)
  Check for an existing default POSIX ACL on a directory.
 ****************************************************************************/
 
-BOOL directory_has_default_acl(connection_struct *conn, const char *fname)
+bool directory_has_default_acl(connection_struct *conn, const char *fname)
 {
        SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT);
-       BOOL has_acl = False;
+       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)) {
@@ -3748,7 +3752,7 @@ BOOL directory_has_default_acl(connection_struct *conn, const char *fname)
  Map from wire type to permset.
 ****************************************************************************/
 
-static BOOL unix_ex_wire_to_permset(connection_struct *conn, unsigned char wire_perm, SMB_ACL_PERMSET_T *p_permset)
+static bool unix_ex_wire_to_permset(connection_struct *conn, unsigned char wire_perm, SMB_ACL_PERMSET_T *p_permset)
 {
        if (wire_perm & ~(SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE)) {
                return False;
@@ -3780,7 +3784,7 @@ static BOOL unix_ex_wire_to_permset(connection_struct *conn, unsigned char wire_
  Map from wire type to tagtype.
 ****************************************************************************/
 
-static BOOL unix_ex_wire_to_tagtype(unsigned char wire_tt, SMB_ACL_TAG_T *p_tt)
+static bool unix_ex_wire_to_tagtype(unsigned char wire_tt, SMB_ACL_TAG_T *p_tt)
 {
        switch (wire_tt) {
                case SMB_POSIX_ACL_USER_OBJ:
@@ -3903,7 +3907,7 @@ static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_
  on the directory.
 ****************************************************************************/
 
-BOOL set_unix_posix_default_acl(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf,
+bool set_unix_posix_default_acl(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf,
                                uint16 num_def_acls, const char *pdata)
 {
        SMB_ACL_T def_acl = NULL;
@@ -3948,12 +3952,12 @@ BOOL set_unix_posix_default_acl(connection_struct *conn, const char *fname, SMB_
  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 char *fname)
 {
        SMB_ACL_T file_acl = NULL;
        int entry_id = SMB_ACL_FIRST_ENTRY;
        SMB_ACL_ENTRY_T entry;
-       BOOL ret = False;
+       bool ret = False;
        /* Create a new ACL with only 3 entries, u/g/w. */
        SMB_ACL_T new_file_acl = SMB_VFS_SYS_ACL_INIT(conn, 3);
        SMB_ACL_ENTRY_T user_ent = NULL;
@@ -4086,7 +4090,7 @@ 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 char *fname, uint16 num_acls, const char *pdata)
 {
        SMB_ACL_T file_acl = NULL;
 
@@ -4122,291 +4126,82 @@ BOOL set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *
 }
 
 /****************************************************************************
- Check for POSIX group ACLs. If none use stat entry.
- Return -1 if no match, 0 if match and denied, 1 if match and allowed.
+ Helper function that gets a security descriptor by connection and
+ file name.
+ NOTE: This is transitional, in the sense that SMB_VFS_GET_NT_ACL really
+ should *not* get a files_struct pointer but a connection_struct ptr
+ (automatic by the vfs handle) and the file name and _use_ that!
 ****************************************************************************/
-
-static int check_posix_acl_group_access(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint32 access_mask)
+static NTSTATUS conn_get_nt_acl(TALLOC_CTX *mem_ctx,
+                               struct connection_struct *conn,
+                               const char *fname,
+                               SMB_STRUCT_STAT *psbuf,
+                               struct security_descriptor **psd)
 {
-       SMB_ACL_T posix_acl = NULL;
-       int entry_id = SMB_ACL_FIRST_ENTRY;
-       SMB_ACL_ENTRY_T entry;
-       int i;
-       BOOL seen_mask = False;
-       BOOL seen_owning_group = False;
-       int ret = -1;
-       gid_t cu_gid;
-
-       DEBUG(10,("check_posix_acl_group_access: requesting 0x%x on file %s\n",
-               (unsigned int)access_mask, fname ));
-
-       if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS)) == NULL) {
-               goto check_stat;
-       }
-
-       /* First ensure the group mask allows group access. */
-       /* Also check any user entries (these take preference over group). */
-
-       while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
-               SMB_ACL_TAG_T tagtype;
-               SMB_ACL_PERMSET_T permset;
-               int have_write = -1;
-               int have_read = -1;
-
-               /* get_next... */
-               if (entry_id == SMB_ACL_FIRST_ENTRY)
-                       entry_id = SMB_ACL_NEXT_ENTRY;
-
-               if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
-                       goto check_stat;
-               }
-
-               if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
-                       goto check_stat;
-               }
-
-               have_read = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ);
-               if (have_read == -1) {
-                       goto check_stat;
-               }
+       NTSTATUS status;
+       struct files_struct *fsp = NULL;
+       struct security_descriptor *secdesc = NULL;
+       size_t secdesc_size;
 
-               have_write = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE);
-               if (have_write == -1) {
-                       goto check_stat;
+       if (!VALID_STAT(*psbuf)) {
+               if (SMB_VFS_STAT(conn, fname, psbuf) != 0) {
+                       return map_nt_error_from_unix(errno);
                }
+       }
 
-               /*
-                * Solaris returns 2 for this if write is available.
-                * canonicalize to 0 or 1.
-                */     
-               have_write = (have_write ? 1 : 0);
-               have_read = (have_read ? 1 : 0);
+       /* fake a files_struct ptr: */
 
-               switch(tagtype) {
-                       case SMB_ACL_MASK:
-                               seen_mask = True;
-                               switch (access_mask) {
-                                       case FILE_READ_DATA:
-                                               if (!have_read) {
-                                                       ret = -1;
-                                                       DEBUG(10,("check_posix_acl_group_access: file %s "
-                                                               "refusing read due to mask.\n", fname));
-                                                       goto done;
-                                               }
-                                               break;
-                                       case FILE_WRITE_DATA:
-                                               if (!have_write) {
-                                                       ret = -1;
-                                                       DEBUG(10,("check_posix_acl_group_access: file %s "
-                                                               "refusing write due to mask.\n", fname));
-                                                       goto done;
-                                               }
-                                               break;
-                                       default: /* FILE_READ_DATA|FILE_WRITE_DATA */
-                                               if (!have_write || !have_read) {
-                                                       ret = -1;
-                                                       DEBUG(10,("check_posix_acl_group_access: file %s "
-                                                               "refusing read/write due to mask.\n", fname));
-                                                       goto done;
-                                               }
-                                               break;
-                               }
-                               break;
-                       case SMB_ACL_USER:
-                       {
-                               /* Check against current_user.ut.uid. */
-                               uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
-                               if (puid == NULL) {
-                                       goto check_stat;
-                               }
-                               if (current_user.ut.uid == *puid) {
-                                       /* We have a uid match but we must ensure we have seen the acl mask. */
-                                       switch (access_mask) {
-                                               case FILE_READ_DATA:
-                                                       ret = have_read;
-                                                       break;
-                                               case FILE_WRITE_DATA:
-                                                       ret = have_write;
-                                                       break;
-                                               default: /* FILE_READ_DATA|FILE_WRITE_DATA */
-                                                       ret = (have_write & have_read);
-                                                       break;
-                                       }
-                                       DEBUG(10,("check_posix_acl_group_access: file %s "
-                                               "match on user %u -> %s.\n",
-                                               fname, (unsigned int)*puid,
-                                               ret ? "can access" : "cannot access"));
-                                       if (seen_mask) {
-                                               goto done;
-                                       }
-                               }
-                               break;
-                       }
-                       default:
-                               continue;
-               }
+       status = open_file_stat(conn, NULL, fname, psbuf, &fsp);
+       /* Perhaps it is a directory */
+       if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
+               status = open_directory(conn, NULL, fname, psbuf,
+                                       READ_CONTROL_ACCESS,
+                                       FILE_SHARE_READ|FILE_SHARE_WRITE,
+                                       FILE_OPEN,
+                                       0,
+                                       FILE_ATTRIBUTE_DIRECTORY,
+                                       NULL, &fsp);
        }
-
-       /* If ret is anything other than -1 we matched on a user entry. */
-       if (ret != -1) {
-               goto done;
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(3, ("Unable to open file %s: %s\n", fname,
+                         nt_errstr(status)));
+               return status;
        }
 
-       /* Next check all group entries. */
-       entry_id = SMB_ACL_FIRST_ENTRY;
-       while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
-               SMB_ACL_TAG_T tagtype;
-               SMB_ACL_PERMSET_T permset;
-               int have_write = -1;
-               int have_read = -1;
-
-               /* get_next... */
-               if (entry_id == SMB_ACL_FIRST_ENTRY)
-                       entry_id = SMB_ACL_NEXT_ENTRY;
-
-               if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
-                       goto check_stat;
-               }
-
-               if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
-                       goto check_stat;
-               }
-
-               have_read = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ);
-               if (have_read == -1) {
-                       goto check_stat;
-               }
-
-               have_write = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE);
-               if (have_write == -1) {
-                       goto check_stat;
-               }
-
-               /*
-                * Solaris returns 2 for this if write is available.
-                * canonicalize to 0 or 1.
-                */     
-               have_write = (have_write ? 1 : 0);
-               have_read = (have_read ? 1 : 0);
-
-               switch(tagtype) {
-                       case SMB_ACL_GROUP:
-                       case SMB_ACL_GROUP_OBJ:
-                       {
-                               gid_t *pgid = NULL;
-
-                               if (tagtype == SMB_ACL_GROUP) {
-                                       pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
-                               } else {
-                                       seen_owning_group = True;
-                                       pgid = &psbuf->st_gid;
-                               }
-                               if (pgid == NULL) {
-                                       goto check_stat;
-                               }
-
-                               /*
-                                * Does it match the current effective group
-                                * or supplementary groups ?
-                                */
-                               for (cu_gid = get_current_user_gid_first(&i); cu_gid != (gid_t)-1;
-                                                       cu_gid = get_current_user_gid_next(&i)) {
-                                       if (cu_gid == *pgid) {
-                                               switch (access_mask) {
-                                                       case FILE_READ_DATA:
-                                                               ret = have_read;
-                                                               break;
-                                                       case FILE_WRITE_DATA:
-                                                               ret = have_write;
-                                                               break;
-                                                       default: /* FILE_READ_DATA|FILE_WRITE_DATA */
-                                                               ret = (have_write & have_read);
-                                                               break;
-                                               }
-
-                                               DEBUG(10,("check_posix_acl_group_access: file %s "
-                                                       "match on group %u -> can access.\n",
-                                                       fname, (unsigned int)cu_gid ));
-
-                                               /* If we don't have access permission this entry doesn't
-                                                       terminate the enumeration of the entries. */
-                                               if (ret) {
-                                                       goto done;
-                                               }
-                                               /* But does terminate the group iteration. */
-                                               break;
-                                       }
-                               }
-                               break;
-                       }
-                       default:
-                               continue;
-               }
+       secdesc_size = SMB_VFS_GET_NT_ACL(fsp, fname,
+                                         (OWNER_SECURITY_INFORMATION |
+                                          GROUP_SECURITY_INFORMATION |
+                                          DACL_SECURITY_INFORMATION),
+                                         &secdesc);
+       if (secdesc_size == 0) {
+               DEBUG(5, ("Unable to get NT ACL for file %s\n", fname));
+               return NT_STATUS_ACCESS_DENIED;
        }
 
-       /* If ret is -1 here we didn't match on the user entry or
-          supplemental group entries. */
-       
-       DEBUG(10,("check_posix_acl_group_access: ret = %d before check_stat:\n", ret));
-
-  check_stat:
-
-       /*
-        * We only check the S_I[RW]GRP permissions if we haven't already
-        * seen an owning group SMB_ACL_GROUP_OBJ ace entry. If there is an
-        * SMB_ACL_GROUP_OBJ ace entry then the group bits in st_gid are
-        * the same as the SMB_ACL_MASK bits, not the SMB_ACL_GROUP_OBJ
-        * bits. Thanks to Marc Cousin <mcousin@sigma.fr> for pointing
-        * this out. JRA.
-        */
-
-       if (!seen_owning_group) {
-               /* Do we match on the owning group entry ? */
-               /*
-                * Does it match the current effective group
-                * or supplementary groups ?
-                */
-               for (cu_gid = get_current_user_gid_first(&i); cu_gid != (gid_t)-1;
-                                               cu_gid = get_current_user_gid_next(&i)) {
-                       if (cu_gid == psbuf->st_gid) {
-                               switch (access_mask) {
-                                       case FILE_READ_DATA:
-                                               ret = (psbuf->st_mode & S_IRGRP) ? 1 : 0;
-                                               break;
-                                       case FILE_WRITE_DATA:
-                                               ret = (psbuf->st_mode & S_IWGRP) ? 1 : 0;
-                                               break;
-                                       default: /* FILE_READ_DATA|FILE_WRITE_DATA */
-                                               if ((psbuf->st_mode & (S_IWGRP|S_IRGRP)) == (S_IWGRP|S_IRGRP)) {
-                                                       ret = 1;
-                                               } else {
-                                                       ret = 0;
-                                               }
-                                               break;
-                               }
-                               DEBUG(10,("check_posix_acl_group_access: file %s "
-                                       "match on owning group %u -> %s.\n",
-                                       fname, (unsigned int)psbuf->st_gid,
-                                       ret ? "can access" : "cannot access"));
-                               break;
-                       }
-               }
-
-               if (cu_gid == (gid_t)-1) {
-                       DEBUG(10,("check_posix_acl_group_access: file %s "
-                               "failed to match on user or group in token (ret = %d).\n",
-                               fname, ret ));
-               }
-       }
+       *psd = talloc_move(mem_ctx, &secdesc);
+       close_file(fsp, NORMAL_CLOSE);
+       return NT_STATUS_OK;
+}
 
-  done:
+static bool can_access_file_acl(struct connection_struct *conn,
+                               const char * fname, SMB_STRUCT_STAT *psbuf,
+                               uint32_t access_mask)
+{
+       bool result;
+       NTSTATUS status;
+       uint32_t access_granted;
+       struct security_descriptor *secdesc = NULL;
 
-       if (posix_acl) {
-               SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
+       status = conn_get_nt_acl(talloc_tos(), conn, fname, psbuf, &secdesc);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(5, ("Could not get acl: %s\n", nt_errstr(status)));
+               return false;
        }
 
-       DEBUG(10,("check_posix_acl_group_access: file %s returning (ret = %d).\n", fname, ret ));
-       return ret;
+       result = se_access_check(secdesc, current_user.nt_user_token,
+                                access_mask, &access_granted, &status);
+       TALLOC_FREE(secdesc);
+       return result;
 }
 
 /****************************************************************************
@@ -4414,21 +4209,29 @@ static int check_posix_acl_group_access(connection_struct *conn, const char *fna
  this to successfully return ACCESS_DENIED on a file open for delete access.
 ****************************************************************************/
 
-BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname)
+bool can_delete_file_in_directory(connection_struct *conn, const char *fname)
 {
-       SMB_STRUCT_STAT sbuf;  
-       pstring dname;
-       int ret;
+       SMB_STRUCT_STAT sbuf;
+       TALLOC_CTX *ctx = talloc_tos();
+       char *dname = NULL;
 
        if (!CAN_WRITE(conn)) {
                return False;
        }
 
        /* Get the parent directory permission mask and owners. */
-       pstrcpy(dname, parent_dirname(fname));
+       if (!parent_dirname_talloc(ctx,
+                               fname,
+                               &dname,
+                               NULL)) {
+               return False;
+       }
        if(SMB_VFS_STAT(conn, dname, &sbuf) != 0) {
                return False;
        }
+
+       /* fast paths first */
+
        if (!S_ISDIR(sbuf.st_mode)) {
                return False;
        }
@@ -4445,7 +4248,7 @@ BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname)
 #ifdef S_ISVTX
        /* sticky bit means delete only by owner or root. */
        if (sbuf.st_mode & S_ISVTX) {
-               SMB_STRUCT_STAT sbuf_file;  
+               SMB_STRUCT_STAT sbuf_file;
                if(SMB_VFS_STAT(conn, fname, &sbuf_file) != 0) {
                        if (errno == ENOENT) {
                                /* If the file doesn't already exist then
@@ -4465,14 +4268,9 @@ BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname)
        }
 #endif
 
-       /* Check group or explicit user acl entry write access. */
-       ret = check_posix_acl_group_access(conn, dname, &sbuf, FILE_WRITE_DATA);
-       if (ret == 0 || ret == 1) {
-               return ret ? True : False;
-       }
+       /* now for ACL checks */
 
-       /* Finally check other write access. */
-       return (sbuf.st_mode & S_IWOTH) ? True : False;
+       return can_access_file(conn, dname, &sbuf, FILE_WRITE_DATA);
 }
 
 /****************************************************************************
@@ -4481,15 +4279,15 @@ BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname)
  Note this doesn't take into account share write permissions.
 ****************************************************************************/
 
-BOOL can_access_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint32 access_mask)
+bool can_access_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf, uint32 access_mask)
 {
-       int ret;
-
        if (!(access_mask & (FILE_READ_DATA|FILE_WRITE_DATA))) {
                return False;
        }
        access_mask &= (FILE_READ_DATA|FILE_WRITE_DATA);
 
+       /* some fast paths first */
+
        DEBUG(10,("can_access_file: requesting 0x%x on file %s\n",
                (unsigned int)access_mask, fname ));
 
@@ -4524,27 +4322,9 @@ BOOL can_access_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT
                }
        }
 
-       /* Check group or explicit user acl entry access. */
-       ret = check_posix_acl_group_access(conn, fname, psbuf, access_mask);
-       if (ret == 0 || ret == 1) {
-               return ret ? True : False;
-       }
-
-       /* Finally check other access. */
-       switch (access_mask) {
-               case FILE_READ_DATA:
-                       return (psbuf->st_mode & S_IROTH) ? True : False;
-
-               case FILE_WRITE_DATA:
-                       return (psbuf->st_mode & S_IWOTH) ? True : False;
-
-               default: /* FILE_READ_DATA|FILE_WRITE_DATA */
+       /* now for ACL checks */
 
-                       if ((psbuf->st_mode & (S_IWOTH|S_IROTH)) == (S_IWOTH|S_IROTH)) {
-                               return True;
-                       }
-       }
-       return False;
+       return can_access_file_acl(conn, fname, psbuf, access_mask);
 }
 
 /****************************************************************************
@@ -4552,7 +4332,7 @@ BOOL can_access_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT
  Note this doesn't take into account share write permissions.
 ****************************************************************************/
 
-BOOL can_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf)
+bool can_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf)
 {
        return can_access_file(conn, fname, psbuf, FILE_WRITE_DATA);
 }
@@ -4563,21 +4343,19 @@ BOOL can_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_ST
  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().
+
  Assume we are dealing with files (for now)
 ********************************************************************/
 
-SEC_DESCget_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
+SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
 {
        SEC_DESC *psd, *ret_sd;
        connection_struct conn;
        files_struct finfo;
        struct fd_handle fh;
-       pstring path;
-       pstring filename;
-       
+
        ZERO_STRUCT( conn );
-       
+
        if ( !(conn.mem_ctx = talloc_init( "novfs_get_nt_acl" )) ) {
                DEBUG(0,("get_nt_acl_no_snum: talloc() failed!\n"));
                return NULL;
@@ -4590,35 +4368,33 @@ SEC_DESC* get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
        }
 
        conn.params->service = -1;
-       
-       pstrcpy( path, "/" );
-       set_conn_connectpath(&conn, path);
-       
+
+       set_conn_connectpath(&conn, "/");
+
        if (!smbd_vfs_init(&conn)) {
                DEBUG(0,("get_nt_acl_no_snum: Unable to create a fake connection struct!\n"));
                conn_free_internal( &conn );
                return NULL;
         }
-       
+
        ZERO_STRUCT( finfo );
        ZERO_STRUCT( fh );
-       
+
        finfo.fnum = -1;
        finfo.conn = &conn;
        finfo.fh = &fh;
        finfo.fh->fd = -1;
-       pstrcpy( filename, fname );
-       finfo.fsp_name = filename;
-       
+       finfo.fsp_name = CONST_DISCARD(char *,fname);
+
        if (get_nt_acl( &finfo, DACL_SECURITY_INFORMATION, &psd ) == 0) {
                DEBUG(0,("get_nt_acl_no_snum: get_nt_acl returned zero.\n"));
                conn_free_internal( &conn );
                return NULL;
        }
-       
+
        ret_sd = dup_sec_desc( ctx, psd );
-       
+
        conn_free_internal( &conn );
-       
+
        return ret_sd;
 }