diff options
author | Jeremy Allison <jra@samba.org> | 2001-01-10 01:53:31 +0000 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2001-01-10 01:53:31 +0000 |
commit | 3713104dbebef8f02244e7c5a9e7bc9840c75c14 (patch) | |
tree | 3e871151b601741742dff8a02d0e1939775738ef | |
parent | 5fbc8f63f5b48a8d5b4350e6b380f83c9d56c98b (diff) | |
download | samba-3713104dbebef8f02244e7c5a9e7bc9840c75c14.tar.gz samba-3713104dbebef8f02244e7c5a9e7bc9840c75c14.tar.xz samba-3713104dbebef8f02244e7c5a9e7bc9840c75c14.zip |
Latest snapshot of POSIX ACL support (note this is not yet compiled in).
Jeremy.
-rw-r--r-- | source/smbd/posix_acls.c | 1093 |
1 files changed, 785 insertions, 308 deletions
diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c index b463ec24794..325fefec3bb 100644 --- a/source/smbd/posix_acls.c +++ b/source/smbd/posix_acls.c @@ -1,4 +1,3 @@ -#ifdef HAVE_POSIX_ACLS #define OLD_NTDOMAIN 1 /* Unix SMB/Netbios implementation. @@ -23,6 +22,43 @@ #include "includes.h" +enum ace_owner {UID_ACE, GID_ACE, WORLD_ACE}; + +typedef union posix_id { + uid_t uid; + gid_t gid; + int world; +} posix_id; + +typedef struct canon_ace { + struct canon_ace *next, *prev; + SMB_ACL_TAG_T type; + mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */ + DOM_SID sid; + enum ace_owner owner_type; + posix_id unix_ug; +} canon_ace; + +static void free_canon_ace_list( canon_ace *list_head ); + +#if 0 +/**************************************************************************** + Function to duplicate a canon_ace struct. +****************************************************************************/ + +static canon_ace *dup_canon_ace( canon_ace *c_ace) +{ + canon_ace *new_ace = (canon_ace *)malloc(sizeof(canon_ace)); + + if (new_ace == NULL) + return NULL; + + *new_ace = *c_ace; + + return new_ace; +} +#endif + /**************************************************************************** Function to create owner and group SIDs from a SMB_STRUCT_STAT. ****************************************************************************/ @@ -34,132 +70,308 @@ static void create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SI } /**************************************************************************** - Map unix perms to NT. + Map canon_ace perms to permission bits NT. ****************************************************************************/ -static SEC_ACCESS map_unix_perms( int *pacl_type, mode_t perm, int r_mask, int w_mask, int x_mask, BOOL is_directory) +static SEC_ACCESS map_canon_ace_perms(int *pacl_type, DOM_SID *powner_sid, canon_ace *ace) { SEC_ACCESS sa; uint32 nt_mask = 0; *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED; - if((perm & (r_mask|w_mask|x_mask)) == (r_mask|w_mask|x_mask)) { - nt_mask = UNIX_ACCESS_RWX; - } else if((perm & (r_mask|w_mask|x_mask)) == 0) { - nt_mask = UNIX_ACCESS_NONE; + if((ace->perms & (S_IRWXU|S_IWUSR|S_IXUSR)) == (S_IRWXU|S_IWUSR|S_IXUSR)) { + nt_mask = UNIX_ACCESS_RWX; + } else if((ace->perms & (S_IRWXU|S_IWUSR|S_IXUSR)) == 0) { + /* + * Here we differentiate between the owner and any other user. + */ + if (sid_equal(powner_sid, &ace->sid)) { + nt_mask = UNIX_ACCESS_NONE; + } else { + /* Not owner, no access. */ + nt_mask = 0; + } } else { - nt_mask |= (perm & r_mask) ? UNIX_ACCESS_R : 0; - if(is_directory) - nt_mask |= (perm & w_mask) ? UNIX_ACCESS_W : 0; - else - nt_mask |= (perm & w_mask) ? UNIX_ACCESS_W : 0; - nt_mask |= (perm & x_mask) ? UNIX_ACCESS_X : 0; + nt_mask |= ((ace->perms & S_IRWXU) ? UNIX_ACCESS_R : 0 ); + nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_ACCESS_W : 0 ); + nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_ACCESS_X : 0 ); } + + DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n", + (unsigned int)ace->perms, (unsigned int)nt_mask )); + init_sec_access(&sa,nt_mask); return sa; } /**************************************************************************** - Validate a SID. + Map NT perms to a UNIX mode_t. ****************************************************************************/ -static BOOL validate_unix_sid( DOM_SID *psid, uint32 *prid, DOM_SID *sd_sid) +#define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES) +#define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES) +#define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE) + +static mode_t map_nt_perms( SEC_ACCESS sec_access, int type) { - extern DOM_SID global_sam_sid; - DOM_SID sid; + mode_t mode = 0; + + switch(type) { + case S_IRUSR: + if(sec_access.mask & GENERIC_ALL_ACCESS) + mode = S_IRUSR|S_IWUSR|S_IXUSR; + else { + mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0; + mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0; + mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0; + } + break; + case S_IRGRP: + if(sec_access.mask & GENERIC_ALL_ACCESS) + mode = S_IRGRP|S_IWGRP|S_IXGRP; + else { + mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0; + mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0; + mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0; + } + break; + case S_IROTH: + if(sec_access.mask & GENERIC_ALL_ACCESS) + mode = S_IROTH|S_IWOTH|S_IXOTH; + else { + mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0; + mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0; + mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0; + } + break; + } - if(!sd_sid) { - DEBUG(5,("validate_unix_sid: sid missing.\n")); - return False; - } + return mode; +} - sid_copy(psid, sd_sid); - sid_copy(&sid, sd_sid); +/**************************************************************************** + Unpack a SEC_DESC into a UNIX owner and group. +****************************************************************************/ - if(!sid_split_rid(&sid, prid)) { - DEBUG(5,("validate_unix_sid: cannot get RID from sid.\n")); - return False; - } +static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd) +{ + DOM_SID owner_sid; + DOM_SID grp_sid; + enum SID_NAME_USE sid_type; - if(!sid_equal( &sid, &global_sam_sid)) { - DEBUG(5,("validate_unix_sid: sid is not ours.\n")); - return False; - } + *puser = (uid_t)-1; + *pgrp = (gid_t)-1; - return True; + if(security_info_sent == 0) { + DEBUG(0,("unpack_nt_owners: no security info sent !\n")); + return False; + } + + /* + * 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")); + + /* + * Don't immediately fail if the owner sid cannot be validated. + * This may be a group chown only set. + */ + + if (security_info_sent & OWNER_SECURITY_INFORMATION) { + sid_copy(&owner_sid, psd->owner_sid); + if (!sid_to_uid( &owner_sid, puser, &sid_type)) + DEBUG(3,("unpack_nt_owners: unable to validate owner sid.\n")); + } + + /* + * Don't immediately fail if the group sid cannot be validated. + * This may be an owner chown only set. + */ + + if (security_info_sent & GROUP_SECURITY_INFORMATION) { + sid_copy(&grp_sid, psd->grp_sid); + if (!sid_to_gid( &grp_sid, pgrp, &sid_type)) + DEBUG(3,("unpack_nt_owners: unable to validate group sid.\n")); + } + + return True; } /**************************************************************************** - Map NT perms to UNIX. + Unpack a SEC_DESC into two canonical ace lists. We don't depend on this + succeeding. ****************************************************************************/ -#define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES) -#define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES) -#define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE) - -static mode_t map_nt_perms( SEC_ACCESS sec_access, int type) +static BOOL unpack_canon_ace(files_struct *fsp, + DOM_SID *pfile_owner_sid, + DOM_SID *pfile_grp_sid, + canon_ace **ppfile_ace, canon_ace **ppdir_ace, + uint32 security_info_sent, SEC_DESC *psd) { - mode_t mode = 0; - - switch(type) { - case S_IRUSR: - if(sec_access.mask & GENERIC_ALL_ACCESS) - mode = S_IRUSR|S_IWUSR|S_IXUSR; - else { - mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0; - mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0; - mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0; - } - break; - case S_IRGRP: - if(sec_access.mask & GENERIC_ALL_ACCESS) - mode = S_IRGRP|S_IWGRP|S_IXGRP; - else { - mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0; - mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0; - mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0; - } - break; - case S_IROTH: - if(sec_access.mask & GENERIC_ALL_ACCESS) - mode = S_IROTH|S_IWOTH|S_IXOTH; - else { - mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0; - mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0; - mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0; - } - break; - } + extern DOM_SID global_sid_World; + SEC_ACL *dacl = psd->dacl; + BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False); + canon_ace *file_ace = NULL; + canon_ace *dir_ace = NULL; + enum SID_NAME_USE sid_type; + int i; + + *ppfile_ace = NULL; + *ppdir_ace = NULL; + + if(security_info_sent == 0) { + DEBUG(0,("unpack_canon_ace: no security info sent !\n")); + return False; + } + + /* + * If no DACL then this is a chown only security descriptor. + */ + + if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !dacl) + return True; + + /* + * Now go through the DACL and create the canon_ace lists. + */ + + for(i = 0; i < dacl->num_aces; i++) { + SEC_ACE *psa = &dacl->ace[i]; + canon_ace *current_ace = NULL; + + if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) { + DEBUG(3,("unpack_canon_ace: unable to set anything but an ALLOW or DENY ACE.\n")); + return False; + } + + /* + * 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. + */ + + psa->info.mask &= (GENERIC_ALL_ACCESS|GENERIC_EXECUTE_ACCESS|GENERIC_WRITE_ACCESS| + GENERIC_READ_ACCESS|UNIX_ACCESS_NONE|FILE_ALL_ATTRIBUTES); + + if(psa->info.mask != UNIX_ACCESS_NONE) + psa->info.mask &= ~UNIX_ACCESS_NONE; - return mode; + /* + * Create a cannon_ace entry representing this NT DACL ACE. + */ + + if ((current_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) { + free_canon_ace_list(file_ace); + free_canon_ace_list(dir_ace); + DEBUG(0,("unpack_canon_ace: malloc fail.\n")); + return False; + } + + ZERO_STRUCTP(current_ace); + + sid_copy(¤t_ace->sid, &psa->sid); + + /* + * Try and work out if the SID is a user or group + * as we need to flag these differently for POSIX. + */ + + if( sid_equal(¤t_ace->sid, &global_sid_World)) { + current_ace->owner_type = WORLD_ACE; + current_ace->unix_ug.world = -1; + } else if (sid_to_uid( ¤t_ace->sid, ¤t_ace->unix_ug.uid, &sid_type)) { + current_ace->owner_type = UID_ACE; + } else if (sid_to_gid( ¤t_ace->sid, ¤t_ace->unix_ug.gid, &sid_type)) { + current_ace->owner_type = GID_ACE; + } else { + fstring str; + + free_canon_ace_list(file_ace); + free_canon_ace_list(dir_ace); + free(current_ace); + DEBUG(0,("unpack_canon_ace: unable to map SID %s to uid or gid.\n", + sid_to_string(str, ¤t_ace->sid) )); + return False; + } + + /* + * Map the given NT permissions into a UNIX mode_t containing only + * S_I(R|W|X)USR bits. + */ + + if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) + current_ace->perms |= map_nt_perms( psa->info, S_IRUSR); + else + current_ace->perms &= ~(map_nt_perms( psa->info, S_IRUSR)); + + /* + * Now note what kind of a POSIX ACL this should map to. + */ + + if(sid_equal(¤t_ace->sid, pfile_owner_sid)) { + current_ace->type = SMB_ACL_USER_OBJ; + } else if( sid_equal(¤t_ace->sid, pfile_grp_sid)) { + current_ace->type = SMB_ACL_GROUP_OBJ; + } else if( sid_equal(¤t_ace->sid, &global_sid_World)) { + current_ace->type = SMB_ACL_OTHER; + } else { + /* + * Could be a SMB_ACL_USER or SMB_ACL_GROUP. Check by + * looking at owner_type. + */ + + current_ace->type = current_ace->owner_type == UID_ACE ? SMB_ACL_USER : SMB_ACL_GROUP; + } + + if (fsp->is_directory && (psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) { + DLIST_ADD(dir_ace, current_ace); + } else { + DLIST_ADD(file_ace, current_ace); + all_aces_are_inherit_only = False; + } + } + + if (fsp->is_directory && all_aces_are_inherit_only) { + /* + * Windows 2000 is doing one of these weird 'inherit acl' + * traverses to conserve NTFS ACL resources. Just pretend + * there was no DACL sent. JRA. + */ + + DEBUG(10,("unpack_posix_permissions: Win2k inherit acl traverse. Ignoring DACL.\n")); + free_sec_acl(&psd->dacl); + } + + *ppfile_ace = file_ace; + *ppdir_ace = dir_ace; + return True; } /**************************************************************************** - Unpack a SEC_DESC into a owner, group and set of UNIX permissions. + Unpack a SEC_DESC into a set of standard POSIX permissions. ****************************************************************************/ -static BOOL unpack_nt_permissions(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, mode_t *pmode, - uint32 security_info_sent, SEC_DESC *psd, BOOL is_directory) +static BOOL unpack_posix_permissions(files_struct *fsp, SMB_STRUCT_STAT *psbuf, mode_t *pmode, + uint32 security_info_sent, SEC_DESC *psd) { extern DOM_SID global_sid_World; - DOM_SID owner_sid; - DOM_SID grp_sid; + connection_struct *conn = fsp->conn; DOM_SID file_owner_sid; DOM_SID file_grp_sid; - uint32 owner_rid; - uint32 grp_rid; SEC_ACL *dacl = psd->dacl; - BOOL all_aces_are_inherit_only = (is_directory ? True : False); + BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False); int i; - enum SID_NAME_USE sid_type; *pmode = 0; - *puser = (uid_t)-1; - *pgrp = (gid_t)-1; if(security_info_sent == 0) { - DEBUG(0,("unpack_nt_permissions: no security info sent !\n")); + DEBUG(0,("unpack_posix_permissions: no security info sent !\n")); return False; } @@ -173,35 +385,6 @@ static BOOL unpack_nt_permissions(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *p create_file_sids(psbuf, &file_owner_sid, &file_grp_sid); /* - * 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_permissions: validating owner_sid.\n")); - - /* - * Don't immediately fail if the owner sid cannot be validated. - * This may be a group chown only set. - */ - - if (security_info_sent & OWNER_SECURITY_INFORMATION) { - if (!sid_to_uid( &owner_sid, puser, &sid_type)) - DEBUG(3,("unpack_nt_permissions: unable to validate owner sid.\n")); - } - - /* - * Don't immediately fail if the group sid cannot be validated. - * This may be an owner chown only set. - */ - - if (security_info_sent & GROUP_SECURITY_INFORMATION) { - if (!sid_to_gid( &grp_sid, pgrp, &sid_type)) - DEBUG(3,("unpack_nt_permissions: unable to validate group sid.\n")); - } - - /* * If no DACL then this is a chown only security descriptor. */ @@ -221,7 +404,7 @@ static BOOL unpack_nt_permissions(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *p if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) { - DEBUG(3,("unpack_nt_permissions: unable to set anything but an ALLOW or DENY ACE.\n")); + DEBUG(3,("unpack_posix_permissions: unable to set anything but an ALLOW or DENY ACE.\n")); return False; } @@ -229,9 +412,9 @@ static BOOL unpack_nt_permissions(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *p * Ignore or remove bits we don't care about on a directory ACE. */ - if(is_directory) { + if(fsp->is_directory) { if(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY) { - DEBUG(3,("unpack_nt_permissions: ignoring inherit only ACE.\n")); + DEBUG(3,("unpack_posix_permissions: ignoring inherit only ACE.\n")); continue; } @@ -252,7 +435,7 @@ static BOOL unpack_nt_permissions(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *p psa->flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT); if(psa->flags != 0) { - DEBUG(1,("unpack_nt_permissions: unable to set ACE flags (%x).\n", + DEBUG(1,("unpack_posix_permissions: unable to set ACE flags (%x).\n", (unsigned int)psa->flags)); return False; } @@ -303,52 +486,324 @@ static BOOL unpack_nt_permissions(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *p *pmode &= ~(map_nt_perms( psa->info, S_IROTH)); } else { - DEBUG(0,("unpack_nt_permissions: unknown SID used in ACL.\n")); + DEBUG(0,("unpack_posix_permissions: unknown SID used in ACL.\n")); return False; } } - if (is_directory && all_aces_are_inherit_only) { + if (fsp->is_directory && all_aces_are_inherit_only) { /* * Windows 2000 is doing one of these weird 'inherit acl' * traverses to conserve NTFS ACL resources. Just pretend * there was no DACL sent. JRA. */ - DEBUG(10,("unpack_nt_permissions: Win2k inherit acl traverse. Ignoring DACL.\n")); + DEBUG(10,("unpack_posix_permissions: Win2k inherit acl traverse. Ignoring DACL.\n")); free_sec_acl(&psd->dacl); } + /* + * Check to see if we need to change anything. + * Enforce limits on modified bits *only*. Don't enforce masks + * on bits not changed by the user. + */ + + if(fsp->is_directory) { + + *pmode &= (lp_dir_security_mask(SNUM(conn)) | psbuf->st_mode); + *pmode |= (lp_force_dir_security_mode(SNUM(conn)) & ( *pmode ^ psbuf->st_mode )); + + } else { + + *pmode &= (lp_security_mask(SNUM(conn)) | psbuf->st_mode); + *pmode |= (lp_force_security_mode(SNUM(conn)) & ( *pmode ^ psbuf->st_mode )); + + } + + /* + * Preserve special bits. + */ + + *pmode |= (psbuf->st_mode & ~0777); + return True; } /**************************************************************************** - Go through the ACL entries one by one, count them and extract the permset - of the mask entry as we scan the acl. + Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits). ****************************************************************************/ -size_t get_num_posix_entries(acl_t posix_acl, acl_permset_t *posix_mask) +static mode_t convert_permset_to_mode_t(SMB_ACL_PERMSET_T permset) { - size_t num_entries; - acl_entry_t entry; - int entry_id = ACL_FIRST_ENTRY; + mode_t ret = 0; - *posix_mask = (ACL_READ|ACL_WRITE|ACL_EXECUTE); + 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); - for( num_entries = 0; acl_get_entry(posix_acl, entry_id, &entry) != -1; num_entries++) { - acl_tag_t tagtype; - acl_permset_t permset; + return ret; +} + +/**************************************************************************** + Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits). +****************************************************************************/ + +static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask) +{ + mode_t ret = 0; + + if (mode & r_mask) + ret |= S_IRUSR; + if (mode & w_mask) + ret |= S_IWUSR; + if (mode & x_mask) + ret |= S_IXUSR; + + return ret; +} + +/**************************************************************************** + Count a linked list of canonical ACE entries. +****************************************************************************/ + +static size_t count_canon_ace_list( canon_ace *list_head ) +{ + size_t count = 0; + canon_ace *ace; + + for (ace = list_head; ace; ace = ace->next) + count++; + + return count; +} + +/**************************************************************************** + Free a linked list of canonical ACE entries. +****************************************************************************/ - entry_id = ACL_NEXT_ENTRY; - if (acl_get_tag_type(entry, &tagtype) == -1) +static void free_canon_ace_list( canon_ace *list_head ) +{ + while (list_head) { + canon_ace *old_head = list_head; + DLIST_REMOVE(list_head, list_head); + free(old_head); + } +} + +/****************************************************************************** + Fall back to the generic 3 element UNIX permissions. +********************************************************************************/ + +static canon_ace *unix_canonicalise_acl(files_struct *fsp, SMB_STRUCT_STAT *psbuf, + DOM_SID *powner, DOM_SID *pgroup) +{ + extern DOM_SID global_sid_World; + canon_ace *list_head = NULL; + canon_ace *owner_ace = NULL; + canon_ace *group_ace = NULL; + canon_ace *other_ace = NULL; + + /* + * Create 3 linked list entries. + */ + + if ((owner_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) + goto fail; + + if ((group_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) + goto fail; + + if ((other_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) + goto fail; + + ZERO_STRUCTP(owner_ace); + ZERO_STRUCTP(group_ace); + ZERO_STRUCTP(other_ace); + + owner_ace->type = SMB_ACL_USER_OBJ; + owner_ace->sid = *powner; + owner_ace->unix_ug.uid = psbuf->st_uid; + owner_ace->owner_type = UID_ACE; + + group_ace->type = SMB_ACL_GROUP_OBJ; + group_ace->sid = *pgroup; + owner_ace->unix_ug.gid = psbuf->st_gid; + owner_ace->owner_type = GID_ACE; + + other_ace->type = SMB_ACL_OTHER; + other_ace->sid = global_sid_World; + owner_ace->unix_ug.world = -1; + owner_ace->owner_type = WORLD_ACE; + + if (!fsp->is_directory) { + owner_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IRUSR, S_IWUSR, S_IXUSR); + group_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IRGRP, S_IWGRP, S_IXGRP); + other_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IROTH, S_IWOTH, S_IXOTH); + } else { + mode_t mode = unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name); + + owner_ace->perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR); + group_ace->perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP); + other_ace->perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH); + } + + DLIST_ADD(list_head, other_ace); + DLIST_ADD(list_head, group_ace); + DLIST_ADD(list_head, owner_ace); + + return list_head; + + fail: + + safe_free(owner_ace); + safe_free(group_ace); + safe_free(other_ace); + + return NULL; +} + +/**************************************************************************** + Create a linked list of canonical ACE entries. This is sorted so that DENY + entries are at the front of the list, as NT requires. +****************************************************************************/ + +static canon_ace *canonicalise_acl( SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf) +{ + extern DOM_SID global_sid_World; + mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR); + canon_ace *list_head = NULL; + canon_ace *ace = NULL; + canon_ace *next_ace = NULL; + int entry_id = SMB_ACL_FIRST_ENTRY; + SMB_ACL_ENTRY_T entry; + + while ( sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) { + SMB_ACL_TAG_T tagtype; + SMB_ACL_PERMSET_T permset; + DOM_SID sid; + posix_id unix_ug; + enum ace_owner owner_type; + + /* get_next... */ + if (entry_id == SMB_ACL_FIRST_ENTRY) + entry_id = SMB_ACL_NEXT_ENTRY; + + /* Is this a MASK entry ? */ + if (sys_acl_get_tag_type(entry, &tagtype) == -1) continue; - if (tagtype == ACL_MASK) - if (acl_get_permset(entry, &permset) == 0) - *posix_mask = permset; + if (sys_acl_get_permset(entry, &permset) == -1) + continue; + + /* Decide which SID to use based on the ACL type. */ + switch(tagtype) { + case SMB_ACL_USER_OBJ: + /* Get the SID from the owner. */ + uid_to_sid( &sid, psbuf->st_uid ); + unix_ug.uid = psbuf->st_uid; + owner_type = UID_ACE; + break; + case SMB_ACL_USER: + { + 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; + owner_type = UID_ACE; + break; + } + case SMB_ACL_GROUP_OBJ: + /* Get the SID from the owning group. */ + gid_to_sid( &sid, psbuf->st_gid ); + unix_ug.gid = psbuf->st_gid; + owner_type = GID_ACE; + break; + case SMB_ACL_GROUP: + { + 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; + owner_type = GID_ACE; + break; + } + case SMB_ACL_MASK: + 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; + owner_type = WORLD_ACE; + break; + default: + DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype)); + continue; + } + + /* + * Add this entry to the list. + */ + + if ((ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) + goto fail; + + ZERO_STRUCTP(ace); + ace->type = tagtype; + ace->perms = convert_permset_to_mode_t(permset); + ace->sid = sid; + ace->unix_ug = unix_ug; + ace->owner_type = owner_type; + + DLIST_ADD(list_head, ace); + } + + /* + * Now go through the list, masking the permissions with the + * acl_mask. If the permissions are 0 it should be listed + * first. + */ + + for ( ace = list_head; ace; ace = next_ace) { + next_ace = ace->next; + + /* Masks are only applied to entries other than USER_OBJ and OTHER. */ + if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ) + ace->perms &= acl_mask; + + if (ace->perms == 0) + DLIST_PROMOTE(list_head, ace); + } + + if( DEBUGLVL( 10 ) ) { + char *acl_text = sys_acl_to_text( posix_acl, NULL); + + dbgtext("canonicalize_acl: processed acl %s\n", acl_text == NULL ? "NULL" : acl_text ); + if (acl_text) + sys_acl_free_text(acl_text); } - return num_entries; + return list_head; + + fail: + + free_canon_ace_list(list_head); + return NULL; +} + +/**************************************************************************** + 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) +{ + return False; } /**************************************************************************** @@ -360,124 +815,141 @@ size_t get_num_posix_entries(acl_t posix_acl, acl_permset_t *posix_mask) size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) { - extern DOM_SID global_sid_World; SMB_STRUCT_STAT sbuf; - SEC_ACE ace_list[6]; + SEC_ACE *nt_ace_list; DOM_SID owner_sid; DOM_SID group_sid; - size_t sd_size; + size_t sd_size = 0; SEC_ACL *psa = NULL; - SEC_ACCESS owner_access; - int owner_acl_type; - SEC_ACCESS group_access; - int grp_acl_type; - SEC_ACCESS other_access; - int other_acl_type; - int num_acls = 0; - acl_t posix_acl; - + size_t num_acls = 0; + size_t num_dir_acls = 0; + size_t num_aces = 0; + SMB_ACL_T posix_acl = NULL; + SMB_ACL_T dir_acl = NULL; + canon_ace *file_ace = NULL; + canon_ace *dir_ace = NULL; + *ppdesc = NULL; if(fsp->is_directory || fsp->fd == -1) { - if(dos_stat(fsp->fsp_name, &sbuf) != 0) { + + /* Get the stat struct for the owner info. */ + if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0) { return 0; } /* * Get the ACL from the path. */ - if ((posix_acl = acl_get_file( dos_to_unix(fsp->fsp_name, False), ACL_TYPE_ACCESS)) == NULL) - return 0; + posix_acl = sys_acl_get_file( dos_to_unix(fsp->fsp_name, False), SMB_ACL_TYPE_ACCESS); + + /* + * If it's a directory get the default POSIX ACL. + */ + + if(fsp->is_directory) + dir_acl = sys_acl_get_file( dos_to_unix(fsp->fsp_name, False), SMB_ACL_TYPE_DEFAULT); } else { - if(fsp->conn->vfs_ops.fstat(fsp->fd,&sbuf) != 0) { + + /* Get the stat struct for the owner info. */ + if(vfs_fstat(fsp,fsp->fd,&sbuf) != 0) { return 0; } /* * Get the ACL from the fd. */ - if ((posix_acl = acl_get_fd( fsp->fd)) == NULL) - return 0; + posix_acl = sys_acl_get_fd(fsp->fd); } + DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n", + posix_acl ? "present" : "absent", + dir_acl ? "present" : "absent" )); + /* * Get the owner, group and world SIDs. */ create_file_sids(&sbuf, &owner_sid, &group_sid); - /* - * Count the number of entries in the ACL and return - * the mask. - */ + /* Create the canon_ace lists. */ + if (posix_acl) + file_ace = canonicalise_acl( posix_acl, &sbuf); + else + file_ace = unix_canonicalise_acl(fsp, &sbuf, &owner_sid, &group_sid); + + num_acls = count_canon_ace_list(file_ace); + + if (fsp->is_directory) { + if (dir_ace) + dir_ace = canonicalise_acl( dir_acl, &sbuf); + else + dir_ace = unix_canonicalise_acl(fsp, &sbuf, &owner_sid, &group_sid); + + num_dir_acls = count_canon_ace_list(dir_ace); + } + + /* Allocate the ace list. */ + if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_dir_acls)* sizeof(SEC_ACE))) == NULL) { + DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n")); + goto done; + } - num_posix_entries = get_num_posix_entries(posix_acl, &posix_mask); + memset(nt_ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) ); /* - * Create the generic 3 element UNIX acl. + * Create the NT ACE list from the canonical ace lists. */ - owner_access = map_unix_perms(&owner_acl_type, sbuf.st_mode, - S_IRUSR, S_IWUSR, S_IXUSR, fsp->is_directory); - group_access = map_unix_perms(&grp_acl_type, sbuf.st_mode, - S_IRGRP, S_IWGRP, S_IXGRP, fsp->is_directory); - other_access = map_unix_perms(&other_acl_type, sbuf.st_mode, - S_IROTH, S_IWOTH, S_IXOTH, fsp->is_directory); + { + canon_ace *ace; + int nt_acl_type; + int i; - if(owner_access.mask) - init_sec_ace(&ace_list[num_acls++], &owner_sid, owner_acl_type, owner_access, 0); + ace = file_ace; - if(group_access.mask) - init_sec_ace(&ace_list[num_acls++], &group_sid, grp_acl_type, group_access, 0); + for (i = 0; i < num_acls; i++, ace = ace->next) { + SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace ); + init_sec_ace(&nt_ace_list[num_aces++], &ace->sid, nt_acl_type, acc, 0); + } - if(other_access.mask) - init_sec_ace(&ace_list[num_acls++], &global_sid_World, other_acl_type, other_access, 0); + ace = dir_ace; - if(fsp->is_directory) { - /* - * For directory ACLs we also add in the inherited permissions - * ACE entries. These are the permissions a file would get when - * being created in the directory. - */ - mode_t mode = unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name); - - owner_access = map_unix_perms(&owner_acl_type, mode, - S_IRUSR, S_IWUSR, S_IXUSR, fsp->is_directory); - group_access = map_unix_perms(&grp_acl_type, mode, - S_IRGRP, S_IWGRP, S_IXGRP, fsp->is_directory); - other_access = map_unix_perms(&other_acl_type, mode, - S_IROTH, S_IWOTH, S_IXOTH, fsp->is_directory); - - if(owner_access.mask) - init_sec_ace(&ace_list[num_acls++], &owner_sid, owner_acl_type, - owner_access, SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY); - - if(group_access.mask) - init_sec_ace(&ace_list[num_acls++], &group_sid, grp_acl_type, - group_access, SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY); - - if(other_access.mask) - init_sec_ace(&ace_list[num_acls++], &global_sid_World, other_acl_type, - other_access, SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY); - } + for (i = 0; i < num_dir_acls; i++, ace = ace->next) { + SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace ); + init_sec_ace(&nt_ace_list[num_aces++], &ace->sid, nt_acl_type, acc, + SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY); + } + } - if(num_acls) { - if((psa = make_sec_acl( ACL_REVISION, num_acls, ace_list)) == NULL) { - DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n")); - return 0; - } - } + if (num_acls) { + if((psa = make_sec_acl( ACL_REVISION, num_aces, nt_ace_list)) == NULL) { + DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n")); + goto done; + } + } - *ppdesc = make_standard_sec_desc( &owner_sid, &group_sid, psa, &sd_size); + *ppdesc = make_standard_sec_desc( &owner_sid, &group_sid, psa, &sd_size); - if(!*ppdesc) { - DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n")); - sd_size = 0; - } + if(!*ppdesc) { + DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n")); + sd_size = 0; + } - free_sec_acl(&psa); + done: - return sd_size; + if (posix_acl) + sys_acl_free_acl(posix_acl); + if (dir_acl) + sys_acl_free_acl(dir_acl); + free_canon_ace_list(file_ace); + free_canon_ace_list(dir_ace); + if (nt_ace_list) + free(nt_ace_list); + if (psa) + free_sec_acl(&psa); + + return sd_size; } /**************************************************************************** @@ -488,131 +960,136 @@ size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc) BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) { - connection_struct *conn = fsp->conn; - uid_t user = (uid_t)-1; - gid_t grp = (gid_t)-1; - mode_t perms = 0; - SMB_STRUCT_STAT sbuf; - BOOL got_dacl = False; - - /* - * Get the current state of the file. - */ - - if(fsp->is_directory) { - if(dos_stat(fsp->fsp_name, &sbuf) != 0) - return False; - } else { - - int ret; + connection_struct *conn = fsp->conn; + uid_t user = (uid_t)-1; + gid_t grp = (gid_t)-1; + mode_t perms = 0; + SMB_STRUCT_STAT sbuf; + DOM_SID file_owner_sid; + DOM_SID file_grp_sid; + canon_ace *file_ace_list = NULL; + canon_ace *dir_ace_list = NULL; + BOOL posix_perms; + BOOL acl_perms; - if(fsp->fd == -1) - ret = conn->vfs_ops.stat(dos_to_unix(fsp->fsp_name,False), &sbuf); - else - ret = conn->vfs_ops.fstat(fsp->fd,&sbuf); - - if(ret != 0) - return False; - } + /* + * Get the current state of the file. + */ - /* - * Unpack the user/group/world id's and permissions. - */ + if(fsp->is_directory || fsp->fd == -1) { + if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0) + return False; + } else { + if(vfs_fstat(fsp,fsp->fd,&sbuf) != 0) + return False; + } - if (!unpack_nt_permissions( &sbuf, &user, &grp, &perms, security_info_sent, psd, fsp->is_directory)) - return False; + /* + * Unpack the user/group/world id's. + */ - if (psd->dacl != NULL) - got_dacl = True; + if (!unpack_nt_owners( &sbuf, &user, &grp, security_info_sent, psd)) + return False; - /* - * Do we need to chown ? - */ + /* + * Do we need to chown ? + */ - if((user != (uid_t)-1 || grp != (uid_t)-1) && (sbuf.st_uid != user || sbuf.st_gid != grp)) { + if((user != (uid_t)-1 || grp != (uid_t)-1) && (sbuf.st_uid != user || sbuf.st_gid != grp)) { - DEBUG(3,("call_nt_transact_set_security_desc: chown %s. uid = %u, gid = %u.\n", - fsp->fsp_name, (unsigned int)user, (unsigned int)grp )); + DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n", + fsp->fsp_name, (unsigned int)user, (unsigned int)grp )); - if(dos_chown( fsp->fsp_name, user, grp) == -1) { - DEBUG(3,("call_nt_transact_set_security_desc: chown %s, %u, %u failed. Error = %s.\n", - fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) )); - return False; - } + if(vfs_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) { + DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n", + fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) )); + return False; + } - /* - * Recheck the current state of the file, which may have changed. - * (suid/sgid bits, for instance) - */ + /* + * Recheck the current state of the file, which may have changed. + * (suid/sgid bits, for instance) + */ - if(fsp->is_directory) { - if(dos_stat(fsp->fsp_name, &sbuf) != 0) { - return False; - } - } else { + if(fsp->is_directory) { + if(vfs_stat(fsp->conn, fsp->fsp_name, &sbuf) != 0) { + return False; + } + } else { - int ret; + int ret; - if(fsp->fd == -1) - ret = conn->vfs_ops.stat(dos_to_unix(fsp->fsp_name,False), &sbuf); - else - ret = conn->vfs_ops.fstat(fsp->fd,&sbuf); + if(fsp->fd == -1) + ret = vfs_stat(fsp->conn, fsp->fsp_name, &sbuf); + else + ret = vfs_fstat(fsp,fsp->fd,&sbuf); - if(ret != 0) - return False; - } - } + if(ret != 0) + return False; + } + } - /* - * Only change security if we got a DACL. - */ + create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid); - if((security_info_sent & DACL_SECURITY_INFORMATION) && got_dacl) { + posix_perms = unpack_posix_permissions( fsp, &sbuf, &perms, security_info_sent, psd); + acl_perms = unpack_canon_ace( fsp, &file_owner_sid, &file_grp_sid, + &file_ace_list, &dir_ace_list, security_info_sent, psd); - /* - * Check to see if we need to change anything. - * Enforce limits on modified bits *only*. Don't enforce masks - * on bits not changed by the user. - */ + if (!posix_perms && !acl_perms) { + /* + * Neither method of setting permissions can work. Fail here. + */ - if(fsp->is_directory) { + DEBUG(3,("set_nt_acl: cannot set normal POSIX permissions or POSIX ACL permissions\n")); + free_canon_ace_list(file_ace_list); + free_canon_ace_list(dir_ace_list); + return False; + } - perms &= (lp_dir_security_mask(SNUM(conn)) | sbuf.st_mode); - perms |= (lp_force_dir_security_mode(SNUM(conn)) & ( perms ^ sbuf.st_mode )); + /* + * Only change security if we got a DACL. + */ - } else { + if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) { - perms &= (lp_security_mask(SNUM(conn)) | sbuf.st_mode); - perms |= (lp_force_security_mode(SNUM(conn)) & ( perms ^ sbuf.st_mode )); + BOOL acl_set_support = False; - } + /* + * Try using the POSIX ACL set first. All back to chmod if + * we have no ACL support on this filesystem. + */ - /* - * Preserve special bits. - */ + if (acl_perms && file_ace_list && set_canon_ace_list(fsp, file_ace_list, False)) + acl_set_support = True; - perms |= (sbuf.st_mode & ~0777); + if (acl_perms && acl_set_support && fsp->is_directory && dir_ace_list) + set_canon_ace_list(fsp, dir_ace_list, True); - /* - * Do we need to chmod ? - */ + /* + * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod. + */ - if(sbuf.st_mode != perms) { + if(!acl_set_support && (sbuf.st_mode != perms)) { - DEBUG(3,("call_nt_transact_set_security_desc: chmod %s. perms = 0%o.\n", - fsp->fsp_name, (unsigned int)perms )); + free_canon_ace_list(file_ace_list); + free_canon_ace_list(dir_ace_list); + file_ace_list = NULL; + dir_ace_list = NULL; - if(conn->vfs_ops.chmod(dos_to_unix(fsp->fsp_name, False), perms) == -1) { - DEBUG(3,("call_nt_transact_set_security_desc: chmod %s, 0%o failed. Error = %s.\n", - fsp->fsp_name, (unsigned int)perms, strerror(errno) )); - return False; - } - } - } + DEBUG(3,("call_nt_transact_set_security_desc: chmod %s. perms = 0%o.\n", + fsp->fsp_name, (unsigned int)perms )); - return True; + if(conn->vfs_ops.chmod(conn,dos_to_unix(fsp->fsp_name, False), perms) == -1) { + DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n", + fsp->fsp_name, (unsigned int)perms, strerror(errno) )); + return False; + } + } + } + + free_canon_ace_list(file_ace_list); + free_canon_ace_list(dir_ace_list); + + return True; } #undef OLD_NTDOMAIN -#else /* HAVE_POSIX_ACLS */ - void dummy_posix_acls(void) {;} /* So some compilers don't complain. */ -#endif /* HAVE_POSIX_ACLS */ |