3 Unix SMB/Netbios implementation.
5 SMB NT Security Descriptor / Unix permission conversion.
6 Copyright (C) Jeremy Allison 1994-2000
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 enum ace_owner {UID_ACE, GID_ACE, WORLD_ACE};
27 typedef union posix_id {
33 typedef struct canon_ace {
34 struct canon_ace *next, *prev;
36 mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */
38 enum ace_owner owner_type;
42 static void free_canon_ace_list( canon_ace *list_head );
44 /****************************************************************************
45 Function to duplicate a canon_ace entry.
46 ****************************************************************************/
48 static canon_ace *dup_canon_ace( canon_ace *src_ace)
50 canon_ace *dst_ace = (canon_ace *)malloc(sizeof(canon_ace));
56 dst_ace->prev = dst_ace->next = NULL;
60 /****************************************************************************
61 Function to create owner and group SIDs from a SMB_STRUCT_STAT.
62 ****************************************************************************/
64 static void create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
66 uid_to_sid( powner_sid, psbuf->st_uid );
67 gid_to_sid( pgroup_sid, psbuf->st_gid );
70 /****************************************************************************
71 Print out a canon ace.
72 ****************************************************************************/
74 static void print_canon_ace(canon_ace *ace, int num)
78 dbgtext( "canon_ace index %d.", num );
79 dbgtext( "SID = %s ", sid_to_string( str, &ace->sid));
80 if (ace->owner_type == UID_ACE) {
81 struct passwd *pass = sys_getpwuid(ace->unix_ug.uid);
82 dbgtext( "uid %u (%s) ", (unsigned int)ace->unix_ug.uid, pass ? pass->pw_name : "UNKNOWN");
83 } else if (ace->owner_type == GID_ACE) {
84 struct group *grp = getgrgid(ace->unix_ug.gid);
85 dbgtext( "gid %u (%s) ", (unsigned int)ace->unix_ug.gid, grp ? grp->gr_name : "UNKNOWN");
90 dbgtext( "SMB_ACL_USER ");
92 case SMB_ACL_USER_OBJ:
93 dbgtext( "SMB_ACL_USER_OBJ ");
96 dbgtext( "SMB_ACL_GROUP ");
98 case SMB_ACL_GROUP_OBJ:
99 dbgtext( "SMB_ACL_GROUP_OBJ ");
102 dbgtext( "SMB_ACL_OTHER ");
106 dbgtext( "%c", ace->perms & S_IRUSR ? 'r' : '-');
107 dbgtext( "%c", ace->perms & S_IWUSR ? 'w' : '-');
108 dbgtext( "%c\n", ace->perms & S_IXUSR ? 'x' : '-');
111 /****************************************************************************
112 Map canon_ace perms to permission bits NT.
113 ****************************************************************************/
115 static SEC_ACCESS map_canon_ace_perms(int *pacl_type, DOM_SID *powner_sid, canon_ace *ace)
120 *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
122 if((ace->perms & (S_IRUSR|S_IWUSR|S_IXUSR)) == (S_IRUSR|S_IWUSR|S_IXUSR)) {
123 nt_mask = UNIX_ACCESS_RWX;
124 } else if((ace->perms & (S_IRUSR|S_IWUSR|S_IXUSR)) == 0) {
126 * Here we differentiate between the owner and any other user.
128 if (sid_equal(powner_sid, &ace->sid)) {
129 nt_mask = UNIX_ACCESS_NONE;
131 /* Not owner, no access. */
135 nt_mask |= ((ace->perms & S_IRUSR) ? UNIX_ACCESS_R : 0 );
136 nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
137 nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_ACCESS_X : 0 );
140 DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
141 (unsigned int)ace->perms, (unsigned int)nt_mask ));
143 init_sec_access(&sa,nt_mask);
147 /****************************************************************************
148 Map NT perms to a UNIX mode_t.
149 ****************************************************************************/
151 #define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
152 #define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
153 #define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
155 static mode_t map_nt_perms( SEC_ACCESS sec_access, int type)
161 if(sec_access.mask & GENERIC_ALL_ACCESS)
162 mode = S_IRUSR|S_IWUSR|S_IXUSR;
164 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
165 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
166 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
170 if(sec_access.mask & GENERIC_ALL_ACCESS)
171 mode = S_IRGRP|S_IWGRP|S_IXGRP;
173 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
174 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
175 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
179 if(sec_access.mask & GENERIC_ALL_ACCESS)
180 mode = S_IROTH|S_IWOTH|S_IXOTH;
182 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
183 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
184 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
192 /****************************************************************************
193 Unpack a SEC_DESC into a UNIX owner and group.
194 ****************************************************************************/
196 static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
200 enum SID_NAME_USE sid_type;
205 if(security_info_sent == 0) {
206 DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
211 * Validate the owner and group SID's.
214 memset(&owner_sid, '\0', sizeof(owner_sid));
215 memset(&grp_sid, '\0', sizeof(grp_sid));
217 DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
220 * Don't immediately fail if the owner sid cannot be validated.
221 * This may be a group chown only set.
224 if (security_info_sent & OWNER_SECURITY_INFORMATION) {
225 sid_copy(&owner_sid, psd->owner_sid);
226 if (!sid_to_uid( &owner_sid, puser, &sid_type))
227 DEBUG(3,("unpack_nt_owners: unable to validate owner sid.\n"));
231 * Don't immediately fail if the group sid cannot be validated.
232 * This may be an owner chown only set.
235 if (security_info_sent & GROUP_SECURITY_INFORMATION) {
236 sid_copy(&grp_sid, psd->grp_sid);
237 if (!sid_to_gid( &grp_sid, pgrp, &sid_type))
238 DEBUG(3,("unpack_nt_owners: unable to validate group sid.\n"));
244 /****************************************************************************
245 Merge aces with a common user.
246 ****************************************************************************/
248 static BOOL merge_aces( canon_ace *list_head, canon_ace *p_ace)
252 for (curr_ace = list_head; curr_ace; curr_ace = curr_ace->next) {
253 if (curr_ace == p_ace)
256 if (curr_ace->type == p_ace->type && sid_equal(&curr_ace->sid, &p_ace->sid)) {
257 if( DEBUGLVL( 10 )) {
258 dbgtext("Merging ACE's\n");
259 print_canon_ace( p_ace, 0);
260 print_canon_ace( curr_ace, 0);
262 p_ace->perms |= curr_ace->perms;
263 DLIST_REMOVE(list_head, curr_ace);
272 /****************************************************************************
273 Create a default mode for a directory default ACE.
274 ****************************************************************************/
276 static mode_t get_default_ace_mode(files_struct *fsp, int type)
278 mode_t force_mode = lp_force_dir_security_mode(SNUM(fsp->conn));
283 mode |= (force_mode & S_IRUSR) ? S_IRUSR : 0;
284 mode |= (force_mode & S_IWUSR) ? S_IWUSR : 0;
285 mode |= (force_mode & S_IXUSR) ? S_IXUSR : 0;
288 mode |= (force_mode & S_IRGRP) ? S_IRUSR : 0;
289 mode |= (force_mode & S_IWGRP) ? S_IWUSR : 0;
290 mode |= (force_mode & S_IXGRP) ? S_IXUSR : 0;
293 mode |= (force_mode & S_IROTH) ? S_IRUSR : 0;
294 mode |= (force_mode & S_IWOTH) ? S_IWUSR : 0;
295 mode |= (force_mode & S_IXOTH) ? S_IXUSR : 0;
302 /****************************************************************************
303 A well formed POSIX file or default ACL has at least 3 entries, a
304 SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
305 ****************************************************************************/
307 static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
309 DOM_SID *pfile_owner_sid,
310 DOM_SID *pfile_grp_sid,
311 SMB_STRUCT_STAT *pst,
314 extern DOM_SID global_sid_World;
316 BOOL got_user = False;
317 BOOL got_grp = False;
318 BOOL got_other = False;
320 for (pace = *pp_ace; pace; pace = pace->next) {
321 if (pace->type == SMB_ACL_USER_OBJ)
323 else if (pace->type == SMB_ACL_GROUP_OBJ)
325 else if (pace->type == SMB_ACL_OTHER)
330 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
331 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
336 pace->type = SMB_ACL_USER_OBJ;
337 pace->owner_type = UID_ACE;
338 pace->unix_ug.uid = pst->st_uid;
339 pace->sid = *pfile_owner_sid;
340 pace->perms = default_acl ? get_default_ace_mode(fsp, S_IRUSR): 0;
342 DLIST_ADD(*pp_ace, pace);
346 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
347 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
352 pace->type = SMB_ACL_GROUP_OBJ;
353 pace->owner_type = GID_ACE;
354 pace->unix_ug.uid = pst->st_gid;
355 pace->sid = *pfile_grp_sid;
356 pace->perms = default_acl ? get_default_ace_mode(fsp, S_IRGRP): 0;
358 DLIST_ADD(*pp_ace, pace);
362 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
363 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
368 pace->type = SMB_ACL_OTHER;
369 pace->owner_type = WORLD_ACE;
370 pace->unix_ug.world = -1;
371 pace->sid = global_sid_World;
372 pace->perms = default_acl ? get_default_ace_mode(fsp, S_IROTH): 0;
374 DLIST_ADD(*pp_ace, pace);
380 /****************************************************************************
381 Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
383 ****************************************************************************/
385 static BOOL unpack_canon_ace(files_struct *fsp,
386 SMB_STRUCT_STAT *pst,
387 DOM_SID *pfile_owner_sid,
388 DOM_SID *pfile_grp_sid,
389 canon_ace **ppfile_ace, canon_ace **ppdir_ace,
390 uint32 security_info_sent, SEC_DESC *psd)
392 extern DOM_SID global_sid_World;
393 SEC_ACL *dacl = psd->dacl;
394 BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
395 canon_ace *file_ace = NULL;
396 canon_ace *dir_ace = NULL;
397 canon_ace *current_ace = NULL;
398 enum SID_NAME_USE sid_type;
404 if(security_info_sent == 0) {
405 DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
410 * If no DACL then this is a chown only security descriptor.
413 if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !dacl)
417 * Now go through the DACL and create the canon_ace lists.
420 for(i = 0; i < dacl->num_aces; i++) {
421 SEC_ACE *psa = &dacl->ace[i];
423 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
424 DEBUG(3,("unpack_canon_ace: unable to set anything but an ALLOW or DENY ACE.\n"));
429 * The security mask may be UNIX_ACCESS_NONE which should map into
430 * no permissions (we overload the WRITE_OWNER bit for this) or it
431 * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
432 * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
435 psa->info.mask &= (GENERIC_ALL_ACCESS|GENERIC_EXECUTE_ACCESS|GENERIC_WRITE_ACCESS|
436 GENERIC_READ_ACCESS|UNIX_ACCESS_NONE|FILE_ALL_ATTRIBUTES);
438 if(psa->info.mask != UNIX_ACCESS_NONE)
439 psa->info.mask &= ~UNIX_ACCESS_NONE;
442 * Create a cannon_ace entry representing this NT DACL ACE.
445 if ((current_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
446 free_canon_ace_list(file_ace);
447 free_canon_ace_list(dir_ace);
448 DEBUG(0,("unpack_canon_ace: malloc fail.\n"));
452 ZERO_STRUCTP(current_ace);
454 sid_copy(¤t_ace->sid, &psa->sid);
457 * Try and work out if the SID is a user or group
458 * as we need to flag these differently for POSIX.
461 if( sid_equal(¤t_ace->sid, &global_sid_World)) {
462 current_ace->owner_type = WORLD_ACE;
463 current_ace->unix_ug.world = -1;
464 } else if (sid_to_uid( ¤t_ace->sid, ¤t_ace->unix_ug.uid, &sid_type)) {
465 current_ace->owner_type = UID_ACE;
466 } else if (sid_to_gid( ¤t_ace->sid, ¤t_ace->unix_ug.gid, &sid_type)) {
467 current_ace->owner_type = GID_ACE;
471 free_canon_ace_list(file_ace);
472 free_canon_ace_list(dir_ace);
474 DEBUG(0,("unpack_canon_ace: unable to map SID %s to uid or gid.\n",
475 sid_to_string(str, ¤t_ace->sid) ));
480 * Map the given NT permissions into a UNIX mode_t containing only
481 * S_I(R|W|X)USR bits.
484 if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
485 current_ace->perms |= map_nt_perms( psa->info, S_IRUSR);
487 current_ace->perms = 0;
490 * Now note what kind of a POSIX ACL this should map to.
493 if(sid_equal(¤t_ace->sid, pfile_owner_sid)) {
494 /* Note we should apply the default mode/mask here.... FIXME ! JRA */
495 current_ace->type = SMB_ACL_USER_OBJ;
496 } else if( sid_equal(¤t_ace->sid, pfile_grp_sid)) {
497 /* Note we should apply the default mode/mask here.... FIXME ! JRA */
498 current_ace->type = SMB_ACL_GROUP_OBJ;
499 } else if( sid_equal(¤t_ace->sid, &global_sid_World)) {
500 /* Note we should apply the default mode/mask here.... FIXME ! JRA */
501 current_ace->type = SMB_ACL_OTHER;
504 * Could be a SMB_ACL_USER or SMB_ACL_GROUP. Check by
505 * looking at owner_type.
508 current_ace->type = (current_ace->owner_type == UID_ACE) ? SMB_ACL_USER : SMB_ACL_GROUP;
511 if (fsp->is_directory) {
514 * We can only add to the default POSIX ACE list if the ACE is
515 * designed to be inherited by both files and directories.
517 if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
518 (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
519 DLIST_ADD(dir_ace, current_ace);
522 * If this is not an inherit only ACE we need to add a duplicate
526 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
527 canon_ace *dup_ace = dup_canon_ace(current_ace);
530 DEBUG(0,("unpack_canon_ace: malloc fail !\n"));
531 free_canon_ace_list(file_ace);
532 free_canon_ace_list(dir_ace);
536 current_ace = dup_ace;
544 * Only add to the file ACL if not inherit only.
547 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
548 DLIST_ADD(file_ace, current_ace);
549 all_aces_are_inherit_only = False;
554 * Free if ACE was not addedd.
561 if (fsp->is_directory && all_aces_are_inherit_only) {
563 * Windows 2000 is doing one of these weird 'inherit acl'
564 * traverses to conserve NTFS ACL resources. Just pretend
565 * there was no DACL sent. JRA.
568 DEBUG(10,("unpack_canon_ace: Win2k inherit acl traverse. Ignoring DACL.\n"));
569 free_sec_acl(&psd->dacl);
573 * Now go through the canon_ace lists and merge entries
574 * belonging to identical users.
579 for (current_ace = file_ace; current_ace; current_ace = current_ace->next ) {
580 if (merge_aces( file_ace, current_ace))
586 for (current_ace = dir_ace; current_ace; current_ace = current_ace->next ) {
587 if (merge_aces( dir_ace, current_ace))
592 * A well formed POSIX file or default ACL has at least 3 entries, a
593 * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
594 * and optionally a mask entry. Ensure this is the case.
597 if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, False)) {
598 free_canon_ace_list(file_ace);
599 free_canon_ace_list(dir_ace);
603 if (!ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
604 free_canon_ace_list(file_ace);
605 free_canon_ace_list(dir_ace);
609 if( DEBUGLVL( 10 )) {
610 dbgtext("unpack_canon_ace: File ACL:\n");
611 for (i = 0, current_ace = file_ace; current_ace; current_ace = current_ace->next, i++ ) {
612 print_canon_ace( current_ace, i);
615 dbgtext("unpack_canon_ace: Directory ACL:\n");
616 for (i = 0, current_ace = dir_ace; current_ace; current_ace = current_ace->next, i++ ) {
617 print_canon_ace( current_ace, i);
621 *ppfile_ace = file_ace;
622 *ppdir_ace = dir_ace;
626 /****************************************************************************
627 Unpack a SEC_DESC into a set of standard POSIX permissions.
628 ****************************************************************************/
630 static BOOL unpack_posix_permissions(files_struct *fsp, SMB_STRUCT_STAT *psbuf, mode_t *pmode,
631 uint32 security_info_sent, SEC_DESC *psd, BOOL posix_acls)
633 extern DOM_SID global_sid_World;
634 connection_struct *conn = fsp->conn;
635 DOM_SID file_owner_sid;
636 DOM_SID file_grp_sid;
637 SEC_ACL *dacl = psd->dacl;
638 BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
643 if(security_info_sent == 0) {
644 DEBUG(0,("unpack_posix_permissions: no security info sent !\n"));
649 * Windows 2000 sends the owner and group SIDs as the logged in
650 * user, not the connected user. But it still sends the file
651 * owner SIDs on an ACL set. So we need to check for the file
652 * owner and group SIDs as well as the owner SIDs. JRA.
655 create_file_sids(psbuf, &file_owner_sid, &file_grp_sid);
658 * If no DACL then this is a chown only security descriptor.
661 if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !dacl) {
667 * Now go through the DACL and ensure that
668 * any owner/group sids match.
671 for(i = 0; i < dacl->num_aces; i++) {
673 SEC_ACE *psa = &dacl->ace[i];
675 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) &&
676 (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
677 DEBUG(3,("unpack_posix_permissions: unable to set anything but an ALLOW or DENY ACE.\n"));
682 * Ignore or remove bits we don't care about on a directory ACE.
685 if(fsp->is_directory) {
686 if(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
687 DEBUG(3,("unpack_posix_permissions: ignoring inherit only ACE.\n"));
692 * At least one of the ACE entries wasn't inherit only.
693 * Flag this so we know the returned mode is valid.
696 all_aces_are_inherit_only = False;
700 * Windows 2000 sets these flags even on *file* ACE's. This is wrong
701 * but we can ignore them for now. Revisit this when we go to POSIX
702 * ACLs on directories.
705 psa->flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT);
707 if(psa->flags != 0) {
708 DEBUG(1,("unpack_posix_permissions: unable to set ACE flags (%x).\n",
709 (unsigned int)psa->flags));
714 * The security mask may be UNIX_ACCESS_NONE which should map into
715 * no permissions (we overload the WRITE_OWNER bit for this) or it
716 * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
717 * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
720 psa->info.mask &= (GENERIC_ALL_ACCESS|GENERIC_EXECUTE_ACCESS|GENERIC_WRITE_ACCESS|
721 GENERIC_READ_ACCESS|UNIX_ACCESS_NONE|FILE_ALL_ATTRIBUTES);
723 if(psa->info.mask != UNIX_ACCESS_NONE)
724 psa->info.mask &= ~UNIX_ACCESS_NONE;
726 sid_copy(&ace_sid, &psa->sid);
728 if(sid_equal(&ace_sid, &file_owner_sid)) {
730 * Map the desired permissions into owner perms.
733 if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
734 *pmode |= map_nt_perms( psa->info, S_IRUSR);
736 *pmode &= ~(map_nt_perms( psa->info, S_IRUSR));
739 } else if( sid_equal(&ace_sid, &file_grp_sid)) {
741 * Map the desired permissions into group perms.
744 if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
745 *pmode |= map_nt_perms( psa->info, S_IRGRP);
747 *pmode &= ~(map_nt_perms( psa->info, S_IRGRP));
749 } else if( sid_equal(&ace_sid, &global_sid_World)) {
751 * Map the desired permissions into other perms.
754 if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
755 *pmode |= map_nt_perms( psa->info, S_IROTH);
757 *pmode &= ~(map_nt_perms( psa->info, S_IROTH));
761 * Only bother printing the level zero error if we didn't get any
765 DEBUG(0,("unpack_posix_permissions: unknown SID used in ACL.\n"));
770 if (fsp->is_directory && all_aces_are_inherit_only) {
772 * Windows 2000 is doing one of these weird 'inherit acl'
773 * traverses to conserve NTFS ACL resources. Just pretend
774 * there was no DACL sent. JRA.
777 DEBUG(10,("unpack_posix_permissions: Win2k inherit acl traverse. Ignoring DACL.\n"));
778 free_sec_acl(&psd->dacl);
782 * Check to see if we need to change anything.
783 * Enforce limits on modified bits *only*. Don't enforce masks
784 * on bits not changed by the user.
787 if(fsp->is_directory) {
789 *pmode &= (lp_dir_security_mask(SNUM(conn)) | psbuf->st_mode);
790 *pmode |= (lp_force_dir_security_mode(SNUM(conn)) & ( *pmode ^ psbuf->st_mode ));
794 *pmode &= (lp_security_mask(SNUM(conn)) | psbuf->st_mode);
795 *pmode |= (lp_force_security_mode(SNUM(conn)) & ( *pmode ^ psbuf->st_mode ));
800 * Preserve special bits.
803 *pmode |= (psbuf->st_mode & ~0777);
808 /****************************************************************************
809 Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
810 ****************************************************************************/
812 static mode_t convert_permset_to_mode_t(SMB_ACL_PERMSET_T permset)
816 ret |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? S_IRUSR : 0);
817 ret |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
818 ret |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
823 /****************************************************************************
824 Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
825 ****************************************************************************/
827 static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
841 /****************************************************************************
842 Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to
843 an SMB_ACL_PERMSET_T.
844 ****************************************************************************/
846 static int map_acl_perms_to_permset(mode_t mode, SMB_ACL_PERMSET_T *p_permset)
848 if (sys_acl_clear_perms(*p_permset) == -1)
850 if (mode & S_IRUSR) {
851 if (sys_acl_add_perm(*p_permset, SMB_ACL_READ) == -1)
854 if (mode & S_IWUSR) {
855 if (sys_acl_add_perm(*p_permset, SMB_ACL_WRITE) == -1)
858 if (mode & S_IXUSR) {
859 if (sys_acl_add_perm(*p_permset, SMB_ACL_EXECUTE) == -1)
865 /****************************************************************************
866 Count a linked list of canonical ACE entries.
867 ****************************************************************************/
869 static size_t count_canon_ace_list( canon_ace *list_head )
874 for (ace = list_head; ace; ace = ace->next)
880 /****************************************************************************
881 Free a linked list of canonical ACE entries.
882 ****************************************************************************/
884 static void free_canon_ace_list( canon_ace *list_head )
887 canon_ace *old_head = list_head;
888 DLIST_REMOVE(list_head, list_head);
893 /******************************************************************************
894 Fall back to the generic 3 element UNIX permissions.
895 ********************************************************************************/
897 static canon_ace *unix_canonicalise_acl(files_struct *fsp, SMB_STRUCT_STAT *psbuf,
898 DOM_SID *powner, DOM_SID *pgroup)
900 extern DOM_SID global_sid_World;
901 canon_ace *list_head = NULL;
902 canon_ace *owner_ace = NULL;
903 canon_ace *group_ace = NULL;
904 canon_ace *other_ace = NULL;
907 * Create 3 linked list entries.
910 if ((owner_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
913 if ((group_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
916 if ((other_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
919 ZERO_STRUCTP(owner_ace);
920 ZERO_STRUCTP(group_ace);
921 ZERO_STRUCTP(other_ace);
923 owner_ace->type = SMB_ACL_USER_OBJ;
924 owner_ace->sid = *powner;
925 owner_ace->unix_ug.uid = psbuf->st_uid;
926 owner_ace->owner_type = UID_ACE;
928 group_ace->type = SMB_ACL_GROUP_OBJ;
929 group_ace->sid = *pgroup;
930 owner_ace->unix_ug.gid = psbuf->st_gid;
931 owner_ace->owner_type = GID_ACE;
933 other_ace->type = SMB_ACL_OTHER;
934 other_ace->sid = global_sid_World;
935 owner_ace->unix_ug.world = -1;
936 owner_ace->owner_type = WORLD_ACE;
938 if (!fsp->is_directory) {
939 owner_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
940 group_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
941 other_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
943 mode_t mode = unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name);
945 owner_ace->perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
946 group_ace->perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
947 other_ace->perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
950 DLIST_ADD(list_head, other_ace);
951 DLIST_ADD(list_head, group_ace);
952 DLIST_ADD(list_head, owner_ace);
958 safe_free(owner_ace);
959 safe_free(group_ace);
960 safe_free(other_ace);
965 /****************************************************************************
966 Create a linked list of canonical ACE entries. This is sorted so that DENY
967 entries are at the front of the list, as NT requires.
968 ****************************************************************************/
970 static canon_ace *canonicalise_acl( SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf)
972 extern DOM_SID global_sid_World;
973 mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
974 canon_ace *list_head = NULL;
975 canon_ace *ace = NULL;
976 canon_ace *next_ace = NULL;
977 int entry_id = SMB_ACL_FIRST_ENTRY;
978 SMB_ACL_ENTRY_T entry;
980 while ( sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
981 SMB_ACL_TAG_T tagtype;
982 SMB_ACL_PERMSET_T permset;
985 enum ace_owner owner_type;
988 if (entry_id == SMB_ACL_FIRST_ENTRY)
989 entry_id = SMB_ACL_NEXT_ENTRY;
991 /* Is this a MASK entry ? */
992 if (sys_acl_get_tag_type(entry, &tagtype) == -1)
995 if (sys_acl_get_permset(entry, &permset) == -1)
998 /* Decide which SID to use based on the ACL type. */
1000 case SMB_ACL_USER_OBJ:
1001 /* Get the SID from the owner. */
1002 uid_to_sid( &sid, psbuf->st_uid );
1003 unix_ug.uid = psbuf->st_uid;
1004 owner_type = UID_ACE;
1008 uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
1010 DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
1013 uid_to_sid( &sid, *puid);
1014 unix_ug.uid = *puid;
1015 owner_type = UID_ACE;
1018 case SMB_ACL_GROUP_OBJ:
1019 /* Get the SID from the owning group. */
1020 gid_to_sid( &sid, psbuf->st_gid );
1021 unix_ug.gid = psbuf->st_gid;
1022 owner_type = GID_ACE;
1026 gid_t *pgid = (gid_t *)sys_acl_get_qualifier(entry);
1028 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
1031 gid_to_sid( &sid, *pgid);
1032 unix_ug.gid = *pgid;
1033 owner_type = GID_ACE;
1037 acl_mask = convert_permset_to_mode_t(permset);
1038 continue; /* Don't count the mask as an entry. */
1040 /* Use the Everyone SID */
1041 sid = global_sid_World;
1043 owner_type = WORLD_ACE;
1046 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
1051 * Add this entry to the list.
1054 if ((ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
1058 ace->type = tagtype;
1059 ace->perms = convert_permset_to_mode_t(permset);
1061 ace->unix_ug = unix_ug;
1062 ace->owner_type = owner_type;
1064 DLIST_ADD(list_head, ace);
1068 * Now go through the list, masking the permissions with the
1069 * acl_mask. If the permissions are 0 it should be listed
1073 for ( ace = list_head; ace; ace = next_ace) {
1074 next_ace = ace->next;
1076 /* Masks are only applied to entries other than USER_OBJ and OTHER. */
1077 if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
1078 ace->perms &= acl_mask;
1080 if (ace->perms == 0)
1081 DLIST_PROMOTE(list_head, ace);
1084 if( DEBUGLVL( 10 ) ) {
1085 char *acl_text = sys_acl_to_text( posix_acl, NULL);
1087 dbgtext("canonicalize_acl: processed acl %s\n", acl_text == NULL ? "NULL" : acl_text );
1089 sys_acl_free_text(acl_text);
1096 free_canon_ace_list(list_head);
1100 /****************************************************************************
1101 Attempt to apply an ACL to a file or directory.
1102 ****************************************************************************/
1104 static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, BOOL *pacl_set_support)
1107 SMB_ACL_T the_acl = sys_acl_init((int)count_canon_ace_list(the_ace) + 1);
1110 SMB_ACL_ENTRY_T mask_entry;
1111 SMB_ACL_PERMSET_T mask_permset;
1112 SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
1114 if (the_acl == NULL) {
1115 #if !defined(HAVE_NO_ACLS)
1117 * Only print this error message if we have some kind of ACL
1118 * support that's not working. Otherwise we would always get this.
1120 DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
1121 default_ace ? "default" : "file", strerror(errno) ));
1123 *pacl_set_support = False;
1127 for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
1128 SMB_ACL_ENTRY_T the_entry;
1129 SMB_ACL_PERMSET_T the_permset;
1132 * Get the entry for this ACE.
1135 if (sys_acl_create_entry( &the_acl, &the_entry) == -1) {
1136 DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
1137 i, strerror(errno) ));
1142 * Ok - we now know the ACL calls should be working, don't
1143 * allow fallback to chmod.
1146 *pacl_set_support = True;
1149 * Initialise the entry from the canon_ace.
1153 * First tell the entry what type of ACE this is.
1156 if (sys_acl_set_tag_type(the_entry, p_ace->type) == -1) {
1157 DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
1158 i, strerror(errno) ));
1163 * Only set the qualifier (user or group id) if the entry is a user
1167 if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
1168 if (sys_acl_set_qualifier(the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
1169 DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
1170 i, strerror(errno) ));
1176 * Convert the mode_t perms in the canon_ace to a POSIX permset.
1179 if (sys_acl_get_permset(the_entry, &the_permset) == -1) {
1180 DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
1181 i, strerror(errno) ));
1185 if (map_acl_perms_to_permset(p_ace->perms, &the_permset) == -1) {
1186 DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
1187 p_ace->perms, i, strerror(errno) ));
1192 * ..and apply them to the entry.
1195 if (sys_acl_set_permset(the_entry, the_permset) == -1) {
1196 DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
1197 i, strerror(errno) ));
1202 print_canon_ace( p_ace, i);
1206 * Add in a mask of rwx.
1209 if (sys_acl_create_entry( &the_acl, &mask_entry) == -1) {
1210 DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
1214 if (sys_acl_set_tag_type(mask_entry, SMB_ACL_MASK) == -1) {
1215 DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
1219 if (sys_acl_get_permset(mask_entry, &mask_permset) == -1) {
1220 DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
1224 if (map_acl_perms_to_permset(S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
1225 DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
1229 if (sys_acl_set_permset(mask_entry, mask_permset) == -1) {
1230 DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
1235 * Check if the ACL is valid.
1238 if (sys_acl_valid(the_acl) == -1) {
1239 DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n",
1240 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
1246 * Finally apply it to the file or directory.
1249 if(default_ace || fsp->is_directory || fsp->fd == -1) {
1250 if (sys_acl_set_file(dos_to_unix(fsp->fsp_name,False), the_acl_type, the_acl) == -1) {
1251 DEBUG(0,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
1252 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
1253 fsp->fsp_name, strerror(errno) ));
1257 if (sys_acl_set_fd(fsp->fd, the_acl) == -1) {
1258 DEBUG(0,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
1259 fsp->fsp_name, strerror(errno) ));
1268 if (the_acl != NULL)
1269 sys_acl_free_acl(the_acl);
1274 /****************************************************************************
1275 Reply to query a security descriptor from an fsp. If it succeeds it allocates
1276 the space for the return elements and returns the size needed to return the
1277 security descriptor. This should be the only external function needed for
1278 the UNIX style get ACL.
1279 ****************************************************************************/
1281 size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
1283 SMB_STRUCT_STAT sbuf;
1284 SEC_ACE *nt_ace_list;
1288 SEC_ACL *psa = NULL;
1289 size_t num_acls = 0;
1290 size_t num_dir_acls = 0;
1291 size_t num_aces = 0;
1292 SMB_ACL_T posix_acl = NULL;
1293 SMB_ACL_T dir_acl = NULL;
1294 canon_ace *file_ace = NULL;
1295 canon_ace *dir_ace = NULL;
1299 DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name ));
1301 if(fsp->is_directory || fsp->fd == -1) {
1303 /* Get the stat struct for the owner info. */
1304 if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
1308 * Get the ACL from the path.
1311 posix_acl = sys_acl_get_file( dos_to_unix(fsp->fsp_name, False), SMB_ACL_TYPE_ACCESS);
1314 * If it's a directory get the default POSIX ACL.
1317 if(fsp->is_directory)
1318 dir_acl = sys_acl_get_file( dos_to_unix(fsp->fsp_name, False), SMB_ACL_TYPE_DEFAULT);
1322 /* Get the stat struct for the owner info. */
1323 if(vfs_fstat(fsp,fsp->fd,&sbuf) != 0) {
1327 * Get the ACL from the fd.
1329 posix_acl = sys_acl_get_fd(fsp->fd);
1332 DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
1333 posix_acl ? "present" : "absent",
1334 dir_acl ? "present" : "absent" ));
1337 * Get the owner, group and world SIDs.
1340 create_file_sids(&sbuf, &owner_sid, &group_sid);
1342 /* Create the canon_ace lists. */
1344 file_ace = canonicalise_acl( posix_acl, &sbuf);
1346 file_ace = unix_canonicalise_acl(fsp, &sbuf, &owner_sid, &group_sid);
1348 num_acls = count_canon_ace_list(file_ace);
1350 if (fsp->is_directory) {
1352 dir_ace = canonicalise_acl( dir_acl, &sbuf);
1354 dir_ace = unix_canonicalise_acl(fsp, &sbuf, &owner_sid, &group_sid);
1356 num_dir_acls = count_canon_ace_list(dir_ace);
1359 /* Allocate the ace list. */
1360 if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_dir_acls)* sizeof(SEC_ACE))) == NULL) {
1361 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
1365 memset(nt_ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) );
1368 * Create the NT ACE list from the canonical ace lists.
1378 for (i = 0; i < num_acls; i++, ace = ace->next) {
1379 SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
1380 init_sec_ace(&nt_ace_list[num_aces++], &ace->sid, nt_acl_type, acc, 0);
1385 for (i = 0; i < num_dir_acls; i++, ace = ace->next) {
1386 SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
1387 init_sec_ace(&nt_ace_list[num_aces++], &ace->sid, nt_acl_type, acc,
1388 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY);
1393 if((psa = make_sec_acl( ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
1394 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
1399 *ppdesc = make_standard_sec_desc( &owner_sid, &group_sid, psa, &sd_size);
1402 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
1409 sys_acl_free_acl(posix_acl);
1411 sys_acl_free_acl(dir_acl);
1412 free_canon_ace_list(file_ace);
1413 free_canon_ace_list(dir_ace);
1422 /****************************************************************************
1423 Reply to set a security descriptor on an fsp. security_info_sent is the
1424 description of the following NT ACL.
1425 This should be the only external function needed for the UNIX style set ACL.
1426 ****************************************************************************/
1428 BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
1430 connection_struct *conn = fsp->conn;
1431 uid_t user = (uid_t)-1;
1432 gid_t grp = (gid_t)-1;
1434 SMB_STRUCT_STAT sbuf;
1435 DOM_SID file_owner_sid;
1436 DOM_SID file_grp_sid;
1437 canon_ace *file_ace_list = NULL;
1438 canon_ace *dir_ace_list = NULL;
1442 DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
1445 * Get the current state of the file.
1448 if(fsp->is_directory || fsp->fd == -1) {
1449 if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0)
1452 if(vfs_fstat(fsp,fsp->fd,&sbuf) != 0)
1457 * Unpack the user/group/world id's.
1460 if (!unpack_nt_owners( &sbuf, &user, &grp, security_info_sent, psd))
1464 * Do we need to chown ?
1467 if((user != (uid_t)-1 || grp != (uid_t)-1) && (sbuf.st_uid != user || sbuf.st_gid != grp)) {
1469 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
1470 fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
1472 if(vfs_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
1473 DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
1474 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
1479 * Recheck the current state of the file, which may have changed.
1480 * (suid/sgid bits, for instance)
1483 if(fsp->is_directory) {
1484 if(vfs_stat(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
1492 ret = vfs_stat(fsp->conn, fsp->fsp_name, &sbuf);
1494 ret = vfs_fstat(fsp,fsp->fd,&sbuf);
1501 create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
1503 acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
1504 &file_ace_list, &dir_ace_list, security_info_sent, psd);
1505 posix_perms = unpack_posix_permissions( fsp, &sbuf, &perms, security_info_sent, psd, acl_perms);
1507 if (!posix_perms && !acl_perms) {
1509 * Neither method of setting permissions can work. Fail here.
1512 DEBUG(3,("set_nt_acl: cannot set normal POSIX permissions or POSIX ACL permissions\n"));
1513 free_canon_ace_list(file_ace_list);
1514 free_canon_ace_list(dir_ace_list);
1519 * Only change security if we got a DACL.
1522 if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
1524 BOOL acl_set_support = False;
1528 * Try using the POSIX ACL set first. All back to chmod if
1529 * we have no ACL support on this filesystem.
1532 if (acl_perms && file_ace_list) {
1533 ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support);
1534 if (acl_set_support && ret == False) {
1535 DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
1536 free_canon_ace_list(file_ace_list);
1537 free_canon_ace_list(dir_ace_list);
1542 if (acl_perms && acl_set_support && fsp->is_directory && dir_ace_list) {
1543 if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) {
1544 DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
1545 free_canon_ace_list(file_ace_list);
1546 free_canon_ace_list(dir_ace_list);
1552 * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
1555 if(!acl_set_support && (sbuf.st_mode != perms)) {
1557 free_canon_ace_list(file_ace_list);
1558 free_canon_ace_list(dir_ace_list);
1559 file_ace_list = NULL;
1560 dir_ace_list = NULL;
1562 DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
1563 fsp->fsp_name, (unsigned int)perms ));
1565 if(conn->vfs_ops.chmod(conn,dos_to_unix(fsp->fsp_name, False), perms) == -1) {
1566 DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
1567 fsp->fsp_name, (unsigned int)perms, strerror(errno) ));
1573 free_canon_ace_list(file_ace_list);
1574 free_canon_ace_list(dir_ace_list);
1579 /****************************************************************************
1580 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
1581 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
1582 ****************************************************************************/
1584 static int chmod_acl_internals( SMB_ACL_T posix_acl, mode_t mode)
1586 int entry_id = SMB_ACL_FIRST_ENTRY;
1587 SMB_ACL_ENTRY_T entry;
1588 int num_entries = 0;
1590 while ( sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
1591 SMB_ACL_TAG_T tagtype;
1592 SMB_ACL_PERMSET_T permset;
1596 if (entry_id == SMB_ACL_FIRST_ENTRY)
1597 entry_id = SMB_ACL_NEXT_ENTRY;
1599 if (sys_acl_get_tag_type(entry, &tagtype) == -1)
1602 if (sys_acl_get_permset(entry, &permset) == -1)
1608 case SMB_ACL_USER_OBJ:
1609 perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
1611 case SMB_ACL_GROUP_OBJ:
1612 perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
1615 perms = S_IRUSR|S_IWUSR|S_IXUSR;
1618 perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
1624 if (map_acl_perms_to_permset(perms, &permset) == -1)
1627 if (sys_acl_set_permset(entry, permset) == -1)
1632 * If this is a simple 3 element ACL then it's a standard
1633 * UNIX permission set. Just use chmod...
1636 if (num_entries == 3)
1642 /****************************************************************************
1643 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
1644 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
1645 Note that name is in UNIX character set.
1646 ****************************************************************************/
1648 int chmod_acl(char *name, mode_t mode)
1650 SMB_ACL_T posix_acl = NULL;
1653 if ((posix_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS)) == NULL)
1656 if ((ret = chmod_acl_internals(posix_acl, mode)) == -1)
1659 ret = sys_acl_set_file(name, SMB_ACL_TYPE_ACCESS, posix_acl);
1663 sys_acl_free_acl(posix_acl);
1667 /****************************************************************************
1668 Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
1669 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
1670 ****************************************************************************/
1672 int fchmod_acl(int fd, mode_t mode)
1674 SMB_ACL_T posix_acl = NULL;
1677 if ((posix_acl = sys_acl_get_fd(fd)) == NULL)
1680 if ((ret = chmod_acl_internals(posix_acl, mode)) == -1)
1683 ret = sys_acl_set_fd(fd, posix_acl);
1687 sys_acl_free_acl(posix_acl);