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"));
241 DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
246 /****************************************************************************
247 Merge aces with a common user.
248 ****************************************************************************/
250 static BOOL merge_aces( canon_ace *list_head, canon_ace *p_ace)
254 for (curr_ace = list_head; curr_ace; curr_ace = curr_ace->next) {
255 if (curr_ace == p_ace)
258 if (curr_ace->type == p_ace->type && sid_equal(&curr_ace->sid, &p_ace->sid)) {
259 if( DEBUGLVL( 10 )) {
260 dbgtext("Merging ACE's\n");
261 print_canon_ace( p_ace, 0);
262 print_canon_ace( curr_ace, 0);
264 p_ace->perms |= curr_ace->perms;
265 DLIST_REMOVE(list_head, curr_ace);
274 /****************************************************************************
275 Create a default mode for a directory default ACE.
276 ****************************************************************************/
278 static mode_t get_default_ace_mode(files_struct *fsp, int type)
280 mode_t force_mode = lp_force_dir_security_mode(SNUM(fsp->conn));
285 mode |= (force_mode & S_IRUSR) ? S_IRUSR : 0;
286 mode |= (force_mode & S_IWUSR) ? S_IWUSR : 0;
287 mode |= (force_mode & S_IXUSR) ? S_IXUSR : 0;
290 mode |= (force_mode & S_IRGRP) ? S_IRUSR : 0;
291 mode |= (force_mode & S_IWGRP) ? S_IWUSR : 0;
292 mode |= (force_mode & S_IXGRP) ? S_IXUSR : 0;
295 mode |= (force_mode & S_IROTH) ? S_IRUSR : 0;
296 mode |= (force_mode & S_IWOTH) ? S_IWUSR : 0;
297 mode |= (force_mode & S_IXOTH) ? S_IXUSR : 0;
304 /****************************************************************************
305 A well formed POSIX file or default ACL has at least 3 entries, a
306 SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
307 ****************************************************************************/
309 static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
311 DOM_SID *pfile_owner_sid,
312 DOM_SID *pfile_grp_sid,
313 SMB_STRUCT_STAT *pst,
316 extern DOM_SID global_sid_World;
318 BOOL got_user = False;
319 BOOL got_grp = False;
320 BOOL got_other = False;
322 for (pace = *pp_ace; pace; pace = pace->next) {
323 if (pace->type == SMB_ACL_USER_OBJ)
325 else if (pace->type == SMB_ACL_GROUP_OBJ)
327 else if (pace->type == SMB_ACL_OTHER)
332 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
333 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
338 pace->type = SMB_ACL_USER_OBJ;
339 pace->owner_type = UID_ACE;
340 pace->unix_ug.uid = pst->st_uid;
341 pace->sid = *pfile_owner_sid;
342 pace->perms = default_acl ? get_default_ace_mode(fsp, S_IRUSR): 0;
344 DLIST_ADD(*pp_ace, pace);
348 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
349 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
354 pace->type = SMB_ACL_GROUP_OBJ;
355 pace->owner_type = GID_ACE;
356 pace->unix_ug.uid = pst->st_gid;
357 pace->sid = *pfile_grp_sid;
358 pace->perms = default_acl ? get_default_ace_mode(fsp, S_IRGRP): 0;
360 DLIST_ADD(*pp_ace, pace);
364 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
365 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
370 pace->type = SMB_ACL_OTHER;
371 pace->owner_type = WORLD_ACE;
372 pace->unix_ug.world = -1;
373 pace->sid = global_sid_World;
374 pace->perms = default_acl ? get_default_ace_mode(fsp, S_IROTH): 0;
376 DLIST_ADD(*pp_ace, pace);
382 /****************************************************************************
383 Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
385 ****************************************************************************/
387 static BOOL unpack_canon_ace(files_struct *fsp,
388 SMB_STRUCT_STAT *pst,
389 DOM_SID *pfile_owner_sid,
390 DOM_SID *pfile_grp_sid,
391 canon_ace **ppfile_ace, canon_ace **ppdir_ace,
392 uint32 security_info_sent, SEC_DESC *psd)
394 #if !defined(HAVE_NO_ACLS)
395 extern DOM_SID global_sid_World;
396 BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
397 canon_ace *file_ace = NULL;
398 canon_ace *dir_ace = NULL;
399 canon_ace *current_ace = NULL;
400 enum SID_NAME_USE sid_type;
402 #endif /* HAVE_NO_ACLS */
403 SEC_ACL *dacl = psd->dacl;
408 if(security_info_sent == 0) {
409 DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
414 * If no DACL then this is a chown only security descriptor.
417 if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !dacl)
420 #if defined(HAVE_NO_ACLS)
422 /* No point in doing this if we have no ACL support. */
425 #else /* HAVE_NO_ACLS */
428 * Now go through the DACL and create the canon_ace lists.
431 for(i = 0; i < dacl->num_aces; i++) {
432 SEC_ACE *psa = &dacl->ace[i];
434 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
435 DEBUG(3,("unpack_canon_ace: unable to set anything but an ALLOW or DENY ACE.\n"));
440 * The security mask may be UNIX_ACCESS_NONE which should map into
441 * no permissions (we overload the WRITE_OWNER bit for this) or it
442 * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
443 * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
446 psa->info.mask &= (GENERIC_ALL_ACCESS|GENERIC_EXECUTE_ACCESS|GENERIC_WRITE_ACCESS|
447 GENERIC_READ_ACCESS|UNIX_ACCESS_NONE|FILE_ALL_ATTRIBUTES);
449 if(psa->info.mask != UNIX_ACCESS_NONE)
450 psa->info.mask &= ~UNIX_ACCESS_NONE;
453 * Create a cannon_ace entry representing this NT DACL ACE.
456 if ((current_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
457 free_canon_ace_list(file_ace);
458 free_canon_ace_list(dir_ace);
459 DEBUG(0,("unpack_canon_ace: malloc fail.\n"));
463 ZERO_STRUCTP(current_ace);
465 sid_copy(¤t_ace->sid, &psa->sid);
468 * Try and work out if the SID is a user or group
469 * as we need to flag these differently for POSIX.
472 if( sid_equal(¤t_ace->sid, &global_sid_World)) {
473 current_ace->owner_type = WORLD_ACE;
474 current_ace->unix_ug.world = -1;
475 } else if (sid_to_uid( ¤t_ace->sid, ¤t_ace->unix_ug.uid, &sid_type)) {
476 current_ace->owner_type = UID_ACE;
477 } else if (sid_to_gid( ¤t_ace->sid, ¤t_ace->unix_ug.gid, &sid_type)) {
478 current_ace->owner_type = GID_ACE;
482 free_canon_ace_list(file_ace);
483 free_canon_ace_list(dir_ace);
485 DEBUG(0,("unpack_canon_ace: unable to map SID %s to uid or gid.\n",
486 sid_to_string(str, ¤t_ace->sid) ));
491 * Map the given NT permissions into a UNIX mode_t containing only
492 * S_I(R|W|X)USR bits.
495 if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
496 current_ace->perms |= map_nt_perms( psa->info, S_IRUSR);
498 current_ace->perms = 0;
501 * Now note what kind of a POSIX ACL this should map to.
504 if(sid_equal(¤t_ace->sid, pfile_owner_sid)) {
505 /* Note we should apply the default mode/mask here.... FIXME ! JRA */
506 current_ace->type = SMB_ACL_USER_OBJ;
507 } else if( sid_equal(¤t_ace->sid, pfile_grp_sid)) {
508 /* Note we should apply the default mode/mask here.... FIXME ! JRA */
509 current_ace->type = SMB_ACL_GROUP_OBJ;
510 } else if( sid_equal(¤t_ace->sid, &global_sid_World)) {
511 /* Note we should apply the default mode/mask here.... FIXME ! JRA */
512 current_ace->type = SMB_ACL_OTHER;
515 * Could be a SMB_ACL_USER or SMB_ACL_GROUP. Check by
516 * looking at owner_type.
519 current_ace->type = (current_ace->owner_type == UID_ACE) ? SMB_ACL_USER : SMB_ACL_GROUP;
522 if (fsp->is_directory) {
525 * We can only add to the default POSIX ACE list if the ACE is
526 * designed to be inherited by both files and directories.
528 if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
529 (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
530 DLIST_ADD(dir_ace, current_ace);
533 * If this is not an inherit only ACE we need to add a duplicate
537 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
538 canon_ace *dup_ace = dup_canon_ace(current_ace);
541 DEBUG(0,("unpack_canon_ace: malloc fail !\n"));
542 free_canon_ace_list(file_ace);
543 free_canon_ace_list(dir_ace);
547 current_ace = dup_ace;
555 * Only add to the file ACL if not inherit only.
558 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
559 DLIST_ADD(file_ace, current_ace);
560 all_aces_are_inherit_only = False;
565 * Free if ACE was not addedd.
572 if (fsp->is_directory && all_aces_are_inherit_only) {
574 * Windows 2000 is doing one of these weird 'inherit acl'
575 * traverses to conserve NTFS ACL resources. Just pretend
576 * there was no DACL sent. JRA.
579 DEBUG(10,("unpack_canon_ace: Win2k inherit acl traverse. Ignoring DACL.\n"));
580 free_sec_acl(&psd->dacl);
584 * Now go through the canon_ace lists and merge entries
585 * belonging to identical users.
590 for (current_ace = file_ace; current_ace; current_ace = current_ace->next ) {
591 if (merge_aces( file_ace, current_ace))
597 for (current_ace = dir_ace; current_ace; current_ace = current_ace->next ) {
598 if (merge_aces( dir_ace, current_ace))
603 * A well formed POSIX file or default ACL has at least 3 entries, a
604 * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
605 * and optionally a mask entry. Ensure this is the case.
608 if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, False)) {
609 free_canon_ace_list(file_ace);
610 free_canon_ace_list(dir_ace);
614 if (!ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
615 free_canon_ace_list(file_ace);
616 free_canon_ace_list(dir_ace);
620 if( DEBUGLVL( 10 )) {
621 dbgtext("unpack_canon_ace: File ACL:\n");
622 for (i = 0, current_ace = file_ace; current_ace; current_ace = current_ace->next, i++ ) {
623 print_canon_ace( current_ace, i);
626 dbgtext("unpack_canon_ace: Directory ACL:\n");
627 for (i = 0, current_ace = dir_ace; current_ace; current_ace = current_ace->next, i++ ) {
628 print_canon_ace( current_ace, i);
632 *ppfile_ace = file_ace;
633 *ppdir_ace = dir_ace;
636 #endif /* HAVE_NO_ACLS */
639 /****************************************************************************
640 Unpack a SEC_DESC into a set of standard POSIX permissions.
641 ****************************************************************************/
643 static BOOL unpack_posix_permissions(files_struct *fsp, SMB_STRUCT_STAT *psbuf, mode_t *pmode,
644 uint32 security_info_sent, SEC_DESC *psd, BOOL posix_acls)
646 extern DOM_SID global_sid_World;
647 connection_struct *conn = fsp->conn;
648 DOM_SID file_owner_sid;
649 DOM_SID file_grp_sid;
650 SEC_ACL *dacl = psd->dacl;
651 BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
656 if(security_info_sent == 0) {
657 DEBUG(0,("unpack_posix_permissions: no security info sent !\n"));
662 * Windows 2000 sends the owner and group SIDs as the logged in
663 * user, not the connected user. But it still sends the file
664 * owner SIDs on an ACL set. So we need to check for the file
665 * owner and group SIDs as well as the owner SIDs. JRA.
668 create_file_sids(psbuf, &file_owner_sid, &file_grp_sid);
671 * If no DACL then this is a chown only security descriptor.
674 if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !dacl) {
680 * Now go through the DACL and ensure that
681 * any owner/group sids match.
684 for(i = 0; i < dacl->num_aces; i++) {
686 SEC_ACE *psa = &dacl->ace[i];
688 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) &&
689 (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
690 DEBUG(3,("unpack_posix_permissions: unable to set anything but an ALLOW or DENY ACE.\n"));
695 * Ignore or remove bits we don't care about on a directory ACE.
698 if(fsp->is_directory) {
699 if(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
700 DEBUG(3,("unpack_posix_permissions: ignoring inherit only ACE.\n"));
705 * At least one of the ACE entries wasn't inherit only.
706 * Flag this so we know the returned mode is valid.
709 all_aces_are_inherit_only = False;
713 * Windows 2000 sets these flags even on *file* ACE's. This is wrong
714 * but we can ignore them for now. Revisit this when we go to POSIX
715 * ACLs on directories.
718 psa->flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERITED_ACE);
720 if(psa->flags != 0) {
721 DEBUG(1,("unpack_posix_permissions: unable to set ACE flags (%x).\n",
722 (unsigned int)psa->flags));
727 * The security mask may be UNIX_ACCESS_NONE which should map into
728 * no permissions (we overload the WRITE_OWNER bit for this) or it
729 * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
730 * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
733 psa->info.mask &= (GENERIC_ALL_ACCESS|GENERIC_EXECUTE_ACCESS|GENERIC_WRITE_ACCESS|
734 GENERIC_READ_ACCESS|UNIX_ACCESS_NONE|FILE_ALL_ATTRIBUTES);
736 if(psa->info.mask != UNIX_ACCESS_NONE)
737 psa->info.mask &= ~UNIX_ACCESS_NONE;
739 sid_copy(&ace_sid, &psa->sid);
741 if(sid_equal(&ace_sid, &file_owner_sid)) {
743 * Map the desired permissions into owner perms.
746 if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
747 *pmode |= map_nt_perms( psa->info, S_IRUSR);
749 *pmode &= ~(map_nt_perms( psa->info, S_IRUSR));
752 } else if( sid_equal(&ace_sid, &file_grp_sid)) {
754 * Map the desired permissions into group perms.
757 if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
758 *pmode |= map_nt_perms( psa->info, S_IRGRP);
760 *pmode &= ~(map_nt_perms( psa->info, S_IRGRP));
762 } else if( sid_equal(&ace_sid, &global_sid_World)) {
764 * Map the desired permissions into other perms.
767 if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
768 *pmode |= map_nt_perms( psa->info, S_IROTH);
770 *pmode &= ~(map_nt_perms( psa->info, S_IROTH));
774 * Only bother printing the level zero error if we didn't get any
778 DEBUG(0,("unpack_posix_permissions: unknown SID used in ACL.\n"));
783 if (fsp->is_directory && all_aces_are_inherit_only) {
785 * Windows 2000 is doing one of these weird 'inherit acl'
786 * traverses to conserve NTFS ACL resources. Just pretend
787 * there was no DACL sent. JRA.
790 DEBUG(10,("unpack_posix_permissions: Win2k inherit acl traverse. Ignoring DACL.\n"));
791 free_sec_acl(&psd->dacl);
795 * Check to see if we need to change anything.
796 * Enforce limits on modified bits *only*. Don't enforce masks
797 * on bits not changed by the user.
800 if(fsp->is_directory) {
802 *pmode &= (lp_dir_security_mask(SNUM(conn)) | psbuf->st_mode);
803 *pmode |= (lp_force_dir_security_mode(SNUM(conn)) & ( *pmode ^ psbuf->st_mode ));
807 *pmode &= (lp_security_mask(SNUM(conn)) | psbuf->st_mode);
808 *pmode |= (lp_force_security_mode(SNUM(conn)) & ( *pmode ^ psbuf->st_mode ));
813 * Preserve special bits.
816 *pmode |= (psbuf->st_mode & ~0777);
821 /****************************************************************************
822 Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
823 ****************************************************************************/
825 static mode_t convert_permset_to_mode_t(SMB_ACL_PERMSET_T permset)
829 ret |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? S_IRUSR : 0);
830 ret |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
831 ret |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
836 /****************************************************************************
837 Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
838 ****************************************************************************/
840 static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
854 /****************************************************************************
855 Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to
856 an SMB_ACL_PERMSET_T.
857 ****************************************************************************/
859 static int map_acl_perms_to_permset(mode_t mode, SMB_ACL_PERMSET_T *p_permset)
861 if (sys_acl_clear_perms(*p_permset) == -1)
863 if (mode & S_IRUSR) {
864 if (sys_acl_add_perm(*p_permset, SMB_ACL_READ) == -1)
867 if (mode & S_IWUSR) {
868 if (sys_acl_add_perm(*p_permset, SMB_ACL_WRITE) == -1)
871 if (mode & S_IXUSR) {
872 if (sys_acl_add_perm(*p_permset, SMB_ACL_EXECUTE) == -1)
878 /****************************************************************************
879 Count a linked list of canonical ACE entries.
880 ****************************************************************************/
882 static size_t count_canon_ace_list( canon_ace *list_head )
887 for (ace = list_head; ace; ace = ace->next)
893 /****************************************************************************
894 Free a linked list of canonical ACE entries.
895 ****************************************************************************/
897 static void free_canon_ace_list( canon_ace *list_head )
900 canon_ace *old_head = list_head;
901 DLIST_REMOVE(list_head, list_head);
906 /******************************************************************************
907 Fall back to the generic 3 element UNIX permissions.
908 ********************************************************************************/
910 static canon_ace *unix_canonicalise_acl(files_struct *fsp, SMB_STRUCT_STAT *psbuf,
911 DOM_SID *powner, DOM_SID *pgroup)
913 extern DOM_SID global_sid_World;
914 canon_ace *list_head = NULL;
915 canon_ace *owner_ace = NULL;
916 canon_ace *group_ace = NULL;
917 canon_ace *other_ace = NULL;
920 * Create 3 linked list entries.
923 if ((owner_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
926 if ((group_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
929 if ((other_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
932 ZERO_STRUCTP(owner_ace);
933 ZERO_STRUCTP(group_ace);
934 ZERO_STRUCTP(other_ace);
936 owner_ace->type = SMB_ACL_USER_OBJ;
937 owner_ace->sid = *powner;
938 owner_ace->unix_ug.uid = psbuf->st_uid;
939 owner_ace->owner_type = UID_ACE;
941 group_ace->type = SMB_ACL_GROUP_OBJ;
942 group_ace->sid = *pgroup;
943 owner_ace->unix_ug.gid = psbuf->st_gid;
944 owner_ace->owner_type = GID_ACE;
946 other_ace->type = SMB_ACL_OTHER;
947 other_ace->sid = global_sid_World;
948 owner_ace->unix_ug.world = -1;
949 owner_ace->owner_type = WORLD_ACE;
951 if (!fsp->is_directory) {
952 owner_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
953 group_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
954 other_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
956 mode_t mode = unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name);
958 owner_ace->perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
959 group_ace->perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
960 other_ace->perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
963 DLIST_ADD(list_head, other_ace);
964 DLIST_ADD(list_head, group_ace);
965 DLIST_ADD(list_head, owner_ace);
971 safe_free(owner_ace);
972 safe_free(group_ace);
973 safe_free(other_ace);
978 /****************************************************************************
979 Create a linked list of canonical ACE entries. This is sorted so that DENY
980 entries are at the front of the list, as NT requires.
981 ****************************************************************************/
983 static canon_ace *canonicalise_acl( SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf)
985 extern DOM_SID global_sid_World;
986 mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
987 canon_ace *list_head = NULL;
988 canon_ace *ace = NULL;
989 canon_ace *next_ace = NULL;
990 int entry_id = SMB_ACL_FIRST_ENTRY;
991 SMB_ACL_ENTRY_T entry;
993 while ( sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
994 SMB_ACL_TAG_T tagtype;
995 SMB_ACL_PERMSET_T permset;
998 enum ace_owner owner_type;
1001 if (entry_id == SMB_ACL_FIRST_ENTRY)
1002 entry_id = SMB_ACL_NEXT_ENTRY;
1004 /* Is this a MASK entry ? */
1005 if (sys_acl_get_tag_type(entry, &tagtype) == -1)
1008 if (sys_acl_get_permset(entry, &permset) == -1)
1011 /* Decide which SID to use based on the ACL type. */
1013 case SMB_ACL_USER_OBJ:
1014 /* Get the SID from the owner. */
1015 uid_to_sid( &sid, psbuf->st_uid );
1016 unix_ug.uid = psbuf->st_uid;
1017 owner_type = UID_ACE;
1021 uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
1023 DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
1026 uid_to_sid( &sid, *puid);
1027 unix_ug.uid = *puid;
1028 owner_type = UID_ACE;
1031 case SMB_ACL_GROUP_OBJ:
1032 /* Get the SID from the owning group. */
1033 gid_to_sid( &sid, psbuf->st_gid );
1034 unix_ug.gid = psbuf->st_gid;
1035 owner_type = GID_ACE;
1039 gid_t *pgid = (gid_t *)sys_acl_get_qualifier(entry);
1041 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
1044 gid_to_sid( &sid, *pgid);
1045 unix_ug.gid = *pgid;
1046 owner_type = GID_ACE;
1050 acl_mask = convert_permset_to_mode_t(permset);
1051 continue; /* Don't count the mask as an entry. */
1053 /* Use the Everyone SID */
1054 sid = global_sid_World;
1056 owner_type = WORLD_ACE;
1059 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
1064 * Add this entry to the list.
1067 if ((ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
1071 ace->type = tagtype;
1072 ace->perms = convert_permset_to_mode_t(permset);
1074 ace->unix_ug = unix_ug;
1075 ace->owner_type = owner_type;
1077 DLIST_ADD(list_head, ace);
1081 * Now go through the list, masking the permissions with the
1082 * acl_mask. If the permissions are 0 it should be listed
1086 for ( ace = list_head; ace; ace = next_ace) {
1087 next_ace = ace->next;
1089 /* Masks are only applied to entries other than USER_OBJ and OTHER. */
1090 if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
1091 ace->perms &= acl_mask;
1093 if (ace->perms == 0)
1094 DLIST_PROMOTE(list_head, ace);
1097 if( DEBUGLVL( 10 ) ) {
1098 char *acl_text = sys_acl_to_text( posix_acl, NULL);
1100 dbgtext("canonicalize_acl: processed acl %s\n", acl_text == NULL ? "NULL" : acl_text );
1102 sys_acl_free_text(acl_text);
1109 free_canon_ace_list(list_head);
1113 /****************************************************************************
1114 Attempt to apply an ACL to a file or directory.
1115 ****************************************************************************/
1117 static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, BOOL *pacl_set_support)
1120 SMB_ACL_T the_acl = sys_acl_init((int)count_canon_ace_list(the_ace) + 1);
1123 SMB_ACL_ENTRY_T mask_entry;
1124 SMB_ACL_PERMSET_T mask_permset;
1125 SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
1127 if (the_acl == NULL) {
1128 #if !defined(HAVE_NO_ACLS)
1130 * Only print this error message if we have some kind of ACL
1131 * support that's not working. Otherwise we would always get this.
1133 DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
1134 default_ace ? "default" : "file", strerror(errno) ));
1136 *pacl_set_support = False;
1140 for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
1141 SMB_ACL_ENTRY_T the_entry;
1142 SMB_ACL_PERMSET_T the_permset;
1145 * Get the entry for this ACE.
1148 if (sys_acl_create_entry( &the_acl, &the_entry) == -1) {
1149 DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
1150 i, strerror(errno) ));
1155 * Ok - we now know the ACL calls should be working, don't
1156 * allow fallback to chmod.
1159 *pacl_set_support = True;
1162 * Initialise the entry from the canon_ace.
1166 * First tell the entry what type of ACE this is.
1169 if (sys_acl_set_tag_type(the_entry, p_ace->type) == -1) {
1170 DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
1171 i, strerror(errno) ));
1176 * Only set the qualifier (user or group id) if the entry is a user
1180 if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
1181 if (sys_acl_set_qualifier(the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
1182 DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
1183 i, strerror(errno) ));
1189 * Convert the mode_t perms in the canon_ace to a POSIX permset.
1192 if (sys_acl_get_permset(the_entry, &the_permset) == -1) {
1193 DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
1194 i, strerror(errno) ));
1198 if (map_acl_perms_to_permset(p_ace->perms, &the_permset) == -1) {
1199 DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
1200 p_ace->perms, i, strerror(errno) ));
1205 * ..and apply them to the entry.
1208 if (sys_acl_set_permset(the_entry, the_permset) == -1) {
1209 DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
1210 i, strerror(errno) ));
1215 print_canon_ace( p_ace, i);
1219 * Add in a mask of rwx.
1222 if (sys_acl_create_entry( &the_acl, &mask_entry) == -1) {
1223 DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
1227 if (sys_acl_set_tag_type(mask_entry, SMB_ACL_MASK) == -1) {
1228 DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
1232 if (sys_acl_get_permset(mask_entry, &mask_permset) == -1) {
1233 DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
1237 if (map_acl_perms_to_permset(S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
1238 DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
1242 if (sys_acl_set_permset(mask_entry, mask_permset) == -1) {
1243 DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
1248 * Check if the ACL is valid.
1251 if (sys_acl_valid(the_acl) == -1) {
1252 DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n",
1253 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
1259 * Finally apply it to the file or directory.
1262 if(default_ace || fsp->is_directory || fsp->fd == -1) {
1263 if (sys_acl_set_file(dos_to_unix(fsp->fsp_name,False), the_acl_type, the_acl) == -1) {
1264 DEBUG(0,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
1265 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
1266 fsp->fsp_name, strerror(errno) ));
1270 if (sys_acl_set_fd(fsp->fd, the_acl) == -1) {
1271 DEBUG(0,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
1272 fsp->fsp_name, strerror(errno) ));
1281 if (the_acl != NULL)
1282 sys_acl_free_acl(the_acl);
1287 /****************************************************************************
1288 Reply to query a security descriptor from an fsp. If it succeeds it allocates
1289 the space for the return elements and returns the size needed to return the
1290 security descriptor. This should be the only external function needed for
1291 the UNIX style get ACL.
1292 ****************************************************************************/
1294 size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
1296 SMB_STRUCT_STAT sbuf;
1297 SEC_ACE *nt_ace_list;
1301 SEC_ACL *psa = NULL;
1302 size_t num_acls = 0;
1303 size_t num_dir_acls = 0;
1304 size_t num_aces = 0;
1305 SMB_ACL_T posix_acl = NULL;
1306 SMB_ACL_T dir_acl = NULL;
1307 canon_ace *file_ace = NULL;
1308 canon_ace *dir_ace = NULL;
1312 DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name ));
1314 if(fsp->is_directory || fsp->fd == -1) {
1316 /* Get the stat struct for the owner info. */
1317 if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
1321 * Get the ACL from the path.
1324 posix_acl = sys_acl_get_file( dos_to_unix(fsp->fsp_name, False), SMB_ACL_TYPE_ACCESS);
1327 * If it's a directory get the default POSIX ACL.
1330 if(fsp->is_directory)
1331 dir_acl = sys_acl_get_file( dos_to_unix(fsp->fsp_name, False), SMB_ACL_TYPE_DEFAULT);
1335 /* Get the stat struct for the owner info. */
1336 if(vfs_fstat(fsp,fsp->fd,&sbuf) != 0) {
1340 * Get the ACL from the fd.
1342 posix_acl = sys_acl_get_fd(fsp->fd);
1345 DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
1346 posix_acl ? "present" : "absent",
1347 dir_acl ? "present" : "absent" ));
1350 * Get the owner, group and world SIDs.
1353 create_file_sids(&sbuf, &owner_sid, &group_sid);
1355 /* Create the canon_ace lists. */
1357 file_ace = canonicalise_acl( posix_acl, &sbuf);
1359 file_ace = unix_canonicalise_acl(fsp, &sbuf, &owner_sid, &group_sid);
1361 num_acls = count_canon_ace_list(file_ace);
1363 if (fsp->is_directory) {
1365 dir_ace = canonicalise_acl( dir_acl, &sbuf);
1367 dir_ace = unix_canonicalise_acl(fsp, &sbuf, &owner_sid, &group_sid);
1369 num_dir_acls = count_canon_ace_list(dir_ace);
1372 /* Allocate the ace list. */
1373 if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_dir_acls)* sizeof(SEC_ACE))) == NULL) {
1374 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
1378 memset(nt_ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) );
1381 * Create the NT ACE list from the canonical ace lists.
1391 for (i = 0; i < num_acls; i++, ace = ace->next) {
1392 SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
1393 init_sec_ace(&nt_ace_list[num_aces++], &ace->sid, nt_acl_type, acc, 0);
1398 for (i = 0; i < num_dir_acls; i++, ace = ace->next) {
1399 SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
1400 init_sec_ace(&nt_ace_list[num_aces++], &ace->sid, nt_acl_type, acc,
1401 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY);
1406 if((psa = make_sec_acl( ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
1407 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
1412 *ppdesc = make_standard_sec_desc( &owner_sid, &group_sid, psa, &sd_size);
1415 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
1422 sys_acl_free_acl(posix_acl);
1424 sys_acl_free_acl(dir_acl);
1425 free_canon_ace_list(file_ace);
1426 free_canon_ace_list(dir_ace);
1435 /****************************************************************************
1436 Reply to set a security descriptor on an fsp. security_info_sent is the
1437 description of the following NT ACL.
1438 This should be the only external function needed for the UNIX style set ACL.
1439 ****************************************************************************/
1441 BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
1443 connection_struct *conn = fsp->conn;
1444 uid_t user = (uid_t)-1;
1445 gid_t grp = (gid_t)-1;
1447 SMB_STRUCT_STAT sbuf;
1448 DOM_SID file_owner_sid;
1449 DOM_SID file_grp_sid;
1450 canon_ace *file_ace_list = NULL;
1451 canon_ace *dir_ace_list = NULL;
1455 DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
1458 * Get the current state of the file.
1461 if(fsp->is_directory || fsp->fd == -1) {
1462 if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0)
1465 if(vfs_fstat(fsp,fsp->fd,&sbuf) != 0)
1470 * Unpack the user/group/world id's.
1473 if (!unpack_nt_owners( &sbuf, &user, &grp, security_info_sent, psd))
1477 * Do we need to chown ?
1480 if((user != (uid_t)-1 || grp != (uid_t)-1) && (sbuf.st_uid != user || sbuf.st_gid != grp)) {
1482 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
1483 fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
1485 if(vfs_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
1486 DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
1487 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
1492 * Recheck the current state of the file, which may have changed.
1493 * (suid/sgid bits, for instance)
1496 if(fsp->is_directory) {
1497 if(vfs_stat(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
1505 ret = vfs_stat(fsp->conn, fsp->fsp_name, &sbuf);
1507 ret = vfs_fstat(fsp,fsp->fd,&sbuf);
1514 create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
1516 acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
1517 &file_ace_list, &dir_ace_list, security_info_sent, psd);
1518 posix_perms = unpack_posix_permissions( fsp, &sbuf, &perms, security_info_sent, psd, acl_perms);
1520 if (!posix_perms && !acl_perms) {
1522 * Neither method of setting permissions can work. Fail here.
1525 DEBUG(3,("set_nt_acl: cannot set normal POSIX permissions or POSIX ACL permissions\n"));
1526 free_canon_ace_list(file_ace_list);
1527 free_canon_ace_list(dir_ace_list);
1532 * Only change security if we got a DACL.
1535 if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
1537 BOOL acl_set_support = False;
1541 * Try using the POSIX ACL set first. All back to chmod if
1542 * we have no ACL support on this filesystem.
1545 if (acl_perms && file_ace_list) {
1546 ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support);
1547 if (acl_set_support && ret == False) {
1548 DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
1549 free_canon_ace_list(file_ace_list);
1550 free_canon_ace_list(dir_ace_list);
1555 if (acl_perms && acl_set_support && fsp->is_directory && dir_ace_list) {
1556 if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) {
1557 DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
1558 free_canon_ace_list(file_ace_list);
1559 free_canon_ace_list(dir_ace_list);
1565 * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
1568 if(!acl_set_support && posix_perms && (sbuf.st_mode != perms)) {
1570 free_canon_ace_list(file_ace_list);
1571 free_canon_ace_list(dir_ace_list);
1572 file_ace_list = NULL;
1573 dir_ace_list = NULL;
1575 DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
1576 fsp->fsp_name, (unsigned int)perms ));
1578 if(conn->vfs_ops.chmod(conn,dos_to_unix(fsp->fsp_name, False), perms) == -1) {
1579 DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
1580 fsp->fsp_name, (unsigned int)perms, strerror(errno) ));
1586 free_canon_ace_list(file_ace_list);
1587 free_canon_ace_list(dir_ace_list);
1592 /****************************************************************************
1593 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
1594 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
1595 ****************************************************************************/
1597 static int chmod_acl_internals( SMB_ACL_T posix_acl, mode_t mode)
1599 int entry_id = SMB_ACL_FIRST_ENTRY;
1600 SMB_ACL_ENTRY_T entry;
1601 int num_entries = 0;
1603 while ( sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
1604 SMB_ACL_TAG_T tagtype;
1605 SMB_ACL_PERMSET_T permset;
1609 if (entry_id == SMB_ACL_FIRST_ENTRY)
1610 entry_id = SMB_ACL_NEXT_ENTRY;
1612 if (sys_acl_get_tag_type(entry, &tagtype) == -1)
1615 if (sys_acl_get_permset(entry, &permset) == -1)
1621 case SMB_ACL_USER_OBJ:
1622 perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
1624 case SMB_ACL_GROUP_OBJ:
1625 perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
1628 perms = S_IRUSR|S_IWUSR|S_IXUSR;
1631 perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
1637 if (map_acl_perms_to_permset(perms, &permset) == -1)
1640 if (sys_acl_set_permset(entry, permset) == -1)
1645 * If this is a simple 3 element ACL then it's a standard
1646 * UNIX permission set. Just use chmod...
1649 if (num_entries == 3)
1655 /****************************************************************************
1656 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
1657 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
1658 Note that name is in UNIX character set.
1659 ****************************************************************************/
1661 int chmod_acl(char *name, mode_t mode)
1663 SMB_ACL_T posix_acl = NULL;
1666 if ((posix_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS)) == NULL)
1669 if ((ret = chmod_acl_internals(posix_acl, mode)) == -1)
1672 ret = sys_acl_set_file(name, SMB_ACL_TYPE_ACCESS, posix_acl);
1676 sys_acl_free_acl(posix_acl);
1680 /****************************************************************************
1681 Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
1682 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
1683 ****************************************************************************/
1685 int fchmod_acl(int fd, mode_t mode)
1687 SMB_ACL_T posix_acl = NULL;
1690 if ((posix_acl = sys_acl_get_fd(fd)) == NULL)
1693 if ((ret = chmod_acl_internals(posix_acl, mode)) == -1)
1696 ret = sys_acl_set_fd(fd, posix_acl);
1700 sys_acl_free_acl(posix_acl);