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. */
136 nt_mask |= ((ace->perms & S_IRUSR) ? UNIX_ACCESS_R : 0 );
137 nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
138 nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_ACCESS_X : 0 );
141 DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
142 (unsigned int)ace->perms, (unsigned int)nt_mask ));
144 init_sec_access(&sa,nt_mask);
148 /****************************************************************************
149 Map NT perms to a UNIX mode_t.
150 ****************************************************************************/
152 #define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
153 #define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
154 #define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
156 static mode_t map_nt_perms( SEC_ACCESS sec_access, int type)
162 if(sec_access.mask & GENERIC_ALL_ACCESS)
163 mode = S_IRUSR|S_IWUSR|S_IXUSR;
165 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
166 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
167 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
171 if(sec_access.mask & GENERIC_ALL_ACCESS)
172 mode = S_IRGRP|S_IWGRP|S_IXGRP;
174 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
175 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
176 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
180 if(sec_access.mask & GENERIC_ALL_ACCESS)
181 mode = S_IROTH|S_IWOTH|S_IXOTH;
183 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
184 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
185 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
193 /****************************************************************************
194 Unpack a SEC_DESC into a UNIX owner and group.
195 ****************************************************************************/
197 static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
201 enum SID_NAME_USE sid_type;
206 if(security_info_sent == 0) {
207 DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
212 * Validate the owner and group SID's.
215 memset(&owner_sid, '\0', sizeof(owner_sid));
216 memset(&grp_sid, '\0', sizeof(grp_sid));
218 DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
221 * Don't immediately fail if the owner sid cannot be validated.
222 * This may be a group chown only set.
225 if (security_info_sent & OWNER_SECURITY_INFORMATION) {
226 sid_copy(&owner_sid, psd->owner_sid);
227 if (!sid_to_uid( &owner_sid, puser, &sid_type))
228 DEBUG(3,("unpack_nt_owners: unable to validate owner sid.\n"));
232 * Don't immediately fail if the group sid cannot be validated.
233 * This may be an owner chown only set.
236 if (security_info_sent & GROUP_SECURITY_INFORMATION) {
237 sid_copy(&grp_sid, psd->grp_sid);
238 if (!sid_to_gid( &grp_sid, pgrp, &sid_type))
239 DEBUG(3,("unpack_nt_owners: unable to validate group sid.\n"));
242 DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
247 #if !defined(HAVE_NO_ACLS)
248 /****************************************************************************
249 Merge aces with a common user.
250 ****************************************************************************/
252 static BOOL merge_aces( canon_ace *list_head, canon_ace *p_ace)
256 for (curr_ace = list_head; curr_ace; curr_ace = curr_ace->next) {
257 if (curr_ace == p_ace)
260 if (curr_ace->type == p_ace->type && sid_equal(&curr_ace->sid, &p_ace->sid)) {
261 if( DEBUGLVL( 10 )) {
262 dbgtext("Merging ACE's\n");
263 print_canon_ace( p_ace, 0);
264 print_canon_ace( curr_ace, 0);
266 p_ace->perms |= curr_ace->perms;
267 DLIST_REMOVE(list_head, curr_ace);
276 /****************************************************************************
277 Create a default mode for a directory default ACE.
278 ****************************************************************************/
280 static mode_t get_default_ace_mode(files_struct *fsp, int type)
282 mode_t force_mode = lp_force_dir_security_mode(SNUM(fsp->conn));
287 mode |= (force_mode & S_IRUSR) ? S_IRUSR : 0;
288 mode |= (force_mode & S_IWUSR) ? S_IWUSR : 0;
289 mode |= (force_mode & S_IXUSR) ? S_IXUSR : 0;
292 mode |= (force_mode & S_IRGRP) ? S_IRUSR : 0;
293 mode |= (force_mode & S_IWGRP) ? S_IWUSR : 0;
294 mode |= (force_mode & S_IXGRP) ? S_IXUSR : 0;
297 mode |= (force_mode & S_IROTH) ? S_IRUSR : 0;
298 mode |= (force_mode & S_IWOTH) ? S_IWUSR : 0;
299 mode |= (force_mode & S_IXOTH) ? S_IXUSR : 0;
306 /****************************************************************************
307 A well formed POSIX file or default ACL has at least 3 entries, a
308 SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
309 ****************************************************************************/
311 static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
313 DOM_SID *pfile_owner_sid,
314 DOM_SID *pfile_grp_sid,
315 SMB_STRUCT_STAT *pst,
318 extern DOM_SID global_sid_World;
320 BOOL got_user = False;
321 BOOL got_grp = False;
322 BOOL got_other = False;
324 for (pace = *pp_ace; pace; pace = pace->next) {
325 if (pace->type == SMB_ACL_USER_OBJ)
327 else if (pace->type == SMB_ACL_GROUP_OBJ)
329 else if (pace->type == SMB_ACL_OTHER)
334 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
335 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
340 pace->type = SMB_ACL_USER_OBJ;
341 pace->owner_type = UID_ACE;
342 pace->unix_ug.uid = pst->st_uid;
343 pace->sid = *pfile_owner_sid;
344 pace->perms = default_acl ? get_default_ace_mode(fsp, S_IRUSR): 0;
346 DLIST_ADD(*pp_ace, pace);
350 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
351 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
356 pace->type = SMB_ACL_GROUP_OBJ;
357 pace->owner_type = GID_ACE;
358 pace->unix_ug.uid = pst->st_gid;
359 pace->sid = *pfile_grp_sid;
360 pace->perms = default_acl ? get_default_ace_mode(fsp, S_IRGRP): 0;
362 DLIST_ADD(*pp_ace, pace);
366 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
367 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
372 pace->type = SMB_ACL_OTHER;
373 pace->owner_type = WORLD_ACE;
374 pace->unix_ug.world = -1;
375 pace->sid = global_sid_World;
376 pace->perms = default_acl ? get_default_ace_mode(fsp, S_IROTH): 0;
378 DLIST_ADD(*pp_ace, pace);
383 #endif /* HAVE_NO_ACLS */
385 /****************************************************************************
386 Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
388 ****************************************************************************/
390 static BOOL unpack_canon_ace(files_struct *fsp,
391 SMB_STRUCT_STAT *pst,
392 DOM_SID *pfile_owner_sid,
393 DOM_SID *pfile_grp_sid,
394 canon_ace **ppfile_ace, canon_ace **ppdir_ace,
395 uint32 security_info_sent, SEC_DESC *psd)
397 #if !defined(HAVE_NO_ACLS)
398 extern DOM_SID global_sid_World;
399 BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
400 canon_ace *file_ace = NULL;
401 canon_ace *dir_ace = NULL;
402 canon_ace *current_ace = NULL;
403 enum SID_NAME_USE sid_type;
405 #endif /* HAVE_NO_ACLS */
406 SEC_ACL *dacl = psd->dacl;
411 if(security_info_sent == 0) {
412 DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
417 * If no DACL then this is a chown only security descriptor.
420 if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !dacl)
423 #if defined(HAVE_NO_ACLS)
425 /* No point in doing this if we have no ACL support. */
428 #else /* HAVE_NO_ACLS */
431 * Now go through the DACL and create the canon_ace lists.
434 for(i = 0; i < dacl->num_aces; i++) {
435 SEC_ACE *psa = &dacl->ace[i];
437 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
438 DEBUG(3,("unpack_canon_ace: unable to set anything but an ALLOW or DENY ACE.\n"));
443 * The security mask may be UNIX_ACCESS_NONE which should map into
444 * no permissions (we overload the WRITE_OWNER bit for this) or it
445 * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
446 * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
449 psa->info.mask &= (GENERIC_ALL_ACCESS|GENERIC_EXECUTE_ACCESS|GENERIC_WRITE_ACCESS|
450 GENERIC_READ_ACCESS|UNIX_ACCESS_NONE|FILE_ALL_ATTRIBUTES);
452 if(psa->info.mask != UNIX_ACCESS_NONE)
453 psa->info.mask &= ~UNIX_ACCESS_NONE;
456 * Create a cannon_ace entry representing this NT DACL ACE.
459 if ((current_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
460 free_canon_ace_list(file_ace);
461 free_canon_ace_list(dir_ace);
462 DEBUG(0,("unpack_canon_ace: malloc fail.\n"));
466 ZERO_STRUCTP(current_ace);
468 sid_copy(¤t_ace->sid, &psa->sid);
471 * Try and work out if the SID is a user or group
472 * as we need to flag these differently for POSIX.
475 if( sid_equal(¤t_ace->sid, &global_sid_World)) {
476 current_ace->owner_type = WORLD_ACE;
477 current_ace->unix_ug.world = -1;
478 } else if (sid_to_uid( ¤t_ace->sid, ¤t_ace->unix_ug.uid, &sid_type)) {
479 current_ace->owner_type = UID_ACE;
480 } else if (sid_to_gid( ¤t_ace->sid, ¤t_ace->unix_ug.gid, &sid_type)) {
481 current_ace->owner_type = GID_ACE;
485 free_canon_ace_list(file_ace);
486 free_canon_ace_list(dir_ace);
488 DEBUG(0,("unpack_canon_ace: unable to map SID %s to uid or gid.\n",
489 sid_to_string(str, ¤t_ace->sid) ));
494 * Map the given NT permissions into a UNIX mode_t containing only
495 * S_I(R|W|X)USR bits.
498 if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
499 current_ace->perms |= map_nt_perms( psa->info, S_IRUSR);
501 current_ace->perms = 0;
504 * Now note what kind of a POSIX ACL this should map to.
507 if(sid_equal(¤t_ace->sid, pfile_owner_sid)) {
508 /* Note we should apply the default mode/mask here.... FIXME ! JRA */
509 current_ace->type = SMB_ACL_USER_OBJ;
510 } else if( sid_equal(¤t_ace->sid, pfile_grp_sid)) {
511 /* Note we should apply the default mode/mask here.... FIXME ! JRA */
512 current_ace->type = SMB_ACL_GROUP_OBJ;
513 } else if( sid_equal(¤t_ace->sid, &global_sid_World)) {
514 /* Note we should apply the default mode/mask here.... FIXME ! JRA */
515 current_ace->type = SMB_ACL_OTHER;
518 * Could be a SMB_ACL_USER or SMB_ACL_GROUP. Check by
519 * looking at owner_type.
522 current_ace->type = (current_ace->owner_type == UID_ACE) ? SMB_ACL_USER : SMB_ACL_GROUP;
525 if (fsp->is_directory) {
528 * We can only add to the default POSIX ACE list if the ACE is
529 * designed to be inherited by both files and directories.
531 if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
532 (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
533 DLIST_ADD(dir_ace, current_ace);
536 * If this is not an inherit only ACE we need to add a duplicate
540 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
541 canon_ace *dup_ace = dup_canon_ace(current_ace);
544 DEBUG(0,("unpack_canon_ace: malloc fail !\n"));
545 free_canon_ace_list(file_ace);
546 free_canon_ace_list(dir_ace);
550 current_ace = dup_ace;
558 * Only add to the file ACL if not inherit only.
561 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
562 DLIST_ADD(file_ace, current_ace);
563 all_aces_are_inherit_only = False;
568 * Free if ACE was not addedd.
575 if (fsp->is_directory && all_aces_are_inherit_only) {
577 * Windows 2000 is doing one of these weird 'inherit acl'
578 * traverses to conserve NTFS ACL resources. Just pretend
579 * there was no DACL sent. JRA.
582 DEBUG(10,("unpack_canon_ace: Win2k inherit acl traverse. Ignoring DACL.\n"));
586 * Now go through the canon_ace lists and merge entries
587 * belonging to identical users.
592 for (current_ace = file_ace; current_ace; current_ace = current_ace->next ) {
593 if (merge_aces( file_ace, current_ace))
599 for (current_ace = dir_ace; current_ace; current_ace = current_ace->next ) {
600 if (merge_aces( dir_ace, current_ace))
605 * A well formed POSIX file or default ACL has at least 3 entries, a
606 * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
607 * and optionally a mask entry. Ensure this is the case.
610 if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, False)) {
611 free_canon_ace_list(file_ace);
612 free_canon_ace_list(dir_ace);
616 if (!ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
617 free_canon_ace_list(file_ace);
618 free_canon_ace_list(dir_ace);
622 if( DEBUGLVL( 10 )) {
623 dbgtext("unpack_canon_ace: File ACL:\n");
624 for (i = 0, current_ace = file_ace; current_ace; current_ace = current_ace->next, i++ ) {
625 print_canon_ace( current_ace, i);
628 dbgtext("unpack_canon_ace: Directory ACL:\n");
629 for (i = 0, current_ace = dir_ace; current_ace; current_ace = current_ace->next, i++ ) {
630 print_canon_ace( current_ace, i);
634 *ppfile_ace = file_ace;
635 *ppdir_ace = dir_ace;
638 #endif /* HAVE_NO_ACLS */
641 /****************************************************************************
642 Unpack a SEC_DESC into a set of standard POSIX permissions.
643 ****************************************************************************/
645 static BOOL unpack_posix_permissions(files_struct *fsp, SMB_STRUCT_STAT *psbuf, mode_t *pmode,
646 uint32 security_info_sent, SEC_DESC *psd, BOOL posix_acls)
648 extern DOM_SID global_sid_World;
649 connection_struct *conn = fsp->conn;
650 DOM_SID file_owner_sid;
651 DOM_SID file_grp_sid;
652 SEC_ACL *dacl = psd->dacl;
653 BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
658 if(security_info_sent == 0) {
659 DEBUG(0,("unpack_posix_permissions: no security info sent !\n"));
664 * Windows 2000 sends the owner and group SIDs as the logged in
665 * user, not the connected user. But it still sends the file
666 * owner SIDs on an ACL set. So we need to check for the file
667 * owner and group SIDs as well as the owner SIDs. JRA.
670 create_file_sids(psbuf, &file_owner_sid, &file_grp_sid);
673 * If no DACL then this is a chown only security descriptor.
676 if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !dacl) {
682 * Now go through the DACL and ensure that
683 * any owner/group sids match.
686 for(i = 0; i < dacl->num_aces; i++) {
688 SEC_ACE *psa = &dacl->ace[i];
690 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) &&
691 (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
692 DEBUG(3,("unpack_posix_permissions: unable to set anything but an ALLOW or DENY ACE.\n"));
697 * Ignore or remove bits we don't care about on a directory ACE.
700 if(fsp->is_directory) {
701 if(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
702 DEBUG(3,("unpack_posix_permissions: ignoring inherit only ACE.\n"));
707 * At least one of the ACE entries wasn't inherit only.
708 * Flag this so we know the returned mode is valid.
711 all_aces_are_inherit_only = False;
715 * Windows 2000 sets these flags even on *file* ACE's. This is wrong
716 * but we can ignore them for now. Revisit this when we go to POSIX
717 * ACLs on directories.
720 psa->flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERITED_ACE);
722 if(psa->flags != 0) {
723 DEBUG(1,("unpack_posix_permissions: unable to set ACE flags (%x).\n",
724 (unsigned int)psa->flags));
729 * The security mask may be UNIX_ACCESS_NONE which should map into
730 * no permissions (we overload the WRITE_OWNER bit for this) or it
731 * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
732 * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
735 psa->info.mask &= (GENERIC_ALL_ACCESS|GENERIC_EXECUTE_ACCESS|GENERIC_WRITE_ACCESS|
736 GENERIC_READ_ACCESS|UNIX_ACCESS_NONE|FILE_ALL_ATTRIBUTES);
738 if(psa->info.mask != UNIX_ACCESS_NONE)
739 psa->info.mask &= ~UNIX_ACCESS_NONE;
741 sid_copy(&ace_sid, &psa->sid);
743 if(sid_equal(&ace_sid, &file_owner_sid)) {
745 * Map the desired permissions into owner perms.
748 if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
749 *pmode |= map_nt_perms( psa->info, S_IRUSR);
751 *pmode &= ~(map_nt_perms( psa->info, S_IRUSR));
754 } else if( sid_equal(&ace_sid, &file_grp_sid)) {
756 * Map the desired permissions into group perms.
759 if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
760 *pmode |= map_nt_perms( psa->info, S_IRGRP);
762 *pmode &= ~(map_nt_perms( psa->info, S_IRGRP));
764 } else if( sid_equal(&ace_sid, &global_sid_World)) {
766 * Map the desired permissions into other perms.
769 if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
770 *pmode |= map_nt_perms( psa->info, S_IROTH);
772 *pmode &= ~(map_nt_perms( psa->info, S_IROTH));
776 * Only bother printing the level zero error if we didn't get any
780 DEBUG(0,("unpack_posix_permissions: unknown SID used in ACL.\n"));
785 if (fsp->is_directory && all_aces_are_inherit_only) {
787 * Windows 2000 is doing one of these weird 'inherit acl'
788 * traverses to conserve NTFS ACL resources. Just pretend
789 * there was no DACL sent. JRA.
792 DEBUG(10,("unpack_posix_permissions: Win2k inherit acl traverse. Ignoring DACL.\n"));
796 * Check to see if we need to change anything.
797 * Enforce limits on modified bits *only*. Don't enforce masks
798 * on bits not changed by the user.
801 if(fsp->is_directory) {
803 *pmode &= (lp_dir_security_mask(SNUM(conn)) | psbuf->st_mode);
804 *pmode |= (lp_force_dir_security_mode(SNUM(conn)) & ( *pmode ^ psbuf->st_mode ));
808 *pmode &= (lp_security_mask(SNUM(conn)) | psbuf->st_mode);
809 *pmode |= (lp_force_security_mode(SNUM(conn)) & ( *pmode ^ psbuf->st_mode ));
814 * Preserve special bits.
817 *pmode |= (psbuf->st_mode & ~0777);
822 /****************************************************************************
823 Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
824 ****************************************************************************/
826 static mode_t convert_permset_to_mode_t(SMB_ACL_PERMSET_T permset)
830 ret |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? S_IRUSR : 0);
831 ret |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
832 ret |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
837 /****************************************************************************
838 Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
839 ****************************************************************************/
841 static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
855 /****************************************************************************
856 Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to
857 an SMB_ACL_PERMSET_T.
858 ****************************************************************************/
860 static int map_acl_perms_to_permset(mode_t mode, SMB_ACL_PERMSET_T *p_permset)
862 if (sys_acl_clear_perms(*p_permset) == -1)
864 if (mode & S_IRUSR) {
865 if (sys_acl_add_perm(*p_permset, SMB_ACL_READ) == -1)
868 if (mode & S_IWUSR) {
869 if (sys_acl_add_perm(*p_permset, SMB_ACL_WRITE) == -1)
872 if (mode & S_IXUSR) {
873 if (sys_acl_add_perm(*p_permset, SMB_ACL_EXECUTE) == -1)
879 /****************************************************************************
880 Count a linked list of canonical ACE entries.
881 ****************************************************************************/
883 static size_t count_canon_ace_list( canon_ace *list_head )
888 for (ace = list_head; ace; ace = ace->next)
894 /****************************************************************************
895 Free a linked list of canonical ACE entries.
896 ****************************************************************************/
898 static void free_canon_ace_list( canon_ace *list_head )
901 canon_ace *old_head = list_head;
902 DLIST_REMOVE(list_head, list_head);
907 /******************************************************************************
908 Fall back to the generic 3 element UNIX permissions.
909 ********************************************************************************/
911 static canon_ace *unix_canonicalise_acl(files_struct *fsp, SMB_STRUCT_STAT *psbuf,
912 DOM_SID *powner, DOM_SID *pgroup)
914 extern DOM_SID global_sid_World;
915 canon_ace *list_head = NULL;
916 canon_ace *owner_ace = NULL;
917 canon_ace *group_ace = NULL;
918 canon_ace *other_ace = NULL;
921 * Create 3 linked list entries.
924 if ((owner_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
927 if ((group_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
930 if ((other_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
933 ZERO_STRUCTP(owner_ace);
934 ZERO_STRUCTP(group_ace);
935 ZERO_STRUCTP(other_ace);
937 owner_ace->type = SMB_ACL_USER_OBJ;
938 owner_ace->sid = *powner;
939 owner_ace->unix_ug.uid = psbuf->st_uid;
940 owner_ace->owner_type = UID_ACE;
942 group_ace->type = SMB_ACL_GROUP_OBJ;
943 group_ace->sid = *pgroup;
944 owner_ace->unix_ug.gid = psbuf->st_gid;
945 owner_ace->owner_type = GID_ACE;
947 other_ace->type = SMB_ACL_OTHER;
948 other_ace->sid = global_sid_World;
949 owner_ace->unix_ug.world = -1;
950 owner_ace->owner_type = WORLD_ACE;
952 if (!fsp->is_directory) {
953 owner_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
954 group_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
955 other_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
957 mode_t mode = unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name);
959 owner_ace->perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
960 group_ace->perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
961 other_ace->perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
964 DLIST_ADD(list_head, other_ace);
965 DLIST_ADD(list_head, group_ace);
966 DLIST_ADD(list_head, owner_ace);
972 safe_free(owner_ace);
973 safe_free(group_ace);
974 safe_free(other_ace);
979 /****************************************************************************
980 Create a linked list of canonical ACE entries. This is sorted so that DENY
981 entries are at the front of the list, as NT requires.
982 ****************************************************************************/
984 static canon_ace *canonicalise_acl( SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf)
986 extern DOM_SID global_sid_World;
987 mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
988 canon_ace *list_head = NULL;
989 canon_ace *ace = NULL;
990 canon_ace *next_ace = NULL;
991 int entry_id = SMB_ACL_FIRST_ENTRY;
992 SMB_ACL_ENTRY_T entry;
994 while ( sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
995 SMB_ACL_TAG_T tagtype;
996 SMB_ACL_PERMSET_T permset;
999 enum ace_owner owner_type;
1002 if (entry_id == SMB_ACL_FIRST_ENTRY)
1003 entry_id = SMB_ACL_NEXT_ENTRY;
1005 /* Is this a MASK entry ? */
1006 if (sys_acl_get_tag_type(entry, &tagtype) == -1)
1009 if (sys_acl_get_permset(entry, &permset) == -1)
1012 /* Decide which SID to use based on the ACL type. */
1014 case SMB_ACL_USER_OBJ:
1015 /* Get the SID from the owner. */
1016 uid_to_sid( &sid, psbuf->st_uid );
1017 unix_ug.uid = psbuf->st_uid;
1018 owner_type = UID_ACE;
1022 uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
1024 DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
1027 uid_to_sid( &sid, *puid);
1028 unix_ug.uid = *puid;
1029 owner_type = UID_ACE;
1032 case SMB_ACL_GROUP_OBJ:
1033 /* Get the SID from the owning group. */
1034 gid_to_sid( &sid, psbuf->st_gid );
1035 unix_ug.gid = psbuf->st_gid;
1036 owner_type = GID_ACE;
1040 gid_t *pgid = (gid_t *)sys_acl_get_qualifier(entry);
1042 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
1045 gid_to_sid( &sid, *pgid);
1046 unix_ug.gid = *pgid;
1047 owner_type = GID_ACE;
1051 acl_mask = convert_permset_to_mode_t(permset);
1052 continue; /* Don't count the mask as an entry. */
1054 /* Use the Everyone SID */
1055 sid = global_sid_World;
1057 owner_type = WORLD_ACE;
1060 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
1065 * Add this entry to the list.
1068 if ((ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
1072 ace->type = tagtype;
1073 ace->perms = convert_permset_to_mode_t(permset);
1075 ace->unix_ug = unix_ug;
1076 ace->owner_type = owner_type;
1078 DLIST_ADD(list_head, ace);
1082 * Now go through the list, masking the permissions with the
1083 * acl_mask. If the permissions are 0 it should be listed
1087 for ( ace = list_head; ace; ace = next_ace) {
1088 next_ace = ace->next;
1090 /* Masks are only applied to entries other than USER_OBJ and OTHER. */
1091 if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
1092 ace->perms &= acl_mask;
1094 if (ace->perms == 0)
1095 DLIST_PROMOTE(list_head, ace);
1098 if( DEBUGLVL( 10 ) ) {
1099 char *acl_text = sys_acl_to_text( posix_acl, NULL);
1101 dbgtext("canonicalize_acl: processed acl %s\n", acl_text == NULL ? "NULL" : acl_text );
1103 sys_acl_free_text(acl_text);
1110 free_canon_ace_list(list_head);
1114 /****************************************************************************
1115 Attempt to apply an ACL to a file or directory.
1116 ****************************************************************************/
1118 static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, BOOL *pacl_set_support)
1121 SMB_ACL_T the_acl = sys_acl_init((int)count_canon_ace_list(the_ace) + 1);
1124 SMB_ACL_ENTRY_T mask_entry;
1125 SMB_ACL_PERMSET_T mask_permset;
1126 SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
1128 if (the_acl == NULL) {
1129 #if !defined(HAVE_NO_ACLS)
1131 * Only print this error message if we have some kind of ACL
1132 * support that's not working. Otherwise we would always get this.
1134 DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
1135 default_ace ? "default" : "file", strerror(errno) ));
1137 *pacl_set_support = False;
1141 for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
1142 SMB_ACL_ENTRY_T the_entry;
1143 SMB_ACL_PERMSET_T the_permset;
1146 * Get the entry for this ACE.
1149 if (sys_acl_create_entry( &the_acl, &the_entry) == -1) {
1150 DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
1151 i, strerror(errno) ));
1156 * Ok - we now know the ACL calls should be working, don't
1157 * allow fallback to chmod.
1160 *pacl_set_support = True;
1163 * Initialise the entry from the canon_ace.
1167 * First tell the entry what type of ACE this is.
1170 if (sys_acl_set_tag_type(the_entry, p_ace->type) == -1) {
1171 DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
1172 i, strerror(errno) ));
1177 * Only set the qualifier (user or group id) if the entry is a user
1181 if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
1182 if (sys_acl_set_qualifier(the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
1183 DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
1184 i, strerror(errno) ));
1190 * Convert the mode_t perms in the canon_ace to a POSIX permset.
1193 if (sys_acl_get_permset(the_entry, &the_permset) == -1) {
1194 DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
1195 i, strerror(errno) ));
1199 if (map_acl_perms_to_permset(p_ace->perms, &the_permset) == -1) {
1200 DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
1201 p_ace->perms, i, strerror(errno) ));
1206 * ..and apply them to the entry.
1209 if (sys_acl_set_permset(the_entry, the_permset) == -1) {
1210 DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
1211 i, strerror(errno) ));
1216 print_canon_ace( p_ace, i);
1220 * Add in a mask of rwx.
1223 if (sys_acl_create_entry( &the_acl, &mask_entry) == -1) {
1224 DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
1228 if (sys_acl_set_tag_type(mask_entry, SMB_ACL_MASK) == -1) {
1229 DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
1233 if (sys_acl_get_permset(mask_entry, &mask_permset) == -1) {
1234 DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
1238 if (map_acl_perms_to_permset(S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
1239 DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
1243 if (sys_acl_set_permset(mask_entry, mask_permset) == -1) {
1244 DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
1249 * Check if the ACL is valid.
1252 if (sys_acl_valid(the_acl) == -1) {
1253 DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n",
1254 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
1260 * Finally apply it to the file or directory.
1263 if(default_ace || fsp->is_directory || fsp->fd == -1) {
1264 if (sys_acl_set_file(dos_to_unix(fsp->fsp_name,False), the_acl_type, the_acl) == -1) {
1265 DEBUG(0,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
1266 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
1267 fsp->fsp_name, strerror(errno) ));
1271 if (sys_acl_set_fd(fsp->fd, the_acl) == -1) {
1272 DEBUG(0,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
1273 fsp->fsp_name, strerror(errno) ));
1282 if (the_acl != NULL)
1283 sys_acl_free_acl(the_acl);
1288 /****************************************************************************
1289 Reply to query a security descriptor from an fsp. If it succeeds it allocates
1290 the space for the return elements and returns the size needed to return the
1291 security descriptor. This should be the only external function needed for
1292 the UNIX style get ACL.
1293 ****************************************************************************/
1295 size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
1297 SMB_STRUCT_STAT sbuf;
1298 SEC_ACE *nt_ace_list;
1302 SEC_ACL *psa = NULL;
1303 size_t num_acls = 0;
1304 size_t num_dir_acls = 0;
1305 size_t num_aces = 0;
1306 SMB_ACL_T posix_acl = NULL;
1307 SMB_ACL_T dir_acl = NULL;
1308 canon_ace *file_ace = NULL;
1309 canon_ace *dir_ace = NULL;
1313 DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name ));
1315 if(fsp->is_directory || fsp->fd == -1) {
1317 /* Get the stat struct for the owner info. */
1318 if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
1322 * Get the ACL from the path.
1325 posix_acl = sys_acl_get_file( dos_to_unix(fsp->fsp_name, False), SMB_ACL_TYPE_ACCESS);
1328 * If it's a directory get the default POSIX ACL.
1331 if(fsp->is_directory)
1332 dir_acl = sys_acl_get_file( dos_to_unix(fsp->fsp_name, False), SMB_ACL_TYPE_DEFAULT);
1336 /* Get the stat struct for the owner info. */
1337 if(vfs_fstat(fsp,fsp->fd,&sbuf) != 0) {
1341 * Get the ACL from the fd.
1343 posix_acl = sys_acl_get_fd(fsp->fd);
1346 DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
1347 posix_acl ? "present" : "absent",
1348 dir_acl ? "present" : "absent" ));
1351 * Get the owner, group and world SIDs.
1354 create_file_sids(&sbuf, &owner_sid, &group_sid);
1356 /* Create the canon_ace lists. */
1358 file_ace = canonicalise_acl( posix_acl, &sbuf);
1360 file_ace = unix_canonicalise_acl(fsp, &sbuf, &owner_sid, &group_sid);
1362 num_acls = count_canon_ace_list(file_ace);
1364 if (fsp->is_directory) {
1366 dir_ace = canonicalise_acl( dir_acl, &sbuf);
1368 dir_ace = unix_canonicalise_acl(fsp, &sbuf, &owner_sid, &group_sid);
1370 num_dir_acls = count_canon_ace_list(dir_ace);
1373 /* Allocate the ace list. */
1374 if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_dir_acls)* sizeof(SEC_ACE))) == NULL) {
1375 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
1379 memset(nt_ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) );
1382 * Create the NT ACE list from the canonical ace lists.
1392 for (i = 0; i < num_acls; i++, ace = ace->next) {
1393 SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
1394 init_sec_ace(&nt_ace_list[num_aces++], &ace->sid, nt_acl_type, acc, 0);
1399 for (i = 0; i < num_dir_acls; i++, ace = ace->next) {
1400 SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
1401 init_sec_ace(&nt_ace_list[num_aces++], &ace->sid, nt_acl_type, acc,
1402 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY);
1407 if((psa = make_sec_acl( main_loop_talloc_get(), ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
1408 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
1413 *ppdesc = make_standard_sec_desc( main_loop_talloc_get(), &owner_sid, &group_sid, psa, &sd_size);
1416 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
1423 sys_acl_free_acl(posix_acl);
1425 sys_acl_free_acl(dir_acl);
1426 free_canon_ace_list(file_ace);
1427 free_canon_ace_list(dir_ace);
1434 /****************************************************************************
1435 Reply to set a security descriptor on an fsp. security_info_sent is the
1436 description of the following NT ACL.
1437 This should be the only external function needed for the UNIX style set ACL.
1438 ****************************************************************************/
1440 BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
1442 connection_struct *conn = fsp->conn;
1443 uid_t user = (uid_t)-1;
1444 gid_t grp = (gid_t)-1;
1446 SMB_STRUCT_STAT sbuf;
1447 DOM_SID file_owner_sid;
1448 DOM_SID file_grp_sid;
1449 canon_ace *file_ace_list = NULL;
1450 canon_ace *dir_ace_list = NULL;
1454 DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
1457 * Get the current state of the file.
1460 if(fsp->is_directory || fsp->fd == -1) {
1461 if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0)
1464 if(vfs_fstat(fsp,fsp->fd,&sbuf) != 0)
1469 * Unpack the user/group/world id's.
1472 if (!unpack_nt_owners( &sbuf, &user, &grp, security_info_sent, psd))
1476 * Do we need to chown ?
1479 if((user != (uid_t)-1 || grp != (uid_t)-1) && (sbuf.st_uid != user || sbuf.st_gid != grp)) {
1481 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
1482 fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
1484 if(vfs_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
1485 DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
1486 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
1491 * Recheck the current state of the file, which may have changed.
1492 * (suid/sgid bits, for instance)
1495 if(fsp->is_directory) {
1496 if(vfs_stat(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
1504 ret = vfs_stat(fsp->conn, fsp->fsp_name, &sbuf);
1506 ret = vfs_fstat(fsp,fsp->fd,&sbuf);
1513 create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
1515 acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
1516 &file_ace_list, &dir_ace_list, security_info_sent, psd);
1517 posix_perms = unpack_posix_permissions( fsp, &sbuf, &perms, security_info_sent, psd, acl_perms);
1519 if (!posix_perms && !acl_perms) {
1521 * Neither method of setting permissions can work. Fail here.
1524 DEBUG(3,("set_nt_acl: cannot set normal POSIX permissions or POSIX ACL permissions\n"));
1525 free_canon_ace_list(file_ace_list);
1526 free_canon_ace_list(dir_ace_list);
1531 * Only change security if we got a DACL.
1534 if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
1536 BOOL acl_set_support = False;
1540 * Try using the POSIX ACL set first. All back to chmod if
1541 * we have no ACL support on this filesystem.
1544 if (acl_perms && file_ace_list) {
1545 ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support);
1546 if (acl_set_support && ret == False) {
1547 DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
1548 free_canon_ace_list(file_ace_list);
1549 free_canon_ace_list(dir_ace_list);
1554 if (acl_perms && acl_set_support && fsp->is_directory && dir_ace_list) {
1555 if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) {
1556 DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
1557 free_canon_ace_list(file_ace_list);
1558 free_canon_ace_list(dir_ace_list);
1564 * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
1567 if(!acl_set_support && posix_perms && (sbuf.st_mode != perms)) {
1569 free_canon_ace_list(file_ace_list);
1570 free_canon_ace_list(dir_ace_list);
1571 file_ace_list = NULL;
1572 dir_ace_list = NULL;
1574 DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
1575 fsp->fsp_name, (unsigned int)perms ));
1577 if(conn->vfs_ops.chmod(conn,dos_to_unix(fsp->fsp_name, False), perms) == -1) {
1578 DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
1579 fsp->fsp_name, (unsigned int)perms, strerror(errno) ));
1585 free_canon_ace_list(file_ace_list);
1586 free_canon_ace_list(dir_ace_list);
1591 /****************************************************************************
1592 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
1593 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
1594 ****************************************************************************/
1596 static int chmod_acl_internals( SMB_ACL_T posix_acl, mode_t mode)
1598 int entry_id = SMB_ACL_FIRST_ENTRY;
1599 SMB_ACL_ENTRY_T entry;
1600 int num_entries = 0;
1602 while ( sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
1603 SMB_ACL_TAG_T tagtype;
1604 SMB_ACL_PERMSET_T permset;
1608 if (entry_id == SMB_ACL_FIRST_ENTRY)
1609 entry_id = SMB_ACL_NEXT_ENTRY;
1611 if (sys_acl_get_tag_type(entry, &tagtype) == -1)
1614 if (sys_acl_get_permset(entry, &permset) == -1)
1620 case SMB_ACL_USER_OBJ:
1621 perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
1623 case SMB_ACL_GROUP_OBJ:
1624 perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
1627 perms = S_IRUSR|S_IWUSR|S_IXUSR;
1630 perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
1636 if (map_acl_perms_to_permset(perms, &permset) == -1)
1639 if (sys_acl_set_permset(entry, permset) == -1)
1644 * If this is a simple 3 element ACL then it's a standard
1645 * UNIX permission set. Just use chmod...
1648 if (num_entries == 3)
1654 /****************************************************************************
1655 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
1656 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
1657 Note that name is in UNIX character set.
1658 ****************************************************************************/
1660 int chmod_acl(char *name, mode_t mode)
1662 SMB_ACL_T posix_acl = NULL;
1665 if ((posix_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS)) == NULL)
1668 if ((ret = chmod_acl_internals(posix_acl, mode)) == -1)
1671 ret = sys_acl_set_file(name, SMB_ACL_TYPE_ACCESS, posix_acl);
1675 sys_acl_free_acl(posix_acl);
1679 /****************************************************************************
1680 Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
1681 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
1682 ****************************************************************************/
1684 int fchmod_acl(int fd, mode_t mode)
1686 SMB_ACL_T posix_acl = NULL;
1689 if ((posix_acl = sys_acl_get_fd(fd)) == NULL)
1692 if ((ret = chmod_acl_internals(posix_acl, mode)) == -1)
1695 ret = sys_acl_set_fd(fd, posix_acl);
1699 sys_acl_free_acl(posix_acl);