2 Unix SMB/Netbios implementation.
4 SMB NT Security Descriptor / Unix permission conversion.
5 Copyright (C) Jeremy Allison 1994-2000
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 enum ace_owner {UID_ACE, GID_ACE, WORLD_ACE};
26 typedef union posix_id {
32 typedef struct canon_ace {
33 struct canon_ace *next, *prev;
35 mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */
37 enum ace_owner owner_type;
41 static void free_canon_ace_list( canon_ace *list_head );
43 #if !defined(HAVE_NO_ACLS)
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;
59 #endif /* HAVE_NO_ACLS */
61 /****************************************************************************
62 Function to create owner and group SIDs from a SMB_STRUCT_STAT.
63 ****************************************************************************/
65 static void create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
67 uid_to_sid( powner_sid, psbuf->st_uid );
68 gid_to_sid( pgroup_sid, psbuf->st_gid );
71 /****************************************************************************
72 Print out a canon ace.
73 ****************************************************************************/
75 static void print_canon_ace(canon_ace *ace, int num)
79 dbgtext( "canon_ace index %d.", num );
80 dbgtext( "SID = %s ", sid_to_string( str, &ace->sid));
81 if (ace->owner_type == UID_ACE) {
82 struct passwd *pass = sys_getpwuid(ace->unix_ug.uid);
83 dbgtext( "uid %u (%s) ", (unsigned int)ace->unix_ug.uid, pass ? pass->pw_name : "UNKNOWN");
84 } else if (ace->owner_type == GID_ACE) {
85 struct group *grp = getgrgid(ace->unix_ug.gid);
86 dbgtext( "gid %u (%s) ", (unsigned int)ace->unix_ug.gid, grp ? grp->gr_name : "UNKNOWN");
91 dbgtext( "SMB_ACL_USER ");
93 case SMB_ACL_USER_OBJ:
94 dbgtext( "SMB_ACL_USER_OBJ ");
97 dbgtext( "SMB_ACL_GROUP ");
99 case SMB_ACL_GROUP_OBJ:
100 dbgtext( "SMB_ACL_GROUP_OBJ ");
103 dbgtext( "SMB_ACL_OTHER ");
107 dbgtext( "%c", ace->perms & S_IRUSR ? 'r' : '-');
108 dbgtext( "%c", ace->perms & S_IWUSR ? 'w' : '-');
109 dbgtext( "%c\n", ace->perms & S_IXUSR ? 'x' : '-');
112 /****************************************************************************
113 Map canon_ace perms to permission bits NT.
114 ****************************************************************************/
116 static SEC_ACCESS map_canon_ace_perms(int *pacl_type, DOM_SID *powner_sid, canon_ace *ace)
121 *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
123 if((ace->perms & (S_IRUSR|S_IWUSR|S_IXUSR)) == (S_IRUSR|S_IWUSR|S_IXUSR)) {
124 nt_mask = UNIX_ACCESS_RWX;
125 } else if((ace->perms & (S_IRUSR|S_IWUSR|S_IXUSR)) == 0) {
127 * Here we differentiate between the owner and any other user.
129 if (sid_equal(powner_sid, &ace->sid)) {
130 nt_mask = UNIX_ACCESS_NONE;
132 /* Not owner, no access. */
133 *pacl_type = SEC_ACE_TYPE_ACCESS_DENIED;
134 nt_mask = GENERIC_ALL_ACCESS;
137 nt_mask |= ((ace->perms & S_IRUSR) ? UNIX_ACCESS_R : 0 );
138 nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
139 nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_ACCESS_X : 0 );
142 DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
143 (unsigned int)ace->perms, (unsigned int)nt_mask ));
145 init_sec_access(&sa,nt_mask);
149 /****************************************************************************
150 Map NT perms to a UNIX mode_t.
151 ****************************************************************************/
153 #define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
154 #define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
155 #define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
157 static mode_t map_nt_perms( SEC_ACCESS sec_access, int type)
163 if(sec_access.mask & GENERIC_ALL_ACCESS)
164 mode = S_IRUSR|S_IWUSR|S_IXUSR;
166 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
167 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
168 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
172 if(sec_access.mask & GENERIC_ALL_ACCESS)
173 mode = S_IRGRP|S_IWGRP|S_IXGRP;
175 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
176 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
177 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
181 if(sec_access.mask & GENERIC_ALL_ACCESS)
182 mode = S_IROTH|S_IWOTH|S_IXOTH;
184 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
185 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
186 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
194 /****************************************************************************
195 Unpack a SEC_DESC into a UNIX owner and group.
196 ****************************************************************************/
198 static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
202 enum SID_NAME_USE sid_type;
207 if(security_info_sent == 0) {
208 DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
213 * Validate the owner and group SID's.
216 memset(&owner_sid, '\0', sizeof(owner_sid));
217 memset(&grp_sid, '\0', sizeof(grp_sid));
219 DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
222 * Don't immediately fail if the owner sid cannot be validated.
223 * This may be a group chown only set.
226 if (security_info_sent & OWNER_SECURITY_INFORMATION) {
227 sid_copy(&owner_sid, psd->owner_sid);
228 if (!sid_to_uid( &owner_sid, puser, &sid_type))
229 DEBUG(3,("unpack_nt_owners: unable to validate owner sid.\n"));
233 * Don't immediately fail if the group sid cannot be validated.
234 * This may be an owner chown only set.
237 if (security_info_sent & GROUP_SECURITY_INFORMATION) {
238 sid_copy(&grp_sid, psd->grp_sid);
239 if (!sid_to_gid( &grp_sid, pgrp, &sid_type))
240 DEBUG(3,("unpack_nt_owners: unable to validate group sid.\n"));
243 DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
248 #if !defined(HAVE_NO_ACLS)
249 /****************************************************************************
250 Merge aces with a common user.
251 ****************************************************************************/
253 static BOOL merge_aces( canon_ace *list_head, canon_ace *p_ace)
257 for (curr_ace = list_head; curr_ace; curr_ace = curr_ace->next) {
258 if (curr_ace == p_ace)
261 if (curr_ace->type == p_ace->type && sid_equal(&curr_ace->sid, &p_ace->sid)) {
262 if( DEBUGLVL( 10 )) {
263 dbgtext("Merging ACE's\n");
264 print_canon_ace( p_ace, 0);
265 print_canon_ace( curr_ace, 0);
267 p_ace->perms |= curr_ace->perms;
268 DLIST_REMOVE(list_head, curr_ace);
277 /****************************************************************************
278 Create a default mode for a directory default ACE.
279 ****************************************************************************/
281 static mode_t get_default_ace_mode(files_struct *fsp, int type)
283 mode_t force_mode = lp_force_dir_security_mode(SNUM(fsp->conn));
288 mode |= (force_mode & S_IRUSR) ? S_IRUSR : 0;
289 mode |= (force_mode & S_IWUSR) ? S_IWUSR : 0;
290 mode |= (force_mode & S_IXUSR) ? S_IXUSR : 0;
293 mode |= (force_mode & S_IRGRP) ? S_IRUSR : 0;
294 mode |= (force_mode & S_IWGRP) ? S_IWUSR : 0;
295 mode |= (force_mode & S_IXGRP) ? S_IXUSR : 0;
298 mode |= (force_mode & S_IROTH) ? S_IRUSR : 0;
299 mode |= (force_mode & S_IWOTH) ? S_IWUSR : 0;
300 mode |= (force_mode & S_IXOTH) ? S_IXUSR : 0;
307 /****************************************************************************
308 A well formed POSIX file or default ACL has at least 3 entries, a
309 SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
310 ****************************************************************************/
312 static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
314 DOM_SID *pfile_owner_sid,
315 DOM_SID *pfile_grp_sid,
316 SMB_STRUCT_STAT *pst,
319 extern DOM_SID global_sid_World;
321 BOOL got_user = False;
322 BOOL got_grp = False;
323 BOOL got_other = False;
325 for (pace = *pp_ace; pace; pace = pace->next) {
326 if (pace->type == SMB_ACL_USER_OBJ)
328 else if (pace->type == SMB_ACL_GROUP_OBJ)
330 else if (pace->type == SMB_ACL_OTHER)
335 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
336 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
341 pace->type = SMB_ACL_USER_OBJ;
342 pace->owner_type = UID_ACE;
343 pace->unix_ug.uid = pst->st_uid;
344 pace->sid = *pfile_owner_sid;
345 pace->perms = default_acl ? get_default_ace_mode(fsp, S_IRUSR): 0;
347 DLIST_ADD(*pp_ace, pace);
351 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
352 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
357 pace->type = SMB_ACL_GROUP_OBJ;
358 pace->owner_type = GID_ACE;
359 pace->unix_ug.uid = pst->st_gid;
360 pace->sid = *pfile_grp_sid;
361 pace->perms = default_acl ? get_default_ace_mode(fsp, S_IRGRP): 0;
363 DLIST_ADD(*pp_ace, pace);
367 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
368 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
373 pace->type = SMB_ACL_OTHER;
374 pace->owner_type = WORLD_ACE;
375 pace->unix_ug.world = -1;
376 pace->sid = global_sid_World;
377 pace->perms = default_acl ? get_default_ace_mode(fsp, S_IROTH): 0;
379 DLIST_ADD(*pp_ace, pace);
384 #endif /* HAVE_NO_ACLS */
386 /****************************************************************************
387 Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
389 ****************************************************************************/
391 static BOOL unpack_canon_ace(files_struct *fsp,
392 SMB_STRUCT_STAT *pst,
393 DOM_SID *pfile_owner_sid,
394 DOM_SID *pfile_grp_sid,
395 canon_ace **ppfile_ace, canon_ace **ppdir_ace,
396 uint32 security_info_sent, SEC_DESC *psd)
398 #if !defined(HAVE_NO_ACLS)
399 extern DOM_SID global_sid_World;
400 BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
401 canon_ace *file_ace = NULL;
402 canon_ace *dir_ace = NULL;
403 canon_ace *current_ace = NULL;
404 enum SID_NAME_USE sid_type;
406 #endif /* HAVE_NO_ACLS */
407 SEC_ACL *dacl = psd->dacl;
412 if(security_info_sent == 0) {
413 DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
418 * If no DACL then this is a chown only security descriptor.
421 if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !dacl)
424 #if defined(HAVE_NO_ACLS)
426 /* No point in doing this if we have no ACL support. */
429 #else /* HAVE_NO_ACLS */
432 * Now go through the DACL and create the canon_ace lists.
435 for(i = 0; i < dacl->num_aces; i++) {
436 SEC_ACE *psa = &dacl->ace[i];
438 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
439 DEBUG(3,("unpack_canon_ace: unable to set anything but an ALLOW or DENY ACE.\n"));
444 * The security mask may be UNIX_ACCESS_NONE which should map into
445 * no permissions (we overload the WRITE_OWNER bit for this) or it
446 * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
447 * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
450 psa->info.mask &= (GENERIC_ALL_ACCESS|GENERIC_EXECUTE_ACCESS|GENERIC_WRITE_ACCESS|
451 GENERIC_READ_ACCESS|UNIX_ACCESS_NONE|FILE_ALL_ATTRIBUTES);
453 if(psa->info.mask != UNIX_ACCESS_NONE)
454 psa->info.mask &= ~UNIX_ACCESS_NONE;
457 * Create a cannon_ace entry representing this NT DACL ACE.
460 if ((current_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
461 free_canon_ace_list(file_ace);
462 free_canon_ace_list(dir_ace);
463 DEBUG(0,("unpack_canon_ace: malloc fail.\n"));
467 ZERO_STRUCTP(current_ace);
469 sid_copy(¤t_ace->sid, &psa->sid);
472 * Try and work out if the SID is a user or group
473 * as we need to flag these differently for POSIX.
476 if( sid_equal(¤t_ace->sid, &global_sid_World)) {
477 current_ace->owner_type = WORLD_ACE;
478 current_ace->unix_ug.world = -1;
479 } else if (sid_to_uid( ¤t_ace->sid, ¤t_ace->unix_ug.uid, &sid_type)) {
480 current_ace->owner_type = UID_ACE;
481 } else if (sid_to_gid( ¤t_ace->sid, ¤t_ace->unix_ug.gid, &sid_type)) {
482 current_ace->owner_type = GID_ACE;
486 free_canon_ace_list(file_ace);
487 free_canon_ace_list(dir_ace);
489 DEBUG(0,("unpack_canon_ace: unable to map SID %s to uid or gid.\n",
490 sid_to_string(str, ¤t_ace->sid) ));
495 * Map the given NT permissions into a UNIX mode_t containing only
496 * S_I(R|W|X)USR bits.
499 if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
500 current_ace->perms |= map_nt_perms( psa->info, S_IRUSR);
502 current_ace->perms = 0;
505 * Now note what kind of a POSIX ACL this should map to.
508 if(sid_equal(¤t_ace->sid, pfile_owner_sid)) {
509 /* Note we should apply the default mode/mask here.... FIXME ! JRA */
510 current_ace->type = SMB_ACL_USER_OBJ;
511 } else if( sid_equal(¤t_ace->sid, pfile_grp_sid)) {
512 /* Note we should apply the default mode/mask here.... FIXME ! JRA */
513 current_ace->type = SMB_ACL_GROUP_OBJ;
514 } else if( sid_equal(¤t_ace->sid, &global_sid_World)) {
515 /* Note we should apply the default mode/mask here.... FIXME ! JRA */
516 current_ace->type = SMB_ACL_OTHER;
519 * Could be a SMB_ACL_USER or SMB_ACL_GROUP. Check by
520 * looking at owner_type.
523 current_ace->type = (current_ace->owner_type == UID_ACE) ? SMB_ACL_USER : SMB_ACL_GROUP;
526 if (fsp->is_directory) {
529 * We can only add to the default POSIX ACE list if the ACE is
530 * designed to be inherited by both files and directories.
532 if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
533 (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
534 DLIST_ADD(dir_ace, current_ace);
537 * If this is not an inherit only ACE we need to add a duplicate
541 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
542 canon_ace *dup_ace = dup_canon_ace(current_ace);
545 DEBUG(0,("unpack_canon_ace: malloc fail !\n"));
546 free_canon_ace_list(file_ace);
547 free_canon_ace_list(dir_ace);
551 current_ace = dup_ace;
559 * Only add to the file ACL if not inherit only.
562 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
563 DLIST_ADD(file_ace, current_ace);
564 all_aces_are_inherit_only = False;
569 * Free if ACE was not addedd.
576 if (fsp->is_directory && all_aces_are_inherit_only) {
578 * Windows 2000 is doing one of these weird 'inherit acl'
579 * traverses to conserve NTFS ACL resources. Just pretend
580 * there was no DACL sent. JRA.
583 DEBUG(10,("unpack_canon_ace: Win2k inherit acl traverse. Ignoring DACL.\n"));
587 * Now go through the canon_ace lists and merge entries
588 * belonging to identical users.
593 for (current_ace = file_ace; current_ace; current_ace = current_ace->next ) {
594 if (merge_aces( file_ace, current_ace))
600 for (current_ace = dir_ace; current_ace; current_ace = current_ace->next ) {
601 if (merge_aces( dir_ace, current_ace))
606 * A well formed POSIX file or default ACL has at least 3 entries, a
607 * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
608 * and optionally a mask entry. Ensure this is the case.
611 if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, False)) {
612 free_canon_ace_list(file_ace);
613 free_canon_ace_list(dir_ace);
617 if (!ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
618 free_canon_ace_list(file_ace);
619 free_canon_ace_list(dir_ace);
623 if( DEBUGLVL( 10 )) {
624 dbgtext("unpack_canon_ace: File ACL:\n");
625 for (i = 0, current_ace = file_ace; current_ace; current_ace = current_ace->next, i++ ) {
626 print_canon_ace( current_ace, i);
629 dbgtext("unpack_canon_ace: Directory ACL:\n");
630 for (i = 0, current_ace = dir_ace; current_ace; current_ace = current_ace->next, i++ ) {
631 print_canon_ace( current_ace, i);
635 *ppfile_ace = file_ace;
636 *ppdir_ace = dir_ace;
639 #endif /* HAVE_NO_ACLS */
642 /****************************************************************************
643 Unpack a SEC_DESC into a set of standard POSIX permissions.
644 ****************************************************************************/
646 static BOOL unpack_posix_permissions(files_struct *fsp, SMB_STRUCT_STAT *psbuf, mode_t *pmode,
647 uint32 security_info_sent, SEC_DESC *psd, BOOL posix_acls)
649 extern DOM_SID global_sid_World;
650 connection_struct *conn = fsp->conn;
651 DOM_SID file_owner_sid;
652 DOM_SID file_grp_sid;
653 SEC_ACL *dacl = psd->dacl;
654 BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
659 if(security_info_sent == 0) {
660 DEBUG(0,("unpack_posix_permissions: no security info sent !\n"));
665 * Windows 2000 sends the owner and group SIDs as the logged in
666 * user, not the connected user. But it still sends the file
667 * owner SIDs on an ACL set. So we need to check for the file
668 * owner and group SIDs as well as the owner SIDs. JRA.
671 create_file_sids(psbuf, &file_owner_sid, &file_grp_sid);
674 * If no DACL then this is a chown only security descriptor.
677 if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !dacl) {
683 * Now go through the DACL and ensure that
684 * any owner/group sids match.
687 for(i = 0; i < dacl->num_aces; i++) {
689 SEC_ACE *psa = &dacl->ace[i];
691 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) &&
692 (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
693 DEBUG(3,("unpack_posix_permissions: unable to set anything but an ALLOW or DENY ACE.\n"));
698 * Ignore or remove bits we don't care about on a directory ACE.
701 if(fsp->is_directory) {
702 if(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
703 DEBUG(3,("unpack_posix_permissions: ignoring inherit only ACE.\n"));
708 * At least one of the ACE entries wasn't inherit only.
709 * Flag this so we know the returned mode is valid.
712 all_aces_are_inherit_only = False;
716 * Windows 2000 sets these flags even on *file* ACE's. This is wrong
717 * but we can ignore them for now. Revisit this when we go to POSIX
718 * ACLs on directories.
721 psa->flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERITED_ACE);
723 if(psa->flags != 0) {
724 DEBUG(1,("unpack_posix_permissions: unable to set ACE flags (%x).\n",
725 (unsigned int)psa->flags));
730 * The security mask may be UNIX_ACCESS_NONE which should map into
731 * no permissions (we overload the WRITE_OWNER bit for this) or it
732 * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
733 * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
736 psa->info.mask &= (GENERIC_ALL_ACCESS|GENERIC_EXECUTE_ACCESS|GENERIC_WRITE_ACCESS|
737 GENERIC_READ_ACCESS|UNIX_ACCESS_NONE|FILE_ALL_ATTRIBUTES);
739 if(psa->info.mask != UNIX_ACCESS_NONE)
740 psa->info.mask &= ~UNIX_ACCESS_NONE;
742 sid_copy(&ace_sid, &psa->sid);
744 if(sid_equal(&ace_sid, &file_owner_sid)) {
746 * Map the desired permissions into owner perms.
749 if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
750 *pmode |= map_nt_perms( psa->info, S_IRUSR);
752 *pmode &= ~(map_nt_perms( psa->info, S_IRUSR));
755 } else if( sid_equal(&ace_sid, &file_grp_sid)) {
757 * Map the desired permissions into group perms.
760 if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
761 *pmode |= map_nt_perms( psa->info, S_IRGRP);
763 *pmode &= ~(map_nt_perms( psa->info, S_IRGRP));
765 } else if( sid_equal(&ace_sid, &global_sid_World)) {
767 * Map the desired permissions into other perms.
770 if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
771 *pmode |= map_nt_perms( psa->info, S_IROTH);
773 *pmode &= ~(map_nt_perms( psa->info, S_IROTH));
777 * Only bother printing the level zero error if we didn't get any
781 DEBUG(0,("unpack_posix_permissions: unknown SID used in ACL.\n"));
786 if (fsp->is_directory && all_aces_are_inherit_only) {
788 * Windows 2000 is doing one of these weird 'inherit acl'
789 * traverses to conserve NTFS ACL resources. Just pretend
790 * there was no DACL sent. JRA.
793 DEBUG(10,("unpack_posix_permissions: Win2k inherit acl traverse. Ignoring DACL.\n"));
797 * Check to see if we need to change anything.
798 * Enforce limits on modified bits *only*. Don't enforce masks
799 * on bits not changed by the user.
802 if(fsp->is_directory) {
804 *pmode &= (lp_dir_security_mask(SNUM(conn)) | psbuf->st_mode);
805 *pmode |= (lp_force_dir_security_mode(SNUM(conn)) & ( *pmode ^ psbuf->st_mode ));
809 *pmode &= (lp_security_mask(SNUM(conn)) | psbuf->st_mode);
810 *pmode |= (lp_force_security_mode(SNUM(conn)) & ( *pmode ^ psbuf->st_mode ));
815 * Preserve special bits.
818 *pmode |= (psbuf->st_mode & ~0777);
823 /****************************************************************************
824 Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
825 ****************************************************************************/
827 static mode_t convert_permset_to_mode_t(SMB_ACL_PERMSET_T permset)
831 ret |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? S_IRUSR : 0);
832 ret |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
833 ret |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
838 /****************************************************************************
839 Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
840 ****************************************************************************/
842 static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
856 /****************************************************************************
857 Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to
858 an SMB_ACL_PERMSET_T.
859 ****************************************************************************/
861 static int map_acl_perms_to_permset(mode_t mode, SMB_ACL_PERMSET_T *p_permset)
863 if (sys_acl_clear_perms(*p_permset) == -1)
865 if (mode & S_IRUSR) {
866 if (sys_acl_add_perm(*p_permset, SMB_ACL_READ) == -1)
869 if (mode & S_IWUSR) {
870 if (sys_acl_add_perm(*p_permset, SMB_ACL_WRITE) == -1)
873 if (mode & S_IXUSR) {
874 if (sys_acl_add_perm(*p_permset, SMB_ACL_EXECUTE) == -1)
880 /****************************************************************************
881 Count a linked list of canonical ACE entries.
882 ****************************************************************************/
884 static size_t count_canon_ace_list( canon_ace *list_head )
889 for (ace = list_head; ace; ace = ace->next)
895 /****************************************************************************
896 Free a linked list of canonical ACE entries.
897 ****************************************************************************/
899 static void free_canon_ace_list( canon_ace *list_head )
902 canon_ace *old_head = list_head;
903 DLIST_REMOVE(list_head, list_head);
908 /******************************************************************************
909 Fall back to the generic 3 element UNIX permissions.
910 ********************************************************************************/
912 static canon_ace *unix_canonicalise_acl(files_struct *fsp, SMB_STRUCT_STAT *psbuf,
913 DOM_SID *powner, DOM_SID *pgroup)
915 extern DOM_SID global_sid_World;
916 canon_ace *list_head = NULL;
917 canon_ace *owner_ace = NULL;
918 canon_ace *group_ace = NULL;
919 canon_ace *other_ace = NULL;
922 * Create 3 linked list entries.
925 if ((owner_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
928 if ((group_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
931 if ((other_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
934 ZERO_STRUCTP(owner_ace);
935 ZERO_STRUCTP(group_ace);
936 ZERO_STRUCTP(other_ace);
938 owner_ace->type = SMB_ACL_USER_OBJ;
939 owner_ace->sid = *powner;
940 owner_ace->unix_ug.uid = psbuf->st_uid;
941 owner_ace->owner_type = UID_ACE;
943 group_ace->type = SMB_ACL_GROUP_OBJ;
944 group_ace->sid = *pgroup;
945 group_ace->unix_ug.gid = psbuf->st_gid;
946 group_ace->owner_type = GID_ACE;
948 other_ace->type = SMB_ACL_OTHER;
949 other_ace->sid = global_sid_World;
950 other_ace->unix_ug.world = -1;
951 other_ace->owner_type = WORLD_ACE;
953 if (!fsp->is_directory) {
954 owner_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
955 group_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
956 other_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
958 mode_t mode = unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name);
960 owner_ace->perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
961 group_ace->perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
962 other_ace->perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
965 if (other_ace->perms) {
966 DLIST_ADD(list_head, other_ace);
968 safe_free(other_ace);
969 if (group_ace->perms) {
970 DLIST_ADD(list_head, group_ace);
972 safe_free(group_ace);
973 if (owner_ace->perms) {
974 DLIST_ADD(list_head, owner_ace);
976 safe_free(owner_ace);
978 if (list_head == NULL) {
980 * Return an "Everyone" NO ACCESS ace.
983 if ((other_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
986 other_ace->type = SMB_ACL_OTHER;
987 other_ace->sid = global_sid_World;
988 other_ace->unix_ug.world = -1;
989 other_ace->owner_type = WORLD_ACE;
990 other_ace->perms = (mode_t)0;
992 DLIST_ADD(list_head, other_ace);
999 safe_free(owner_ace);
1000 safe_free(group_ace);
1001 safe_free(other_ace);
1006 /****************************************************************************
1007 Create a linked list of canonical ACE entries. This is sorted so that DENY
1008 entries are at the front of the list, as NT requires.
1009 ****************************************************************************/
1011 static canon_ace *canonicalise_acl( SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf)
1013 extern DOM_SID global_sid_World;
1014 mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
1015 canon_ace *list_head = NULL;
1016 canon_ace *ace = NULL;
1017 canon_ace *next_ace = NULL;
1018 int entry_id = SMB_ACL_FIRST_ENTRY;
1019 SMB_ACL_ENTRY_T entry;
1021 while ( sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
1022 SMB_ACL_TAG_T tagtype;
1023 SMB_ACL_PERMSET_T permset;
1026 enum ace_owner owner_type;
1029 if (entry_id == SMB_ACL_FIRST_ENTRY)
1030 entry_id = SMB_ACL_NEXT_ENTRY;
1032 /* Is this a MASK entry ? */
1033 if (sys_acl_get_tag_type(entry, &tagtype) == -1)
1036 if (sys_acl_get_permset(entry, &permset) == -1)
1039 /* Decide which SID to use based on the ACL type. */
1041 case SMB_ACL_USER_OBJ:
1042 /* Get the SID from the owner. */
1043 uid_to_sid( &sid, psbuf->st_uid );
1044 unix_ug.uid = psbuf->st_uid;
1045 owner_type = UID_ACE;
1049 uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
1051 DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
1054 uid_to_sid( &sid, *puid);
1055 unix_ug.uid = *puid;
1056 owner_type = UID_ACE;
1059 case SMB_ACL_GROUP_OBJ:
1060 /* Get the SID from the owning group. */
1061 gid_to_sid( &sid, psbuf->st_gid );
1062 unix_ug.gid = psbuf->st_gid;
1063 owner_type = GID_ACE;
1067 gid_t *pgid = (gid_t *)sys_acl_get_qualifier(entry);
1069 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
1072 gid_to_sid( &sid, *pgid);
1073 unix_ug.gid = *pgid;
1074 owner_type = GID_ACE;
1078 acl_mask = convert_permset_to_mode_t(permset);
1079 continue; /* Don't count the mask as an entry. */
1081 /* Use the Everyone SID */
1082 sid = global_sid_World;
1084 owner_type = WORLD_ACE;
1087 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
1092 * Add this entry to the list.
1095 if ((ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
1099 ace->type = tagtype;
1100 ace->perms = convert_permset_to_mode_t(permset);
1102 ace->unix_ug = unix_ug;
1103 ace->owner_type = owner_type;
1105 DLIST_ADD(list_head, ace);
1109 * Now go through the list, masking the permissions with the
1110 * acl_mask. If the permissions are 0 it should be listed
1114 for ( ace = list_head; ace; ace = next_ace) {
1115 next_ace = ace->next;
1117 /* Masks are only applied to entries other than USER_OBJ and OTHER. */
1118 if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
1119 ace->perms &= acl_mask;
1121 if (ace->perms == 0)
1122 DLIST_PROMOTE(list_head, ace);
1125 if( DEBUGLVL( 10 ) ) {
1126 char *acl_text = sys_acl_to_text( posix_acl, NULL);
1128 dbgtext("canonicalize_acl: processed acl %s\n", acl_text == NULL ? "NULL" : acl_text );
1130 sys_acl_free_text(acl_text);
1137 free_canon_ace_list(list_head);
1141 /****************************************************************************
1142 Attempt to apply an ACL to a file or directory.
1143 ****************************************************************************/
1145 static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, BOOL *pacl_set_support)
1148 SMB_ACL_T the_acl = sys_acl_init((int)count_canon_ace_list(the_ace) + 1);
1151 SMB_ACL_ENTRY_T mask_entry;
1152 SMB_ACL_PERMSET_T mask_permset;
1153 SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
1155 if (the_acl == NULL) {
1156 #if !defined(HAVE_NO_ACLS)
1158 * Only print this error message if we have some kind of ACL
1159 * support that's not working. Otherwise we would always get this.
1161 DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
1162 default_ace ? "default" : "file", strerror(errno) ));
1164 *pacl_set_support = False;
1168 for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
1169 SMB_ACL_ENTRY_T the_entry;
1170 SMB_ACL_PERMSET_T the_permset;
1173 * Get the entry for this ACE.
1176 if (sys_acl_create_entry( &the_acl, &the_entry) == -1) {
1177 DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
1178 i, strerror(errno) ));
1183 * Ok - we now know the ACL calls should be working, don't
1184 * allow fallback to chmod.
1187 *pacl_set_support = True;
1190 * Initialise the entry from the canon_ace.
1194 * First tell the entry what type of ACE this is.
1197 if (sys_acl_set_tag_type(the_entry, p_ace->type) == -1) {
1198 DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
1199 i, strerror(errno) ));
1204 * Only set the qualifier (user or group id) if the entry is a user
1208 if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
1209 if (sys_acl_set_qualifier(the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
1210 DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
1211 i, strerror(errno) ));
1217 * Convert the mode_t perms in the canon_ace to a POSIX permset.
1220 if (sys_acl_get_permset(the_entry, &the_permset) == -1) {
1221 DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
1222 i, strerror(errno) ));
1226 if (map_acl_perms_to_permset(p_ace->perms, &the_permset) == -1) {
1227 DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
1228 p_ace->perms, i, strerror(errno) ));
1233 * ..and apply them to the entry.
1236 if (sys_acl_set_permset(the_entry, the_permset) == -1) {
1237 DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
1238 i, strerror(errno) ));
1243 print_canon_ace( p_ace, i);
1247 * Add in a mask of rwx.
1250 if (sys_acl_create_entry( &the_acl, &mask_entry) == -1) {
1251 DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
1255 if (sys_acl_set_tag_type(mask_entry, SMB_ACL_MASK) == -1) {
1256 DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
1260 if (sys_acl_get_permset(mask_entry, &mask_permset) == -1) {
1261 DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
1265 if (map_acl_perms_to_permset(S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
1266 DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
1270 if (sys_acl_set_permset(mask_entry, mask_permset) == -1) {
1271 DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
1276 * Check if the ACL is valid.
1279 if (sys_acl_valid(the_acl) == -1) {
1280 DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n",
1281 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
1287 * Finally apply it to the file or directory.
1290 if(default_ace || fsp->is_directory || fsp->fd == -1) {
1291 if (sys_acl_set_file(dos_to_unix(fsp->fsp_name,False), the_acl_type, the_acl) == -1) {
1292 DEBUG(0,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
1293 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
1294 fsp->fsp_name, strerror(errno) ));
1298 if (sys_acl_set_fd(fsp->fd, the_acl) == -1) {
1299 DEBUG(0,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
1300 fsp->fsp_name, strerror(errno) ));
1309 if (the_acl != NULL)
1310 sys_acl_free_acl(the_acl);
1315 /****************************************************************************
1316 Reply to query a security descriptor from an fsp. If it succeeds it allocates
1317 the space for the return elements and returns the size needed to return the
1318 security descriptor. This should be the only external function needed for
1319 the UNIX style get ACL.
1320 ****************************************************************************/
1322 size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
1324 SMB_STRUCT_STAT sbuf;
1325 SEC_ACE *nt_ace_list = NULL;
1329 SEC_ACL *psa = NULL;
1330 size_t num_acls = 0;
1331 size_t num_dir_acls = 0;
1332 size_t num_aces = 0;
1333 SMB_ACL_T posix_acl = NULL;
1334 SMB_ACL_T dir_acl = NULL;
1335 canon_ace *file_ace = NULL;
1336 canon_ace *dir_ace = NULL;
1340 DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name ));
1342 if(fsp->is_directory || fsp->fd == -1) {
1344 /* Get the stat struct for the owner info. */
1345 if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
1349 * Get the ACL from the path.
1352 posix_acl = sys_acl_get_file( dos_to_unix(fsp->fsp_name, False), SMB_ACL_TYPE_ACCESS);
1355 * If it's a directory get the default POSIX ACL.
1358 if(fsp->is_directory)
1359 dir_acl = sys_acl_get_file( dos_to_unix(fsp->fsp_name, False), SMB_ACL_TYPE_DEFAULT);
1363 /* Get the stat struct for the owner info. */
1364 if(vfs_fstat(fsp,fsp->fd,&sbuf) != 0) {
1368 * Get the ACL from the fd.
1370 posix_acl = sys_acl_get_fd(fsp->fd);
1373 DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
1374 posix_acl ? "present" : "absent",
1375 dir_acl ? "present" : "absent" ));
1378 * Get the owner, group and world SIDs.
1381 create_file_sids(&sbuf, &owner_sid, &group_sid);
1383 /* Create the canon_ace lists. */
1385 file_ace = canonicalise_acl( posix_acl, &sbuf);
1387 file_ace = unix_canonicalise_acl(fsp, &sbuf, &owner_sid, &group_sid);
1389 num_acls = count_canon_ace_list(file_ace);
1391 if (fsp->is_directory) {
1393 dir_ace = canonicalise_acl( dir_acl, &sbuf);
1395 dir_ace = unix_canonicalise_acl(fsp, &sbuf, &owner_sid, &group_sid);
1397 num_dir_acls = count_canon_ace_list(dir_ace);
1400 if ((num_acls + num_dir_acls) != 0) {
1401 /* Allocate the ace list. */
1402 if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_dir_acls)* sizeof(SEC_ACE))) == NULL) {
1403 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
1407 memset(nt_ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) );
1411 * Create the NT ACE list from the canonical ace lists.
1421 for (i = 0; i < num_acls; i++, ace = ace->next) {
1422 SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
1423 init_sec_ace(&nt_ace_list[num_aces++], &ace->sid, nt_acl_type, acc, 0);
1428 for (i = 0; i < num_dir_acls; i++, ace = ace->next) {
1429 SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
1430 init_sec_ace(&nt_ace_list[num_aces++], &ace->sid, nt_acl_type, acc,
1431 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY);
1436 if((psa = make_sec_acl( main_loop_talloc_get(), ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
1437 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
1442 *ppdesc = make_standard_sec_desc( main_loop_talloc_get(), &owner_sid, &group_sid, psa, &sd_size);
1445 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
1452 sys_acl_free_acl(posix_acl);
1454 sys_acl_free_acl(dir_acl);
1455 free_canon_ace_list(file_ace);
1456 free_canon_ace_list(dir_ace);
1463 /****************************************************************************
1464 Reply to set a security descriptor on an fsp. security_info_sent is the
1465 description of the following NT ACL.
1466 This should be the only external function needed for the UNIX style set ACL.
1467 ****************************************************************************/
1469 BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
1471 connection_struct *conn = fsp->conn;
1472 uid_t user = (uid_t)-1;
1473 gid_t grp = (gid_t)-1;
1475 SMB_STRUCT_STAT sbuf;
1476 DOM_SID file_owner_sid;
1477 DOM_SID file_grp_sid;
1478 canon_ace *file_ace_list = NULL;
1479 canon_ace *dir_ace_list = NULL;
1483 DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
1486 * Get the current state of the file.
1489 if(fsp->is_directory || fsp->fd == -1) {
1490 if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0)
1493 if(vfs_fstat(fsp,fsp->fd,&sbuf) != 0)
1498 * Unpack the user/group/world id's.
1501 if (!unpack_nt_owners( &sbuf, &user, &grp, security_info_sent, psd))
1505 * Do we need to chown ?
1508 if((user != (uid_t)-1 || grp != (uid_t)-1) && (sbuf.st_uid != user || sbuf.st_gid != grp)) {
1510 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
1511 fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
1513 if(vfs_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
1514 DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
1515 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
1520 * Recheck the current state of the file, which may have changed.
1521 * (suid/sgid bits, for instance)
1524 if(fsp->is_directory) {
1525 if(vfs_stat(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
1533 ret = vfs_stat(fsp->conn, fsp->fsp_name, &sbuf);
1535 ret = vfs_fstat(fsp,fsp->fd,&sbuf);
1542 create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
1544 acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
1545 &file_ace_list, &dir_ace_list, security_info_sent, psd);
1546 posix_perms = unpack_posix_permissions( fsp, &sbuf, &perms, security_info_sent, psd, acl_perms);
1548 if (!posix_perms && !acl_perms) {
1550 * Neither method of setting permissions can work. Fail here.
1553 DEBUG(3,("set_nt_acl: cannot set normal POSIX permissions or POSIX ACL permissions\n"));
1554 free_canon_ace_list(file_ace_list);
1555 free_canon_ace_list(dir_ace_list);
1560 * Only change security if we got a DACL.
1563 if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
1565 BOOL acl_set_support = False;
1569 * Try using the POSIX ACL set first. All back to chmod if
1570 * we have no ACL support on this filesystem.
1573 if (acl_perms && file_ace_list) {
1574 ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support);
1575 if (acl_set_support && ret == False) {
1576 DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
1577 free_canon_ace_list(file_ace_list);
1578 free_canon_ace_list(dir_ace_list);
1583 if (acl_perms && acl_set_support && fsp->is_directory && dir_ace_list) {
1584 if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) {
1585 DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
1586 free_canon_ace_list(file_ace_list);
1587 free_canon_ace_list(dir_ace_list);
1593 * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
1596 if(!acl_set_support && posix_perms && (sbuf.st_mode != perms)) {
1598 free_canon_ace_list(file_ace_list);
1599 free_canon_ace_list(dir_ace_list);
1600 file_ace_list = NULL;
1601 dir_ace_list = NULL;
1603 DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
1604 fsp->fsp_name, (unsigned int)perms ));
1606 if(conn->vfs_ops.chmod(conn,dos_to_unix(fsp->fsp_name, False), perms) == -1) {
1607 DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
1608 fsp->fsp_name, (unsigned int)perms, strerror(errno) ));
1614 free_canon_ace_list(file_ace_list);
1615 free_canon_ace_list(dir_ace_list);
1620 /****************************************************************************
1621 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
1622 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
1623 ****************************************************************************/
1625 static int chmod_acl_internals( SMB_ACL_T posix_acl, mode_t mode)
1627 int entry_id = SMB_ACL_FIRST_ENTRY;
1628 SMB_ACL_ENTRY_T entry;
1629 int num_entries = 0;
1631 while ( sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
1632 SMB_ACL_TAG_T tagtype;
1633 SMB_ACL_PERMSET_T permset;
1637 if (entry_id == SMB_ACL_FIRST_ENTRY)
1638 entry_id = SMB_ACL_NEXT_ENTRY;
1640 if (sys_acl_get_tag_type(entry, &tagtype) == -1)
1643 if (sys_acl_get_permset(entry, &permset) == -1)
1649 case SMB_ACL_USER_OBJ:
1650 perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
1652 case SMB_ACL_GROUP_OBJ:
1653 perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
1656 perms = S_IRUSR|S_IWUSR|S_IXUSR;
1659 perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
1665 if (map_acl_perms_to_permset(perms, &permset) == -1)
1668 if (sys_acl_set_permset(entry, permset) == -1)
1673 * If this is a simple 3 element ACL then it's a standard
1674 * UNIX permission set. Just use chmod...
1677 if (num_entries == 3)
1683 /****************************************************************************
1684 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
1685 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
1686 Note that name is in UNIX character set.
1687 ****************************************************************************/
1689 int chmod_acl(char *name, mode_t mode)
1691 SMB_ACL_T posix_acl = NULL;
1694 if ((posix_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS)) == NULL)
1697 if ((ret = chmod_acl_internals(posix_acl, mode)) == -1)
1700 ret = sys_acl_set_file(name, SMB_ACL_TYPE_ACCESS, posix_acl);
1704 sys_acl_free_acl(posix_acl);
1708 /****************************************************************************
1709 Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
1710 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
1711 ****************************************************************************/
1713 int fchmod_acl(int fd, mode_t mode)
1715 SMB_ACL_T posix_acl = NULL;
1718 if ((posix_acl = sys_acl_get_fd(fd)) == NULL)
1721 if ((ret = chmod_acl_internals(posix_acl, mode)) == -1)
1724 ret = sys_acl_set_fd(fd, posix_acl);
1728 sys_acl_free_acl(posix_acl);