2 Unix SMB/CIFS implementation.
3 SMB NT Security Descriptor / Unix permission conversion.
4 Copyright (C) Jeremy Allison 1994-2000.
5 Copyright (C) Andreas Gruenbacher 2002.
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 /****************************************************************************
25 Data structures representing the internal ACE format.
26 ****************************************************************************/
28 enum ace_owner {UID_ACE, GID_ACE, WORLD_ACE};
29 enum ace_attribute {ALLOW_ACE, DENY_ACE}; /* Used for incoming NT ACLS. */
31 typedef union posix_id {
37 typedef struct canon_ace {
38 struct canon_ace *next, *prev;
40 mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */
42 enum ace_owner owner_type;
43 enum ace_attribute attr;
48 #define ALL_ACE_PERMS (S_IRUSR|S_IWUSR|S_IXUSR)
51 * EA format of user.SAMBA_PAI (Samba_Posix_Acl_Interitance)
54 * | 1 | 1 | 2 | 2 | ....
55 * +------+------+-------------+---------------------+-------------+--------------------+
56 * | vers | flag | num_entries | num_default_entries | ..entries.. | default_entries... |
57 * +------+------+-------------+---------------------+-------------+--------------------+
60 #define SAMBA_POSIX_INHERITANCE_EA_NAME "user.SAMBA_PAI"
62 #define PAI_VERSION_OFFSET 0
63 #define PAI_FLAG_OFFSET 1
64 #define PAI_NUM_ENTRIES_OFFSET 2
65 #define PAI_NUM_DEFAULT_ENTRIES_OFFSET 4
66 #define PAI_ENTRIES_BASE 6
69 #define PAI_ACL_FLAG_PROTECTED 0x1
70 #define PAI_ENTRY_LENGTH 5
73 * In memory format of user.SAMBA_PAI attribute.
77 struct pai_entry *next, *prev;
78 enum ace_owner owner_type;
84 unsigned int num_entries;
85 struct pai_entry *entry_list;
86 unsigned int num_def_entries;
87 struct pai_entry *def_entry_list;
90 /************************************************************************
91 Return a uint32 of the pai_entry principal.
92 ************************************************************************/
94 static uint32 get_pai_entry_val(struct pai_entry *paie)
96 switch (paie->owner_type) {
98 DEBUG(10,("get_pai_entry_val: uid = %u\n", (unsigned int)paie->unix_ug.uid ));
99 return (uint32)paie->unix_ug.uid;
101 DEBUG(10,("get_pai_entry_val: gid = %u\n", (unsigned int)paie->unix_ug.gid ));
102 return (uint32)paie->unix_ug.gid;
105 DEBUG(10,("get_pai_entry_val: world ace\n"));
110 /************************************************************************
111 Return a uint32 of the entry principal.
112 ************************************************************************/
114 static uint32 get_entry_val(canon_ace *ace_entry)
116 switch (ace_entry->owner_type) {
118 DEBUG(10,("get_entry_val: uid = %u\n", (unsigned int)ace_entry->unix_ug.uid ));
119 return (uint32)ace_entry->unix_ug.uid;
121 DEBUG(10,("get_entry_val: gid = %u\n", (unsigned int)ace_entry->unix_ug.gid ));
122 return (uint32)ace_entry->unix_ug.gid;
125 DEBUG(10,("get_entry_val: world ace\n"));
130 /************************************************************************
131 Count the inherited entries.
132 ************************************************************************/
134 static unsigned int num_inherited_entries(canon_ace *ace_list)
136 unsigned int num_entries = 0;
138 for (; ace_list; ace_list = ace_list->next)
139 if (ace_list->inherited)
144 /************************************************************************
145 Create the on-disk format. Caller must free.
146 ************************************************************************/
148 static char *create_pai_buf(canon_ace *file_ace_list, canon_ace *dir_ace_list, BOOL protected, size_t *store_size)
150 char *pai_buf = NULL;
151 canon_ace *ace_list = NULL;
152 char *entry_offset = NULL;
153 unsigned int num_entries = 0;
154 unsigned int num_def_entries = 0;
156 for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next)
157 if (ace_list->inherited)
160 for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next)
161 if (ace_list->inherited)
164 *store_size = PAI_ENTRIES_BASE + ((num_entries + num_def_entries)*PAI_ENTRY_LENGTH);
166 pai_buf = malloc(*store_size);
171 /* Set up the header. */
172 memset(pai_buf, '\0', PAI_ENTRIES_BASE);
173 SCVAL(pai_buf,PAI_VERSION_OFFSET,PAI_VERSION);
174 SCVAL(pai_buf,PAI_FLAG_OFFSET,(protected ? PAI_ACL_FLAG_PROTECTED : 0));
175 SSVAL(pai_buf,PAI_NUM_ENTRIES_OFFSET,num_entries);
176 SSVAL(pai_buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET,num_def_entries);
178 entry_offset = pai_buf + PAI_ENTRIES_BASE;
180 for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next) {
181 if (ace_list->inherited) {
182 uint8 type_val = (unsigned char)ace_list->owner_type;
183 uint32 entry_val = get_entry_val(ace_list);
185 SCVAL(entry_offset,0,type_val);
186 SIVAL(entry_offset,1,entry_val);
187 entry_offset += PAI_ENTRY_LENGTH;
191 for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) {
192 if (ace_list->inherited) {
193 uint8 type_val = (unsigned char)ace_list->owner_type;
194 uint32 entry_val = get_entry_val(ace_list);
196 SCVAL(entry_offset,0,type_val);
197 SIVAL(entry_offset,1,entry_val);
198 entry_offset += PAI_ENTRY_LENGTH;
205 /************************************************************************
206 Store the user.SAMBA_PAI attribute on disk.
207 ************************************************************************/
209 static void store_inheritance_attributes(files_struct *fsp, canon_ace *file_ace_list,
210 canon_ace *dir_ace_list, BOOL protected)
216 if (!lp_map_acl_inherit(SNUM(fsp->conn)))
220 * Don't store if this ACL isn't protected and
221 * none of the entries in it are marked as inherited.
224 if (!protected && num_inherited_entries(file_ace_list) == 0 && num_inherited_entries(dir_ace_list) == 0) {
225 /* Instead just remove the attribute if it exists. */
227 SMB_VFS_FREMOVEXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME);
229 SMB_VFS_REMOVEXATTR(fsp->conn, fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME);
233 pai_buf = create_pai_buf(file_ace_list, dir_ace_list, protected, &store_size);
236 ret = SMB_VFS_FSETXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME,
237 pai_buf, store_size, 0);
239 ret = SMB_VFS_SETXATTR(fsp->conn,fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME,
240 pai_buf, store_size, 0);
244 DEBUG(10,("store_inheritance_attribute:%s for file %s\n", protected ? " (protected)" : "", fsp->fsp_name));
245 if (ret == -1 && errno != ENOSYS)
246 DEBUG(1,("store_inheritance_attribute: Error %s\n", strerror(errno) ));
249 /************************************************************************
250 Delete the in memory inheritance info.
251 ************************************************************************/
253 static void free_inherited_info(struct pai_val *pal)
256 struct pai_entry *paie, *paie_next;
257 for (paie = pal->entry_list; paie; paie = paie_next) {
258 paie_next = paie->next;
261 for (paie = pal->def_entry_list; paie; paie = paie_next) {
262 paie_next = paie->next;
269 /************************************************************************
270 Was this ACL protected ?
271 ************************************************************************/
273 static BOOL get_protected_flag(struct pai_val *pal)
277 return pal->protected;
280 /************************************************************************
281 Was this ACE inherited ?
282 ************************************************************************/
284 static BOOL get_inherited_flag(struct pai_val *pal, canon_ace *ace_entry, BOOL default_ace)
286 struct pai_entry *paie;
291 /* If the entry exists it is inherited. */
292 for (paie = (default_ace ? pal->def_entry_list : pal->entry_list); paie; paie = paie->next) {
293 if (ace_entry->owner_type == paie->owner_type &&
294 get_entry_val(ace_entry) == get_pai_entry_val(paie))
300 /************************************************************************
301 Ensure an attribute just read is valid.
302 ************************************************************************/
304 static BOOL check_pai_ok(char *pai_buf, size_t pai_buf_data_size)
307 uint16 num_def_entries;
309 if (pai_buf_data_size < PAI_ENTRIES_BASE) {
310 /* Corrupted - too small. */
314 if (CVAL(pai_buf,PAI_VERSION_OFFSET) != PAI_VERSION)
317 num_entries = SVAL(pai_buf,PAI_NUM_ENTRIES_OFFSET);
318 num_def_entries = SVAL(pai_buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET);
320 /* Check the entry lists match. */
321 /* Each entry is 5 bytes (type plus 4 bytes of uid or gid). */
323 if (((num_entries + num_def_entries)*PAI_ENTRY_LENGTH) + PAI_ENTRIES_BASE != pai_buf_data_size)
330 /************************************************************************
331 Convert to in-memory format.
332 ************************************************************************/
334 static struct pai_val *create_pai_val(char *buf, size_t size)
337 struct pai_val *paiv = NULL;
340 if (!check_pai_ok(buf, size))
343 paiv = malloc(sizeof(struct pai_val));
347 memset(paiv, '\0', sizeof(struct pai_val));
349 paiv->protected = (CVAL(buf,PAI_FLAG_OFFSET) == PAI_ACL_FLAG_PROTECTED);
351 paiv->num_entries = SVAL(buf,PAI_NUM_ENTRIES_OFFSET);
352 paiv->num_def_entries = SVAL(buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET);
354 entry_offset = buf + PAI_ENTRIES_BASE;
356 DEBUG(10,("create_pai_val:%s num_entries = %u, num_def_entries = %u\n",
357 paiv->protected ? " (protected)" : "", paiv->num_entries, paiv->num_def_entries ));
359 for (i = 0; i < paiv->num_entries; i++) {
360 struct pai_entry *paie;
362 paie = malloc(sizeof(struct pai_entry));
364 free_inherited_info(paiv);
368 paie->owner_type = (enum ace_owner)CVAL(entry_offset,0);
369 switch( paie->owner_type) {
371 paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1);
372 DEBUG(10,("create_pai_val: uid = %u\n", (unsigned int)paie->unix_ug.uid ));
375 paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1);
376 DEBUG(10,("create_pai_val: gid = %u\n", (unsigned int)paie->unix_ug.gid ));
379 paie->unix_ug.world = -1;
380 DEBUG(10,("create_pai_val: world ace\n"));
383 free_inherited_info(paiv);
386 entry_offset += PAI_ENTRY_LENGTH;
387 DLIST_ADD(paiv->entry_list, paie);
390 for (i = 0; i < paiv->num_def_entries; i++) {
391 struct pai_entry *paie;
393 paie = malloc(sizeof(struct pai_entry));
395 free_inherited_info(paiv);
399 paie->owner_type = (enum ace_owner)CVAL(entry_offset,0);
400 switch( paie->owner_type) {
402 paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1);
403 DEBUG(10,("create_pai_val: (def) uid = %u\n", (unsigned int)paie->unix_ug.uid ));
406 paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1);
407 DEBUG(10,("create_pai_val: (def) gid = %u\n", (unsigned int)paie->unix_ug.gid ));
410 paie->unix_ug.world = -1;
411 DEBUG(10,("create_pai_val: (def) world ace\n"));
414 free_inherited_info(paiv);
417 entry_offset += PAI_ENTRY_LENGTH;
418 DLIST_ADD(paiv->def_entry_list, paie);
424 /************************************************************************
425 Load the user.SAMBA_PAI attribute.
426 ************************************************************************/
428 static struct pai_val *load_inherited_info(files_struct *fsp)
431 size_t pai_buf_size = 1024;
432 struct pai_val *paiv = NULL;
435 if (!lp_map_acl_inherit(SNUM(fsp->conn)))
438 if ((pai_buf = malloc(pai_buf_size)) == NULL)
443 ret = SMB_VFS_FGETXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME,
444 pai_buf, pai_buf_size);
446 ret = SMB_VFS_GETXATTR(fsp->conn,fsp->fsp_name,SAMBA_POSIX_INHERITANCE_EA_NAME,
447 pai_buf, pai_buf_size);
450 if (errno != ERANGE) {
453 /* Buffer too small - enlarge it. */
456 if ((pai_buf = malloc(pai_buf_size)) == NULL)
461 DEBUG(10,("load_inherited_info: ret = %d for file %s\n", ret, fsp->fsp_name));
464 /* No attribute or not supported. */
466 if (errno != ENOATTR)
467 DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
470 DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
476 paiv = create_pai_val(pai_buf, ret);
478 if (paiv && paiv->protected)
479 DEBUG(10,("load_inherited_info: ACL is protected for file %s\n", fsp->fsp_name));
485 /****************************************************************************
486 Functions to manipulate the internal ACE format.
487 ****************************************************************************/
489 /****************************************************************************
490 Count a linked list of canonical ACE entries.
491 ****************************************************************************/
493 static size_t count_canon_ace_list( canon_ace *list_head )
498 for (ace = list_head; ace; ace = ace->next)
504 /****************************************************************************
505 Free a linked list of canonical ACE entries.
506 ****************************************************************************/
508 static void free_canon_ace_list( canon_ace *list_head )
511 canon_ace *old_head = list_head;
512 DLIST_REMOVE(list_head, list_head);
517 /****************************************************************************
518 Function to duplicate a canon_ace entry.
519 ****************************************************************************/
521 static canon_ace *dup_canon_ace( canon_ace *src_ace)
523 canon_ace *dst_ace = (canon_ace *)malloc(sizeof(canon_ace));
529 dst_ace->prev = dst_ace->next = NULL;
533 /****************************************************************************
534 Print out a canon ace.
535 ****************************************************************************/
537 static void print_canon_ace(canon_ace *pace, int num)
541 dbgtext( "canon_ace index %d. Type = %s ", num, pace->attr == ALLOW_ACE ? "allow" : "deny" );
542 dbgtext( "SID = %s ", sid_to_string( str, &pace->trustee));
543 if (pace->owner_type == UID_ACE) {
544 const char *u_name = uidtoname(pace->unix_ug.uid);
545 dbgtext( "uid %u (%s) %s", (unsigned int)pace->unix_ug.uid, u_name, pace->inherited ? "(inherited) " : "");
546 } else if (pace->owner_type == GID_ACE) {
547 char *g_name = gidtoname(pace->unix_ug.gid);
548 dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.gid, g_name);
551 switch (pace->type) {
553 dbgtext( "SMB_ACL_USER ");
555 case SMB_ACL_USER_OBJ:
556 dbgtext( "SMB_ACL_USER_OBJ ");
559 dbgtext( "SMB_ACL_GROUP ");
561 case SMB_ACL_GROUP_OBJ:
562 dbgtext( "SMB_ACL_GROUP_OBJ ");
565 dbgtext( "SMB_ACL_OTHER ");
569 dbgtext( "%c", pace->perms & S_IRUSR ? 'r' : '-');
570 dbgtext( "%c", pace->perms & S_IWUSR ? 'w' : '-');
571 dbgtext( "%c\n", pace->perms & S_IXUSR ? 'x' : '-');
574 /****************************************************************************
575 Print out a canon ace list.
576 ****************************************************************************/
578 static void print_canon_ace_list(const char *name, canon_ace *ace_list)
582 if( DEBUGLVL( 10 )) {
583 dbgtext( "print_canon_ace_list: %s\n", name );
584 for (;ace_list; ace_list = ace_list->next, count++)
585 print_canon_ace(ace_list, count );
589 /****************************************************************************
590 Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
591 ****************************************************************************/
593 static mode_t convert_permset_to_mode_t(connection_struct *conn, SMB_ACL_PERMSET_T permset)
597 ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRUSR : 0);
598 ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
599 ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
604 /****************************************************************************
605 Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
606 ****************************************************************************/
608 static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
622 /****************************************************************************
623 Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to
624 an SMB_ACL_PERMSET_T.
625 ****************************************************************************/
627 static int map_acl_perms_to_permset(connection_struct *conn, mode_t mode, SMB_ACL_PERMSET_T *p_permset)
629 if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) == -1)
631 if (mode & S_IRUSR) {
632 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1)
635 if (mode & S_IWUSR) {
636 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1)
639 if (mode & S_IXUSR) {
640 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1)
645 /****************************************************************************
646 Function to create owner and group SIDs from a SMB_STRUCT_STAT.
647 ****************************************************************************/
649 static void create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
651 uid_to_sid( powner_sid, psbuf->st_uid );
652 gid_to_sid( pgroup_sid, psbuf->st_gid );
655 /****************************************************************************
656 Merge aces with a common sid - if both are allow or deny, OR the permissions together and
657 delete the second one. If the first is deny, mask the permissions off and delete the allow
658 if the permissions become zero, delete the deny if the permissions are non zero.
659 ****************************************************************************/
661 static void merge_aces( canon_ace **pp_list_head )
663 canon_ace *list_head = *pp_list_head;
664 canon_ace *curr_ace_outer;
665 canon_ace *curr_ace_outer_next;
668 * First, merge allow entries with identical SIDs, and deny entries
669 * with identical SIDs.
672 for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
674 canon_ace *curr_ace_next;
676 curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
678 for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
680 curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
682 if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
683 (curr_ace->attr == curr_ace_outer->attr)) {
685 if( DEBUGLVL( 10 )) {
686 dbgtext("merge_aces: Merging ACE's\n");
687 print_canon_ace( curr_ace_outer, 0);
688 print_canon_ace( curr_ace, 0);
691 /* Merge two allow or two deny ACE's. */
693 curr_ace_outer->perms |= curr_ace->perms;
694 DLIST_REMOVE(list_head, curr_ace);
696 curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
702 * Now go through and mask off allow permissions with deny permissions.
703 * We can delete either the allow or deny here as we know that each SID
704 * appears only once in the list.
707 for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
709 canon_ace *curr_ace_next;
711 curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
713 for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
715 curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
718 * Subtract ACE's with different entries. Due to the ordering constraints
719 * we've put on the ACL, we know the deny must be the first one.
722 if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
723 (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
725 if( DEBUGLVL( 10 )) {
726 dbgtext("merge_aces: Masking ACE's\n");
727 print_canon_ace( curr_ace_outer, 0);
728 print_canon_ace( curr_ace, 0);
731 curr_ace->perms &= ~curr_ace_outer->perms;
733 if (curr_ace->perms == 0) {
736 * The deny overrides the allow. Remove the allow.
739 DLIST_REMOVE(list_head, curr_ace);
741 curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
746 * Even after removing permissions, there
747 * are still allow permissions - delete the deny.
748 * It is safe to delete the deny here,
749 * as we are guarenteed by the deny first
750 * ordering that all the deny entries for
751 * this SID have already been merged into one
752 * before we can get to an allow ace.
755 DLIST_REMOVE(list_head, curr_ace_outer);
756 SAFE_FREE(curr_ace_outer);
761 } /* end for curr_ace */
762 } /* end for curr_ace_outer */
764 /* We may have modified the list. */
766 *pp_list_head = list_head;
769 /****************************************************************************
770 Check if we need to return NT4.x compatible ACL entries.
771 ****************************************************************************/
773 static BOOL nt4_compatible_acls(void)
775 const char *compat = lp_acl_compatibility();
777 if (*compat == '\0') {
778 enum remote_arch_types ra_type = get_remote_arch();
780 /* Automatically adapt to client */
781 return (ra_type <= RA_WINNT);
783 return (strequal(compat, "winnt"));
787 /****************************************************************************
788 Map canon_ace perms to permission bits NT.
789 The attr element is not used here - we only process deny entries on set,
790 not get. Deny entries are implicit on get with ace->perms = 0.
791 ****************************************************************************/
793 static SEC_ACCESS map_canon_ace_perms(int *pacl_type, DOM_SID *powner_sid, canon_ace *ace)
798 *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
800 if ((ace->perms & ALL_ACE_PERMS) == ALL_ACE_PERMS) {
801 nt_mask = UNIX_ACCESS_RWX;
802 } else if ((ace->perms & ALL_ACE_PERMS) == (mode_t)0) {
804 * Windows NT refuses to display ACEs with no permissions in them (but
805 * they are perfectly legal with Windows 2000). If the ACE has empty
806 * permissions we cannot use 0, so we use the otherwise unused
807 * WRITE_OWNER permission, which we ignore when we set an ACL.
808 * We abstract this into a #define of UNIX_ACCESS_NONE to allow this
809 * to be changed in the future.
812 if (nt4_compatible_acls())
813 nt_mask = UNIX_ACCESS_NONE;
817 nt_mask |= ((ace->perms & S_IRUSR) ? UNIX_ACCESS_R : 0 );
818 nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
819 nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_ACCESS_X : 0 );
822 DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
823 (unsigned int)ace->perms, (unsigned int)nt_mask ));
825 init_sec_access(&sa,nt_mask);
829 /****************************************************************************
830 Map NT perms to a UNIX mode_t.
831 ****************************************************************************/
833 #define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
834 #define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
835 #define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
837 static mode_t map_nt_perms( SEC_ACCESS sec_access, int type)
843 if(sec_access.mask & GENERIC_ALL_ACCESS)
844 mode = S_IRUSR|S_IWUSR|S_IXUSR;
846 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
847 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
848 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
852 if(sec_access.mask & GENERIC_ALL_ACCESS)
853 mode = S_IRGRP|S_IWGRP|S_IXGRP;
855 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
856 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
857 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
861 if(sec_access.mask & GENERIC_ALL_ACCESS)
862 mode = S_IROTH|S_IWOTH|S_IXOTH;
864 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
865 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
866 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
874 /****************************************************************************
875 Unpack a SEC_DESC into a UNIX owner and group.
876 ****************************************************************************/
878 static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
886 if(security_info_sent == 0) {
887 DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
892 * Validate the owner and group SID's.
895 memset(&owner_sid, '\0', sizeof(owner_sid));
896 memset(&grp_sid, '\0', sizeof(grp_sid));
898 DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
901 * Don't immediately fail if the owner sid cannot be validated.
902 * This may be a group chown only set.
905 if (security_info_sent & OWNER_SECURITY_INFORMATION) {
906 sid_copy(&owner_sid, psd->owner_sid);
907 if (!NT_STATUS_IS_OK(sid_to_uid(&owner_sid, puser))) {
908 #if ACL_FORCE_UNMAPPABLE
909 /* this allows take ownership to work reasonably */
910 extern struct current_user current_user;
911 *puser = current_user.uid;
913 DEBUG(3,("unpack_nt_owners: unable to validate owner sid for %s\n",
914 sid_string_static(&owner_sid)));
921 * Don't immediately fail if the group sid cannot be validated.
922 * This may be an owner chown only set.
925 if (security_info_sent & GROUP_SECURITY_INFORMATION) {
926 sid_copy(&grp_sid, psd->grp_sid);
927 if (!NT_STATUS_IS_OK(sid_to_gid( &grp_sid, pgrp))) {
928 #if ACL_FORCE_UNMAPPABLE
929 /* this allows take group ownership to work reasonably */
930 extern struct current_user current_user;
931 *pgrp = current_user.gid;
933 DEBUG(3,("unpack_nt_owners: unable to validate group sid.\n"));
939 DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
944 /****************************************************************************
945 Ensure the enforced permissions for this share apply.
946 ****************************************************************************/
948 static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type)
950 int snum = SNUM(fsp->conn);
951 mode_t and_bits = (mode_t)0;
952 mode_t or_bits = (mode_t)0;
954 /* Get the initial bits to apply. */
956 if (fsp->is_directory) {
957 and_bits = lp_dir_security_mask(snum);
958 or_bits = lp_force_dir_security_mode(snum);
960 and_bits = lp_security_mask(snum);
961 or_bits = lp_force_security_mode(snum);
964 /* Now bounce them into the S_USR space. */
967 /* Ensure owner has read access. */
968 pace->perms |= S_IRUSR;
969 if (fsp->is_directory)
970 pace->perms |= (S_IWUSR|S_IXUSR);
971 and_bits = unix_perms_to_acl_perms(and_bits, S_IRUSR, S_IWUSR, S_IXUSR);
972 or_bits = unix_perms_to_acl_perms(or_bits, S_IRUSR, S_IWUSR, S_IXUSR);
975 and_bits = unix_perms_to_acl_perms(and_bits, S_IRGRP, S_IWGRP, S_IXGRP);
976 or_bits = unix_perms_to_acl_perms(or_bits, S_IRGRP, S_IWGRP, S_IXGRP);
979 and_bits = unix_perms_to_acl_perms(and_bits, S_IROTH, S_IWOTH, S_IXOTH);
980 or_bits = unix_perms_to_acl_perms(or_bits, S_IROTH, S_IWOTH, S_IXOTH);
984 pace->perms = ((pace->perms & and_bits)|or_bits);
987 /****************************************************************************
988 Check if a given uid/SID is in a group gid/SID. This is probably very
989 expensive and will need optimisation. A *lot* of optimisation :-). JRA.
990 ****************************************************************************/
992 static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
994 extern DOM_SID global_sid_World;
997 extern struct current_user current_user;
999 /* "Everyone" always matches every uid. */
1001 if (sid_equal(&group_ace->trustee, &global_sid_World))
1004 /* Assume that the current user is in the current group (force group) */
1006 if (uid_ace->unix_ug.uid == current_user.uid && group_ace->unix_ug.gid == current_user.gid)
1009 fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid));
1010 fstrcpy(g_name, gidtoname(group_ace->unix_ug.gid));
1013 * Due to the winbind interfaces we need to do this via names,
1017 return user_in_group_list(u_name, g_name, NULL, 0);
1020 /****************************************************************************
1021 A well formed POSIX file or default ACL has at least 3 entries, a
1022 SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
1023 In addition, the owner must always have at least read access.
1024 When using this call on get_acl, the pst struct is valid and contains
1025 the mode of the file. When using this call on set_acl, the pst struct has
1026 been modified to have a mode containing the default for this file or directory
1028 ****************************************************************************/
1030 static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
1032 DOM_SID *pfile_owner_sid,
1033 DOM_SID *pfile_grp_sid,
1034 SMB_STRUCT_STAT *pst,
1037 extern DOM_SID global_sid_World;
1039 BOOL got_user = False;
1040 BOOL got_grp = False;
1041 BOOL got_other = False;
1042 canon_ace *pace_other = NULL;
1043 canon_ace *pace_group = NULL;
1045 for (pace = *pp_ace; pace; pace = pace->next) {
1046 if (pace->type == SMB_ACL_USER_OBJ) {
1049 apply_default_perms(fsp, pace, S_IRUSR);
1052 } else if (pace->type == SMB_ACL_GROUP_OBJ) {
1055 * Ensure create mask/force create mode is respected on set.
1059 apply_default_perms(fsp, pace, S_IRGRP);
1063 } else if (pace->type == SMB_ACL_OTHER) {
1066 * Ensure create mask/force create mode is respected on set.
1070 apply_default_perms(fsp, pace, S_IROTH);
1077 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
1078 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1083 pace->type = SMB_ACL_USER_OBJ;
1084 pace->owner_type = UID_ACE;
1085 pace->unix_ug.uid = pst->st_uid;
1086 pace->trustee = *pfile_owner_sid;
1087 pace->attr = ALLOW_ACE;
1090 /* If we only got an "everyone" perm, just use that. */
1091 if (!got_grp && got_other)
1092 pace->perms = pace_other->perms;
1093 else if (got_grp && uid_entry_in_group(pace, pace_group))
1094 pace->perms = pace_group->perms;
1098 apply_default_perms(fsp, pace, S_IRUSR);
1100 pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
1103 DLIST_ADD(*pp_ace, pace);
1107 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
1108 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1113 pace->type = SMB_ACL_GROUP_OBJ;
1114 pace->owner_type = GID_ACE;
1115 pace->unix_ug.uid = pst->st_gid;
1116 pace->trustee = *pfile_grp_sid;
1117 pace->attr = ALLOW_ACE;
1119 /* If we only got an "everyone" perm, just use that. */
1121 pace->perms = pace_other->perms;
1124 apply_default_perms(fsp, pace, S_IRGRP);
1126 pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
1129 DLIST_ADD(*pp_ace, pace);
1133 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
1134 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1139 pace->type = SMB_ACL_OTHER;
1140 pace->owner_type = WORLD_ACE;
1141 pace->unix_ug.world = -1;
1142 pace->trustee = global_sid_World;
1143 pace->attr = ALLOW_ACE;
1146 apply_default_perms(fsp, pace, S_IROTH);
1148 pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
1150 DLIST_ADD(*pp_ace, pace);
1156 /****************************************************************************
1157 Check if a POSIX ACL has the required SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries.
1158 If it does not have them, check if there are any entries where the trustee is the
1159 file owner or the owning group, and map these to SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ.
1160 ****************************************************************************/
1162 static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid)
1164 BOOL got_user_obj, got_group_obj;
1165 canon_ace *current_ace;
1168 entries = count_canon_ace_list(ace);
1169 got_user_obj = False;
1170 got_group_obj = False;
1172 for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1173 if (current_ace->type == SMB_ACL_USER_OBJ)
1174 got_user_obj = True;
1175 else if (current_ace->type == SMB_ACL_GROUP_OBJ)
1176 got_group_obj = True;
1178 if (got_user_obj && got_group_obj) {
1179 DEBUG(10,("check_owning_objs: ACL had owning user/group entries.\n"));
1183 for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1184 if (!got_user_obj && current_ace->owner_type == UID_ACE &&
1185 sid_equal(¤t_ace->trustee, pfile_owner_sid)) {
1186 current_ace->type = SMB_ACL_USER_OBJ;
1187 got_user_obj = True;
1189 if (!got_group_obj && current_ace->owner_type == GID_ACE &&
1190 sid_equal(¤t_ace->trustee, pfile_grp_sid)) {
1191 current_ace->type = SMB_ACL_GROUP_OBJ;
1192 got_group_obj = True;
1196 DEBUG(10,("check_owning_objs: ACL is missing an owner entry.\n"));
1198 DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n"));
1201 /****************************************************************************
1202 Unpack a SEC_DESC into two canonical ace lists.
1203 ****************************************************************************/
1205 static BOOL create_canon_ace_lists(files_struct *fsp,
1206 DOM_SID *pfile_owner_sid,
1207 DOM_SID *pfile_grp_sid,
1208 canon_ace **ppfile_ace, canon_ace **ppdir_ace,
1211 extern DOM_SID global_sid_Creator_Owner;
1212 extern DOM_SID global_sid_Creator_Group;
1213 extern DOM_SID global_sid_World;
1214 extern struct generic_mapping file_generic_mapping;
1215 BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
1216 canon_ace *file_ace = NULL;
1217 canon_ace *dir_ace = NULL;
1218 canon_ace *tmp_ace = NULL;
1219 canon_ace *current_ace = NULL;
1220 BOOL got_dir_allow = False;
1221 BOOL got_file_allow = False;
1228 * Convert the incoming ACL into a more regular form.
1231 for(i = 0; i < dacl->num_aces; i++) {
1232 SEC_ACE *psa = &dacl->ace[i];
1234 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
1235 DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
1239 if (nt4_compatible_acls()) {
1241 * The security mask may be UNIX_ACCESS_NONE which should map into
1242 * no permissions (we overload the WRITE_OWNER bit for this) or it
1243 * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
1244 * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
1248 * Convert GENERIC bits to specific bits.
1251 se_map_generic(&psa->info.mask, &file_generic_mapping);
1253 psa->info.mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS);
1255 if(psa->info.mask != UNIX_ACCESS_NONE)
1256 psa->info.mask &= ~UNIX_ACCESS_NONE;
1261 * Deal with the fact that NT 4.x re-writes the canonical format
1262 * that we return for default ACLs. If a directory ACE is identical
1263 * to a inherited directory ACE then NT changes the bits so that the
1264 * first ACE is set to OI|IO and the second ACE for this SID is set
1265 * to CI. We need to repair this. JRA.
1268 for(i = 0; i < dacl->num_aces; i++) {
1269 SEC_ACE *psa1 = &dacl->ace[i];
1271 for (j = i + 1; j < dacl->num_aces; j++) {
1272 SEC_ACE *psa2 = &dacl->ace[j];
1274 if (psa1->info.mask != psa2->info.mask)
1277 if (!sid_equal(&psa1->trustee, &psa2->trustee))
1281 * Ok - permission bits and SIDs are equal.
1282 * Check if flags were re-written.
1285 if (psa1->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1287 psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1288 psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1290 } else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1292 psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1293 psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1299 for(i = 0; i < dacl->num_aces; i++) {
1300 SEC_ACE *psa = &dacl->ace[i];
1303 * Ignore non-mappable SIDs (NT Authority, BUILTIN etc).
1306 if (non_mappable_sid(&psa->trustee)) {
1308 DEBUG(10,("create_canon_ace_lists: ignoring non-mappable SID %s\n",
1309 sid_to_string(str, &psa->trustee) ));
1314 * Create a cannon_ace entry representing this NT DACL ACE.
1317 if ((current_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
1318 free_canon_ace_list(file_ace);
1319 free_canon_ace_list(dir_ace);
1320 DEBUG(0,("create_canon_ace_lists: malloc fail.\n"));
1324 ZERO_STRUCTP(current_ace);
1326 sid_copy(¤t_ace->trustee, &psa->trustee);
1329 * Try and work out if the SID is a user or group
1330 * as we need to flag these differently for POSIX.
1331 * Note what kind of a POSIX ACL this should map to.
1334 if( sid_equal(¤t_ace->trustee, &global_sid_World)) {
1335 current_ace->owner_type = WORLD_ACE;
1336 current_ace->unix_ug.world = -1;
1337 current_ace->type = SMB_ACL_OTHER;
1338 } else if (sid_equal(¤t_ace->trustee, &global_sid_Creator_Owner)) {
1339 current_ace->owner_type = UID_ACE;
1340 current_ace->unix_ug.world = -1;
1341 current_ace->type = SMB_ACL_USER_OBJ;
1344 * The Creator Owner entry only specifies inheritable permissions,
1345 * never access permissions. WinNT doesn't always set the ACE to
1346 *INHERIT_ONLY, though.
1349 if (nt4_compatible_acls())
1350 psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1351 } else if (sid_equal(¤t_ace->trustee, &global_sid_Creator_Group)) {
1352 current_ace->owner_type = GID_ACE;
1353 current_ace->unix_ug.world = -1;
1354 current_ace->type = SMB_ACL_GROUP_OBJ;
1357 * The Creator Group entry only specifies inheritable permissions,
1358 * never access permissions. WinNT doesn't always set the ACE to
1359 *INHERIT_ONLY, though.
1361 if (nt4_compatible_acls())
1362 psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1364 } else if (NT_STATUS_IS_OK(sid_to_gid( ¤t_ace->trustee, ¤t_ace->unix_ug.gid))) {
1365 current_ace->owner_type = GID_ACE;
1366 current_ace->type = SMB_ACL_GROUP;
1367 } else if (NT_STATUS_IS_OK(sid_to_uid( ¤t_ace->trustee, ¤t_ace->unix_ug.uid))) {
1368 current_ace->owner_type = UID_ACE;
1369 current_ace->type = SMB_ACL_USER;
1373 free_canon_ace_list(file_ace);
1374 free_canon_ace_list(dir_ace);
1375 DEBUG(0,("create_canon_ace_lists: unable to map SID %s to uid or gid.\n",
1376 sid_to_string(str, ¤t_ace->trustee) ));
1377 SAFE_FREE(current_ace);
1382 * Map the given NT permissions into a UNIX mode_t containing only
1383 * S_I(R|W|X)USR bits.
1386 current_ace->perms |= map_nt_perms( psa->info, S_IRUSR);
1387 current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
1388 current_ace->inherited = ((psa->flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False);
1391 * Now add the created ace to either the file list, the directory
1392 * list, or both. We *MUST* preserve the order here (hence we use
1393 * DLIST_ADD_END) as NT ACLs are order dependent.
1396 if (fsp->is_directory) {
1399 * We can only add to the default POSIX ACE list if the ACE is
1400 * designed to be inherited by both files and directories.
1403 if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
1404 (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
1406 DLIST_ADD_END(dir_ace, current_ace, tmp_ace);
1409 * Note if this was an allow ace. We can't process
1410 * any further deny ace's after this.
1413 if (current_ace->attr == ALLOW_ACE)
1414 got_dir_allow = True;
1416 if ((current_ace->attr == DENY_ACE) && got_dir_allow) {
1417 DEBUG(0,("create_canon_ace_lists: malformed ACL in inheritable ACL ! \
1418 Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
1419 free_canon_ace_list(file_ace);
1420 free_canon_ace_list(dir_ace);
1421 SAFE_FREE(current_ace);
1425 if( DEBUGLVL( 10 )) {
1426 dbgtext("create_canon_ace_lists: adding dir ACL:\n");
1427 print_canon_ace( current_ace, 0);
1431 * If this is not an inherit only ACE we need to add a duplicate
1435 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1436 canon_ace *dup_ace = dup_canon_ace(current_ace);
1439 DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
1440 free_canon_ace_list(file_ace);
1441 free_canon_ace_list(dir_ace);
1446 * We must not free current_ace here as its
1447 * pointer is now owned by the dir_ace list.
1449 current_ace = dup_ace;
1452 * We must not free current_ace here as its
1453 * pointer is now owned by the dir_ace list.
1461 * Only add to the file ACL if not inherit only.
1464 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1465 DLIST_ADD_END(file_ace, current_ace, tmp_ace);
1468 * Note if this was an allow ace. We can't process
1469 * any further deny ace's after this.
1472 if (current_ace->attr == ALLOW_ACE)
1473 got_file_allow = True;
1475 if ((current_ace->attr == DENY_ACE) && got_file_allow) {
1476 DEBUG(0,("create_canon_ace_lists: malformed ACL in file ACL ! \
1477 Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
1478 free_canon_ace_list(file_ace);
1479 free_canon_ace_list(dir_ace);
1480 SAFE_FREE(current_ace);
1484 if( DEBUGLVL( 10 )) {
1485 dbgtext("create_canon_ace_lists: adding file ACL:\n");
1486 print_canon_ace( current_ace, 0);
1488 all_aces_are_inherit_only = False;
1490 * We must not free current_ace here as its
1491 * pointer is now owned by the file_ace list.
1497 * Free if ACE was not added.
1500 SAFE_FREE(current_ace);
1503 if (fsp->is_directory && all_aces_are_inherit_only) {
1505 * Windows 2000 is doing one of these weird 'inherit acl'
1506 * traverses to conserve NTFS ACL resources. Just pretend
1507 * there was no DACL sent. JRA.
1510 DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n"));
1511 free_canon_ace_list(file_ace);
1512 free_canon_ace_list(dir_ace);
1517 * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in each
1518 * ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP
1519 * entries can be converted to *_OBJ. Usually we will already have these
1520 * entries in the Default ACL, and the Access ACL will not have them.
1522 check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);
1523 check_owning_objs(dir_ace, pfile_owner_sid, pfile_grp_sid);
1526 *ppfile_ace = file_ace;
1527 *ppdir_ace = dir_ace;
1532 /****************************************************************************
1533 ASCII art time again... JRA :-).
1535 We have 4 cases to process when moving from an NT ACL to a POSIX ACL. Firstly,
1536 we insist the ACL is in canonical form (ie. all DENY entries preceede ALLOW
1537 entries). Secondly, the merge code has ensured that all duplicate SID entries for
1538 allow or deny have been merged, so the same SID can only appear once in the deny
1539 list or once in the allow list.
1541 We then process as follows :
1543 ---------------------------------------------------------------------------
1544 First pass - look for a Everyone DENY entry.
1546 If it is deny all (rwx) trunate the list at this point.
1547 Else, walk the list from this point and use the deny permissions of this
1548 entry as a mask on all following allow entries. Finally, delete
1549 the Everyone DENY entry (we have applied it to everything possible).
1551 In addition, in this pass we remove any DENY entries that have
1552 no permissions (ie. they are a DENY nothing).
1553 ---------------------------------------------------------------------------
1554 Second pass - only deal with deny user entries.
1556 DENY user1 (perms XXX)
1559 for all following allow group entries where user1 is in group
1560 new_perms |= group_perms;
1562 user1 entry perms = new_perms & ~ XXX;
1564 Convert the deny entry to an allow entry with the new perms and
1565 push to the end of the list. Note if the user was in no groups
1566 this maps to a specific allow nothing entry for this user.
1568 The common case from the NT ACL choser (userX deny all) is
1569 optimised so we don't do the group lookup - we just map to
1570 an allow nothing entry.
1572 What we're doing here is inferring the allow permissions the
1573 person setting the ACE on user1 wanted by looking at the allow
1574 permissions on the groups the user is currently in. This will
1575 be a snapshot, depending on group membership but is the best
1576 we can do and has the advantage of failing closed rather than
1578 ---------------------------------------------------------------------------
1579 Third pass - only deal with deny group entries.
1581 DENY group1 (perms XXX)
1583 for all following allow user entries where user is in group1
1584 user entry perms = user entry perms & ~ XXX;
1586 If there is a group Everyone allow entry with permissions YYY,
1587 convert the group1 entry to an allow entry and modify its
1590 new_perms = YYY & ~ XXX
1592 and push to the end of the list.
1594 If there is no group Everyone allow entry then convert the
1595 group1 entry to a allow nothing entry and push to the end of the list.
1597 Note that the common case from the NT ACL choser (groupX deny all)
1598 cannot be optimised here as we need to modify user entries who are
1599 in the group to change them to a deny all also.
1601 What we're doing here is modifying the allow permissions of
1602 user entries (which are more specific in POSIX ACLs) to mask
1603 out the explicit deny set on the group they are in. This will
1604 be a snapshot depending on current group membership but is the
1605 best we can do and has the advantage of failing closed rather
1607 ---------------------------------------------------------------------------
1608 Fourth pass - cope with cumulative permissions.
1610 for all allow user entries, if there exists an allow group entry with
1611 more permissive permissions, and the user is in that group, rewrite the
1612 allow user permissions to contain both sets of permissions.
1614 Currently the code for this is #ifdef'ed out as these semantics make
1615 no sense to me. JRA.
1616 ---------------------------------------------------------------------------
1618 Note we *MUST* do the deny user pass first as this will convert deny user
1619 entries into allow user entries which can then be processed by the deny
1622 The above algorithm took a *lot* of thinking about - hence this
1623 explaination :-). JRA.
1624 ****************************************************************************/
1626 /****************************************************************************
1627 Process a canon_ace list entries. This is very complex code. We need
1628 to go through and remove the "deny" permissions from any allow entry that matches
1629 the id of this entry. We have already refused any NT ACL that wasn't in correct
1630 order (DENY followed by ALLOW). If any allow entry ends up with zero permissions,
1631 we just remove it (to fail safe). We have already removed any duplicate ace
1632 entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all
1634 ****************************************************************************/
1636 static void process_deny_list( canon_ace **pp_ace_list )
1638 extern DOM_SID global_sid_World;
1639 canon_ace *ace_list = *pp_ace_list;
1640 canon_ace *curr_ace = NULL;
1641 canon_ace *curr_ace_next = NULL;
1643 /* Pass 1 above - look for an Everyone, deny entry. */
1645 for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1646 canon_ace *allow_ace_p;
1648 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1650 if (curr_ace->attr != DENY_ACE)
1653 if (curr_ace->perms == (mode_t)0) {
1655 /* Deny nothing entry - delete. */
1657 DLIST_REMOVE(ace_list, curr_ace);
1661 if (!sid_equal(&curr_ace->trustee, &global_sid_World))
1664 /* JRATEST - assert. */
1665 SMB_ASSERT(curr_ace->owner_type == WORLD_ACE);
1667 if (curr_ace->perms == ALL_ACE_PERMS) {
1670 * Optimisation. This is a DENY_ALL to Everyone. Truncate the
1671 * list at this point including this entry.
1674 canon_ace *prev_entry = curr_ace->prev;
1676 free_canon_ace_list( curr_ace );
1678 prev_entry->next = NULL;
1680 /* We deleted the entire list. */
1686 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1689 * Only mask off allow entries.
1692 if (allow_ace_p->attr != ALLOW_ACE)
1695 allow_ace_p->perms &= ~curr_ace->perms;
1699 * Now it's been applied, remove it.
1702 DLIST_REMOVE(ace_list, curr_ace);
1705 /* Pass 2 above - deal with deny user entries. */
1707 for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1708 mode_t new_perms = (mode_t)0;
1709 canon_ace *allow_ace_p;
1712 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1714 if (curr_ace->attr != DENY_ACE)
1717 if (curr_ace->owner_type != UID_ACE)
1720 if (curr_ace->perms == ALL_ACE_PERMS) {
1723 * Optimisation - this is a deny everything to this user.
1724 * Convert to an allow nothing and push to the end of the list.
1727 curr_ace->attr = ALLOW_ACE;
1728 curr_ace->perms = (mode_t)0;
1729 DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1733 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1735 if (allow_ace_p->attr != ALLOW_ACE)
1738 /* We process GID_ACE and WORLD_ACE entries only. */
1740 if (allow_ace_p->owner_type == UID_ACE)
1743 if (uid_entry_in_group( curr_ace, allow_ace_p))
1744 new_perms |= allow_ace_p->perms;
1748 * Convert to a allow entry, modify the perms and push to the end
1752 curr_ace->attr = ALLOW_ACE;
1753 curr_ace->perms = (new_perms & ~curr_ace->perms);
1754 DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1757 /* Pass 3 above - deal with deny group entries. */
1759 for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1761 canon_ace *allow_ace_p;
1762 canon_ace *allow_everyone_p = NULL;
1764 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1766 if (curr_ace->attr != DENY_ACE)
1769 if (curr_ace->owner_type != GID_ACE)
1772 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1774 if (allow_ace_p->attr != ALLOW_ACE)
1777 /* Store a pointer to the Everyone allow, if it exists. */
1778 if (allow_ace_p->owner_type == WORLD_ACE)
1779 allow_everyone_p = allow_ace_p;
1781 /* We process UID_ACE entries only. */
1783 if (allow_ace_p->owner_type != UID_ACE)
1786 /* Mask off the deny group perms. */
1788 if (uid_entry_in_group( allow_ace_p, curr_ace))
1789 allow_ace_p->perms &= ~curr_ace->perms;
1793 * Convert the deny to an allow with the correct perms and
1794 * push to the end of the list.
1797 curr_ace->attr = ALLOW_ACE;
1798 if (allow_everyone_p)
1799 curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms;
1801 curr_ace->perms = (mode_t)0;
1802 DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1806 /* Doing this fourth pass allows Windows semantics to be layered
1807 * on top of POSIX semantics. I'm not sure if this is desirable.
1808 * For example, in W2K ACLs there is no way to say, "Group X no
1809 * access, user Y full access" if user Y is a member of group X.
1810 * This seems completely broken semantics to me.... JRA.
1814 /* Pass 4 above - deal with allow entries. */
1816 for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1817 canon_ace *allow_ace_p;
1819 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1821 if (curr_ace->attr != ALLOW_ACE)
1824 if (curr_ace->owner_type != UID_ACE)
1827 for (allow_ace_p = ace_list; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1829 if (allow_ace_p->attr != ALLOW_ACE)
1832 /* We process GID_ACE entries only. */
1834 if (allow_ace_p->owner_type != GID_ACE)
1837 /* OR in the group perms. */
1839 if (uid_entry_in_group( curr_ace, allow_ace_p))
1840 curr_ace->perms |= allow_ace_p->perms;
1845 *pp_ace_list = ace_list;
1848 /****************************************************************************
1849 Create a default mode that will be used if a security descriptor entry has
1850 no user/group/world entries.
1851 ****************************************************************************/
1853 static mode_t create_default_mode(files_struct *fsp, BOOL interitable_mode)
1855 int snum = SNUM(fsp->conn);
1856 mode_t and_bits = (mode_t)0;
1857 mode_t or_bits = (mode_t)0;
1858 mode_t mode = interitable_mode ? unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name) : S_IRUSR;
1860 if (fsp->is_directory)
1861 mode |= (S_IWUSR|S_IXUSR);
1864 * Now AND with the create mode/directory mode bits then OR with the
1865 * force create mode/force directory mode bits.
1868 if (fsp->is_directory) {
1869 and_bits = lp_dir_security_mask(snum);
1870 or_bits = lp_force_dir_security_mode(snum);
1872 and_bits = lp_security_mask(snum);
1873 or_bits = lp_force_security_mode(snum);
1876 return ((mode & and_bits)|or_bits);
1879 /****************************************************************************
1880 Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
1882 ****************************************************************************/
1884 static BOOL unpack_canon_ace(files_struct *fsp,
1885 SMB_STRUCT_STAT *pst,
1886 DOM_SID *pfile_owner_sid,
1887 DOM_SID *pfile_grp_sid,
1888 canon_ace **ppfile_ace, canon_ace **ppdir_ace,
1889 uint32 security_info_sent, SEC_DESC *psd)
1891 canon_ace *file_ace = NULL;
1892 canon_ace *dir_ace = NULL;
1897 if(security_info_sent == 0) {
1898 DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
1903 * If no DACL then this is a chown only security descriptor.
1906 if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !psd->dacl)
1910 * Now go through the DACL and create the canon_ace lists.
1913 if (!create_canon_ace_lists( fsp, pfile_owner_sid, pfile_grp_sid,
1914 &file_ace, &dir_ace, psd->dacl))
1917 if ((file_ace == NULL) && (dir_ace == NULL)) {
1918 /* W2K traverse DACL set - ignore. */
1923 * Go through the canon_ace list and merge entries
1924 * belonging to identical users of identical allow or deny type.
1925 * We can do this as all deny entries come first, followed by
1926 * all allow entries (we have mandated this before accepting this acl).
1929 print_canon_ace_list( "file ace - before merge", file_ace);
1930 merge_aces( &file_ace );
1932 print_canon_ace_list( "dir ace - before merge", dir_ace);
1933 merge_aces( &dir_ace );
1936 * NT ACLs are order dependent. Go through the acl lists and
1937 * process DENY entries by masking the allow entries.
1940 print_canon_ace_list( "file ace - before deny", file_ace);
1941 process_deny_list( &file_ace);
1943 print_canon_ace_list( "dir ace - before deny", dir_ace);
1944 process_deny_list( &dir_ace);
1947 * A well formed POSIX file or default ACL has at least 3 entries, a
1948 * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
1949 * and optionally a mask entry. Ensure this is the case.
1952 print_canon_ace_list( "file ace - before valid", file_ace);
1955 * A default 3 element mode entry for a file should be r-- --- ---.
1956 * A default 3 element mode entry for a directory should be rwx --- ---.
1959 pst->st_mode = create_default_mode(fsp, False);
1961 if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
1962 free_canon_ace_list(file_ace);
1963 free_canon_ace_list(dir_ace);
1967 print_canon_ace_list( "dir ace - before valid", dir_ace);
1970 * A default inheritable 3 element mode entry for a directory should be the
1971 * mode Samba will use to create a file within. Ensure user rwx bits are set if
1975 pst->st_mode = create_default_mode(fsp, True);
1977 if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
1978 free_canon_ace_list(file_ace);
1979 free_canon_ace_list(dir_ace);
1983 print_canon_ace_list( "file ace - return", file_ace);
1984 print_canon_ace_list( "dir ace - return", dir_ace);
1986 *ppfile_ace = file_ace;
1987 *ppdir_ace = dir_ace;
1992 /******************************************************************************
1993 When returning permissions, try and fit NT display
1994 semantics if possible. Note the the canon_entries here must have been malloced.
1995 The list format should be - first entry = owner, followed by group and other user
1996 entries, last entry = other.
1998 Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries
1999 are not ordered, and match on the most specific entry rather than walking a list,
2000 then a simple POSIX permission of rw-r--r-- should really map to 5 entries,
2002 Entry 0: owner : deny all except read and write.
2003 Entry 1: group : deny all except read.
2004 Entry 2: owner : allow read and write.
2005 Entry 3: group : allow read.
2006 Entry 4: Everyone : allow read.
2008 But NT cannot display this in their ACL editor !
2009 ********************************************************************************/
2011 static void arrange_posix_perms( char *filename, canon_ace **pp_list_head)
2013 canon_ace *list_head = *pp_list_head;
2014 canon_ace *owner_ace = NULL;
2015 canon_ace *other_ace = NULL;
2016 canon_ace *ace = NULL;
2018 for (ace = list_head; ace; ace = ace->next) {
2019 if (ace->type == SMB_ACL_USER_OBJ)
2021 else if (ace->type == SMB_ACL_OTHER) {
2022 /* Last ace - this is "other" */
2027 if (!owner_ace || !other_ace) {
2028 DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n",
2034 * The POSIX algorithm applies to owner first, and other last,
2035 * so ensure they are arranged in this order.
2039 DLIST_PROMOTE(list_head, owner_ace);
2043 DLIST_DEMOTE(list_head, other_ace, ace);
2046 /* We have probably changed the head of the list. */
2048 *pp_list_head = list_head;
2051 /****************************************************************************
2052 Create a linked list of canonical ACE entries.
2053 ****************************************************************************/
2055 static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf,
2056 DOM_SID *powner, DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type)
2058 extern DOM_SID global_sid_World;
2059 connection_struct *conn = fsp->conn;
2060 mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
2061 canon_ace *list_head = NULL;
2062 canon_ace *ace = NULL;
2063 canon_ace *next_ace = NULL;
2064 int entry_id = SMB_ACL_FIRST_ENTRY;
2065 SMB_ACL_ENTRY_T entry;
2068 while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
2069 SMB_ACL_TAG_T tagtype;
2070 SMB_ACL_PERMSET_T permset;
2073 enum ace_owner owner_type;
2076 if (entry_id == SMB_ACL_FIRST_ENTRY)
2077 entry_id = SMB_ACL_NEXT_ENTRY;
2079 /* Is this a MASK entry ? */
2080 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
2083 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
2086 /* Decide which SID to use based on the ACL type. */
2088 case SMB_ACL_USER_OBJ:
2089 /* Get the SID from the owner. */
2090 sid_copy(&sid, powner);
2091 unix_ug.uid = psbuf->st_uid;
2092 owner_type = UID_ACE;
2096 uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
2098 DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
2102 * A SMB_ACL_USER entry for the owner is shadowed by the
2103 * SMB_ACL_USER_OBJ entry and Windows also cannot represent
2104 * that entry, so we ignore it. We also don't create such
2105 * entries out of the blue when setting ACLs, so a get/set
2106 * cycle will drop them.
2108 if (the_acl_type == SMB_ACL_TYPE_ACCESS && *puid == psbuf->st_uid)
2110 uid_to_sid( &sid, *puid);
2111 unix_ug.uid = *puid;
2112 owner_type = UID_ACE;
2113 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
2116 case SMB_ACL_GROUP_OBJ:
2117 /* Get the SID from the owning group. */
2118 sid_copy(&sid, pgroup);
2119 unix_ug.gid = psbuf->st_gid;
2120 owner_type = GID_ACE;
2124 gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
2126 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
2129 gid_to_sid( &sid, *pgid);
2130 unix_ug.gid = *pgid;
2131 owner_type = GID_ACE;
2132 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
2136 acl_mask = convert_permset_to_mode_t(conn, permset);
2137 continue; /* Don't count the mask as an entry. */
2139 /* Use the Everyone SID */
2140 sid = global_sid_World;
2142 owner_type = WORLD_ACE;
2145 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
2150 * Add this entry to the list.
2153 if ((ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
2157 ace->type = tagtype;
2158 ace->perms = convert_permset_to_mode_t(conn, permset);
2159 ace->attr = ALLOW_ACE;
2161 ace->unix_ug = unix_ug;
2162 ace->owner_type = owner_type;
2163 ace->inherited = get_inherited_flag(pal, ace, (the_acl_type == SMB_ACL_TYPE_DEFAULT));
2165 DLIST_ADD(list_head, ace);
2169 * This next call will ensure we have at least a user/group/world set.
2172 if (!ensure_canon_entry_valid(&list_head, fsp, powner, pgroup, psbuf, False))
2176 * Now go through the list, masking the permissions with the
2177 * acl_mask. Ensure all DENY Entries are at the start of the list.
2180 DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", the_acl_type == SMB_ACL_TYPE_ACCESS ? "Access" : "Default" ));
2182 for ( ace_count = 0, ace = list_head; ace; ace = next_ace, ace_count++) {
2183 next_ace = ace->next;
2185 /* Masks are only applied to entries other than USER_OBJ and OTHER. */
2186 if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
2187 ace->perms &= acl_mask;
2189 if (ace->perms == 0) {
2190 DLIST_PROMOTE(list_head, ace);
2193 if( DEBUGLVL( 10 ) ) {
2194 print_canon_ace(ace, ace_count);
2198 arrange_posix_perms(fsp->fsp_name,&list_head );
2200 print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head );
2206 free_canon_ace_list(list_head);
2210 /****************************************************************************
2211 Attempt to apply an ACL to a file or directory.
2212 ****************************************************************************/
2214 static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, BOOL *pacl_set_support)
2216 connection_struct *conn = fsp->conn;
2218 SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, (int)count_canon_ace_list(the_ace) + 1);
2221 SMB_ACL_ENTRY_T mask_entry;
2222 BOOL got_mask_entry = False;
2223 SMB_ACL_PERMSET_T mask_permset;
2224 SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
2225 BOOL needs_mask = False;
2226 mode_t mask_perms = 0;
2228 #if defined(POSIX_ACL_NEEDS_MASK)
2229 /* HP-UX always wants to have a mask (called "class" there). */
2233 if (the_acl == NULL) {
2235 if (errno != ENOSYS) {
2237 * Only print this error message if we have some kind of ACL
2238 * support that's not working. Otherwise we would always get this.
2240 DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
2241 default_ace ? "default" : "file", strerror(errno) ));
2243 *pacl_set_support = False;
2247 if( DEBUGLVL( 10 )) {
2248 dbgtext("set_canon_ace_list: setting ACL:\n");
2249 for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2250 print_canon_ace( p_ace, i);
2254 for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2255 SMB_ACL_ENTRY_T the_entry;
2256 SMB_ACL_PERMSET_T the_permset;
2259 * ACLs only "need" an ACL_MASK entry if there are any named user or
2260 * named group entries. But if there is an ACL_MASK entry, it applies
2261 * to ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. Set the mask
2262 * so that it doesn't deny (i.e., mask off) any permissions.
2265 if (p_ace->type == SMB_ACL_USER || p_ace->type == SMB_ACL_GROUP) {
2267 mask_perms |= p_ace->perms;
2268 } else if (p_ace->type == SMB_ACL_GROUP_OBJ) {
2269 mask_perms |= p_ace->perms;
2273 * Get the entry for this ACE.
2276 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
2277 DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
2278 i, strerror(errno) ));
2282 if (p_ace->type == SMB_ACL_MASK) {
2283 mask_entry = the_entry;
2284 got_mask_entry = True;
2288 * Ok - we now know the ACL calls should be working, don't
2289 * allow fallback to chmod.
2292 *pacl_set_support = True;
2295 * Initialise the entry from the canon_ace.
2299 * First tell the entry what type of ACE this is.
2302 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, p_ace->type) == -1) {
2303 DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
2304 i, strerror(errno) ));
2309 * Only set the qualifier (user or group id) if the entry is a user
2313 if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
2314 if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
2315 DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
2316 i, strerror(errno) ));
2322 * Convert the mode_t perms in the canon_ace to a POSIX permset.
2325 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
2326 DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
2327 i, strerror(errno) ));
2331 if (map_acl_perms_to_permset(conn, p_ace->perms, &the_permset) == -1) {
2332 DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
2333 (unsigned int)p_ace->perms, i, strerror(errno) ));
2338 * ..and apply them to the entry.
2341 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
2342 DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
2343 i, strerror(errno) ));
2348 print_canon_ace( p_ace, i);
2352 if (needs_mask && !got_mask_entry) {
2353 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &mask_entry) == -1) {
2354 DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
2358 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, mask_entry, SMB_ACL_MASK) == -1) {
2359 DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
2363 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, mask_entry, &mask_permset) == -1) {
2364 DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
2368 if (map_acl_perms_to_permset(conn, S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
2369 DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
2373 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, mask_entry, mask_permset) == -1) {
2374 DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
2380 * Check if the ACL is valid.
2383 if (SMB_VFS_SYS_ACL_VALID(conn, the_acl) == -1) {
2384 DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n",
2385 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
2391 * Finally apply it to the file or directory.
2394 if(default_ace || fsp->is_directory || fsp->fd == -1) {
2395 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl) == -1) {
2397 * Some systems allow all the above calls and only fail with no ACL support
2398 * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2400 if (errno == ENOSYS)
2401 *pacl_set_support = False;
2404 if (errno == ENOTSUP)
2405 *pacl_set_support = False;
2408 DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
2409 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
2410 fsp->fsp_name, strerror(errno) ));
2414 if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fd, the_acl) == -1) {
2416 * Some systems allow all the above calls and only fail with no ACL support
2417 * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2419 if (errno == ENOSYS)
2420 *pacl_set_support = False;
2423 if (errno == ENOTSUP)
2424 *pacl_set_support = False;
2427 DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
2428 fsp->fsp_name, strerror(errno) ));
2437 if (the_acl != NULL)
2438 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2443 /****************************************************************************
2444 Find a particular canon_ace entry.
2445 ****************************************************************************/
2447 static struct canon_ace *canon_ace_entry_for(struct canon_ace *list, SMB_ACL_TAG_T type, posix_id *id)
2450 if (list->type == type && ((type != SMB_ACL_USER && type != SMB_ACL_GROUP) ||
2451 (type == SMB_ACL_USER && id && id->uid == list->unix_ug.uid) ||
2452 (type == SMB_ACL_GROUP && id && id->gid == list->unix_ug.gid)))
2459 /****************************************************************************
2461 ****************************************************************************/
2463 SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl)
2465 SMB_ACL_ENTRY_T entry;
2469 if (SMB_VFS_SYS_ACL_GET_ENTRY(conn, the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
2470 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2476 /****************************************************************************
2477 Convert a canon_ace to a generic 3 element permission - if possible.
2478 ****************************************************************************/
2480 #define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
2482 static BOOL convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
2484 int snum = SNUM(fsp->conn);
2485 size_t ace_count = count_canon_ace_list(file_ace_list);
2487 canon_ace *owner_ace = NULL;
2488 canon_ace *group_ace = NULL;
2489 canon_ace *other_ace = NULL;
2493 if (ace_count != 3) {
2494 DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \
2495 posix perms.\n", fsp->fsp_name ));
2499 for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
2500 if (ace_p->owner_type == UID_ACE)
2502 else if (ace_p->owner_type == GID_ACE)
2504 else if (ace_p->owner_type == WORLD_ACE)
2508 if (!owner_ace || !group_ace || !other_ace) {
2509 DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n",
2514 *posix_perms = (mode_t)0;
2516 *posix_perms |= owner_ace->perms;
2517 *posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP);
2518 *posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP);
2519 *posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP);
2520 *posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH);
2521 *posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH);
2522 *posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH);
2524 /* The owner must have at least read access. */
2526 *posix_perms |= S_IRUSR;
2527 if (fsp->is_directory)
2528 *posix_perms |= (S_IWUSR|S_IXUSR);
2530 /* If requested apply the masks. */
2532 /* Get the initial bits to apply. */
2534 if (fsp->is_directory) {
2535 and_bits = lp_dir_security_mask(snum);
2536 or_bits = lp_force_dir_security_mode(snum);
2538 and_bits = lp_security_mask(snum);
2539 or_bits = lp_force_security_mode(snum);
2542 *posix_perms = (((*posix_perms) & and_bits)|or_bits);
2544 DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n",
2545 (int)owner_ace->perms, (int)group_ace->perms, (int)other_ace->perms, (int)*posix_perms,
2551 static int nt_ace_comp( SEC_ACE *a1, SEC_ACE *a2)
2553 if (a1->type == a2->type)
2556 if (a1->type == SEC_ACE_TYPE_ACCESS_DENIED && a2->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
2561 /****************************************************************************
2562 Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and
2563 a normal POSIX acl. Win2k needs these split acls re-merging into one ACL
2564 with CI|OI set so it is inherited and also applies to the directory.
2565 Based on code from "Jim McDonough" <jmcd@us.ibm.com>.
2566 ****************************************************************************/
2568 static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
2572 for (i = 0; i < num_aces; i++) {
2573 for (j = i+1; j < num_aces; j++) {
2574 uint32 i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
2575 uint32 j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
2576 BOOL i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
2577 BOOL j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
2579 /* We know the lower number ACE's are file entries. */
2580 if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
2581 (nt_ace_list[i].size == nt_ace_list[j].size) &&
2582 (nt_ace_list[i].info.mask == nt_ace_list[j].info.mask) &&
2583 sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
2585 (i_flags_ni == 0) &&
2586 (j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT|
2587 SEC_ACE_FLAG_CONTAINER_INHERIT|
2588 SEC_ACE_FLAG_INHERIT_ONLY))) {
2590 * W2K wants to have access allowed zero access ACE's
2591 * at the end of the list. If the mask is zero, merge
2592 * the non-inherited ACE onto the inherited ACE.
2595 if (nt_ace_list[i].info.mask == 0) {
2596 nt_ace_list[j].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2597 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2598 if (num_aces - i - 1 > 0)
2599 memmove(&nt_ace_list[i], &nt_ace_list[i+1], (num_aces-i-1) *
2602 DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n",
2603 (unsigned int)i, (unsigned int)j ));
2606 * These are identical except for the flags.
2607 * Merge the inherited ACE onto the non-inherited ACE.
2610 nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2611 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2612 if (num_aces - j - 1 > 0)
2613 memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) *
2616 DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n",
2617 (unsigned int)j, (unsigned int)i ));
2627 /****************************************************************************
2628 Reply to query a security descriptor from an fsp. If it succeeds it allocates
2629 the space for the return elements and returns the size needed to return the
2630 security descriptor. This should be the only external function needed for
2631 the UNIX style get ACL.
2632 ****************************************************************************/
2634 size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
2636 extern DOM_SID global_sid_Builtin_Administrators;
2637 extern DOM_SID global_sid_Builtin_Users;
2638 extern DOM_SID global_sid_Creator_Owner;
2639 extern DOM_SID global_sid_Creator_Group;
2640 connection_struct *conn = fsp->conn;
2641 SMB_STRUCT_STAT sbuf;
2642 SEC_ACE *nt_ace_list = NULL;
2646 SEC_ACL *psa = NULL;
2647 size_t num_acls = 0;
2648 size_t num_dir_acls = 0;
2649 size_t num_aces = 0;
2650 SMB_ACL_T posix_acl = NULL;
2651 SMB_ACL_T dir_acl = NULL;
2652 canon_ace *file_ace = NULL;
2653 canon_ace *dir_ace = NULL;
2654 size_t num_profile_acls = 0;
2655 struct pai_val *pal = NULL;
2659 DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name ));
2661 if(fsp->is_directory || fsp->fd == -1) {
2663 /* Get the stat struct for the owner info. */
2664 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
2668 * Get the ACL from the path.
2671 posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
2674 * If it's a directory get the default POSIX ACL.
2677 if(fsp->is_directory) {
2678 dir_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
2679 dir_acl = free_empty_sys_acl(conn, dir_acl);
2684 /* Get the stat struct for the owner info. */
2685 if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) {
2689 * Get the ACL from the fd.
2691 posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd);
2694 DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
2695 posix_acl ? "present" : "absent",
2696 dir_acl ? "present" : "absent" ));
2698 pal = load_inherited_info(fsp);
2701 * Get the owner, group and world SIDs.
2704 if (lp_profile_acls(SNUM(fsp->conn))) {
2705 /* For WXP SP1 the owner must be administrators. */
2706 sid_copy(&owner_sid, &global_sid_Builtin_Administrators);
2707 sid_copy(&group_sid, &global_sid_Builtin_Users);
2708 num_profile_acls = 2;
2710 create_file_sids(&sbuf, &owner_sid, &group_sid);
2713 if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) {
2716 * In the optimum case Creator Owner and Creator Group would be used for
2717 * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this
2718 * would lead to usability problems under Windows: The Creator entries
2719 * are only available in browse lists of directories and not for files;
2720 * additionally the identity of the owning group couldn't be determined.
2721 * We therefore use those identities only for Default ACLs.
2724 /* Create the canon_ace lists. */
2725 file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid, pal, SMB_ACL_TYPE_ACCESS );
2727 /* We must have *some* ACLS. */
2729 if (count_canon_ace_list(file_ace) == 0) {
2730 DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name ));
2734 if (fsp->is_directory && dir_acl) {
2735 dir_ace = canonicalise_acl(fsp, dir_acl, &sbuf,
2736 &global_sid_Creator_Owner,
2737 &global_sid_Creator_Group, pal, SMB_ACL_TYPE_DEFAULT );
2741 * Create the NT ACE list from the canonical ace lists.
2749 if (nt4_compatible_acls() && dir_ace) {
2751 * NT 4 chokes if an ACL contains an INHERIT_ONLY entry
2752 * but no non-INHERIT_ONLY entry for one SID. So we only
2753 * remove entries from the Access ACL if the
2754 * corresponding Default ACL entries have also been
2755 * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP
2756 * are exceptions. We can do nothing
2757 * intelligent if the Default ACL contains entries that
2758 * are not also contained in the Access ACL, so this
2759 * case will still fail under NT 4.
2762 ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL);
2763 if (ace && !ace->perms) {
2764 DLIST_REMOVE(dir_ace, ace);
2767 ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL);
2768 if (ace && !ace->perms) {
2769 DLIST_REMOVE(file_ace, ace);
2775 * WinNT doesn't usually have Creator Group
2776 * in browse lists, so we send this entry to
2777 * WinNT even if it contains no relevant
2778 * permissions. Once we can add
2779 * Creator Group to browse lists we can
2784 ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL);
2785 if (ace && !ace->perms) {
2786 DLIST_REMOVE(dir_ace, ace);
2791 ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL);
2792 if (ace && !ace->perms) {
2793 DLIST_REMOVE(file_ace, ace);
2798 num_acls = count_canon_ace_list(file_ace);
2799 num_dir_acls = count_canon_ace_list(dir_ace);
2801 /* Allocate the ace list. */
2802 if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_profile_acls + num_dir_acls)* sizeof(SEC_ACE))) == NULL) {
2803 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
2807 memset(nt_ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) );
2810 * Create the NT ACE list from the canonical ace lists.
2815 for (i = 0; i < num_acls; i++, ace = ace->next) {
2818 acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
2819 init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2822 /* The User must have access to a profile share - even if we can't map the SID. */
2823 if (lp_profile_acls(SNUM(fsp->conn))) {
2826 init_sec_access(&acc,FILE_GENERIC_ALL);
2827 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED,
2833 for (i = 0; i < num_dir_acls; i++, ace = ace->next) {
2836 acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
2837 init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc,
2838 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2839 SEC_ACE_FLAG_INHERIT_ONLY|
2840 (ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0));
2843 /* The User must have access to a profile share - even if we can't map the SID. */
2844 if (lp_profile_acls(SNUM(fsp->conn))) {
2847 init_sec_access(&acc,FILE_GENERIC_ALL);
2848 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc,
2849 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2850 SEC_ACE_FLAG_INHERIT_ONLY|0);
2854 * Merge POSIX default ACLs and normal ACLs into one NT ACE.
2855 * Win2K needs this to get the inheritance correct when replacing ACLs
2856 * on a directory tree. Based on work by Jim @ IBM.
2859 num_aces = merge_default_aces(nt_ace_list, num_aces);
2862 * Sort to force deny entries to the front.
2866 qsort( nt_ace_list, num_aces, sizeof(nt_ace_list[0]), QSORT_CAST nt_ace_comp);
2870 if((psa = make_sec_acl( main_loop_talloc_get(), ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
2871 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
2875 } /* security_info & DACL_SECURITY_INFORMATION */
2877 *ppdesc = make_standard_sec_desc( main_loop_talloc_get(),
2878 (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL,
2879 (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL,
2884 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
2888 * Windows 2000: The DACL_PROTECTED flag in the security
2889 * descriptor marks the ACL as non-inheriting, i.e., no
2890 * ACEs from higher level directories propagate to this
2891 * ACL. In the POSIX ACL model permissions are only
2892 * inherited at file create time, so ACLs never contain
2893 * any ACEs that are inherited dynamically. The DACL_PROTECTED
2894 * flag doesn't seem to bother Windows NT.
2896 if (get_protected_flag(pal))
2897 (*ppdesc)->type |= SE_DESC_DACL_PROTECTED;
2903 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
2905 SMB_VFS_SYS_ACL_FREE_ACL(conn, dir_acl);
2906 free_canon_ace_list(file_ace);
2907 free_canon_ace_list(dir_ace);
2908 free_inherited_info(pal);
2909 SAFE_FREE(nt_ace_list);
2914 /****************************************************************************
2915 Try to chown a file. We will be able to chown it under the following conditions.
2917 1) If we have root privileges, then it will just work.
2918 2) If we have write permission to the file and dos_filemodes is set
2919 then allow chown to the currently authenticated user.
2920 ****************************************************************************/
2922 static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
2925 extern struct current_user current_user;
2929 /* try the direct way first */
2930 ret = SMB_VFS_CHOWN(conn, fname, uid, gid);
2934 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
2937 if (SMB_VFS_STAT(conn,fname,&st))
2940 fsp = open_file_fchmod(conn,fname,&st);
2944 /* only allow chown to the current user. This is more secure,
2945 and also copes with the case where the SID in a take ownership ACL is
2946 a local SID on the users workstation
2948 uid = current_user.uid;
2951 /* Keep the current file gid the same. */
2952 ret = SMB_VFS_FCHOWN(fsp, fsp->fd, uid, (gid_t)-1);
2955 close_file_fchmod(fsp);
2960 /****************************************************************************
2961 Reply to set a security descriptor on an fsp. security_info_sent is the
2962 description of the following NT ACL.
2963 This should be the only external function needed for the UNIX style set ACL.
2964 ****************************************************************************/
2966 BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
2968 connection_struct *conn = fsp->conn;
2969 uid_t user = (uid_t)-1;
2970 gid_t grp = (gid_t)-1;
2971 SMB_STRUCT_STAT sbuf;
2972 DOM_SID file_owner_sid;
2973 DOM_SID file_grp_sid;
2974 canon_ace *file_ace_list = NULL;
2975 canon_ace *dir_ace_list = NULL;
2976 BOOL acl_perms = False;
2977 mode_t orig_mode = (mode_t)0;
2980 BOOL need_chown = False;
2981 extern struct current_user current_user;
2983 DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
2985 if (!CAN_WRITE(conn)) {
2986 DEBUG(10,("set acl rejected on read-only share\n"));
2991 * Get the current state of the file.
2994 if(fsp->is_directory || fsp->fd == -1) {
2995 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0)
2998 if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0)
3002 /* Save the original elements we check against. */
3003 orig_mode = sbuf.st_mode;
3004 orig_uid = sbuf.st_uid;
3005 orig_gid = sbuf.st_gid;
3008 * Unpack the user/group/world id's.
3011 if (!unpack_nt_owners( &sbuf, &user, &grp, security_info_sent, psd))
3015 * Do we need to chown ?
3018 if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp)))
3022 * Chown before setting ACL only if we don't change the user, or
3023 * if we change to the current user, but not if we want to give away
3027 if (need_chown && (user == (uid_t)-1 || user == current_user.uid)) {
3029 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3030 fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
3032 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
3033 DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3034 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
3039 * Recheck the current state of the file, which may have changed.
3040 * (suid/sgid bits, for instance)
3043 if(fsp->is_directory) {
3044 if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
3052 ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf);
3054 ret = SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf);
3060 /* Save the original elements we check against. */
3061 orig_mode = sbuf.st_mode;
3062 orig_uid = sbuf.st_uid;
3063 orig_gid = sbuf.st_gid;
3065 /* We did it, don't try again */
3069 create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
3071 acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
3072 &file_ace_list, &dir_ace_list, security_info_sent, psd);
3074 /* Ignore W2K traverse DACL set. */
3075 if (file_ace_list || dir_ace_list) {
3078 DEBUG(3,("set_nt_acl: cannot set permissions\n"));
3079 free_canon_ace_list(file_ace_list);
3080 free_canon_ace_list(dir_ace_list);
3085 * Only change security if we got a DACL.
3088 if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
3090 BOOL acl_set_support = False;
3094 * Try using the POSIX ACL set first. Fall back to chmod if
3095 * we have no ACL support on this filesystem.
3098 if (acl_perms && file_ace_list) {
3099 ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support);
3100 if (acl_set_support && ret == False) {
3101 DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
3102 free_canon_ace_list(file_ace_list);
3103 free_canon_ace_list(dir_ace_list);
3108 if (acl_perms && acl_set_support && fsp->is_directory) {
3110 if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) {
3111 DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
3112 free_canon_ace_list(file_ace_list);
3113 free_canon_ace_list(dir_ace_list);
3119 * No default ACL - delete one if it exists.
3122 if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name) == -1) {
3123 DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
3124 free_canon_ace_list(file_ace_list);
3125 free_canon_ace_list(dir_ace_list);
3131 if (acl_set_support)
3132 store_inheritance_attributes(fsp, file_ace_list, dir_ace_list,
3133 (psd->type & SE_DESC_DACL_PROTECTED) ? True : False);
3136 * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
3139 if(!acl_set_support && acl_perms) {
3142 if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
3143 free_canon_ace_list(file_ace_list);
3144 free_canon_ace_list(dir_ace_list);
3145 DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
3150 if (orig_mode != posix_perms) {
3152 DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
3153 fsp->fsp_name, (unsigned int)posix_perms ));
3155 if(SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms) == -1) {
3156 DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
3157 fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
3158 free_canon_ace_list(file_ace_list);
3159 free_canon_ace_list(dir_ace_list);
3166 free_canon_ace_list(file_ace_list);
3167 free_canon_ace_list(dir_ace_list);
3170 /* Any chown pending? */
3173 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3174 fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
3176 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
3177 DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3178 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
3186 /****************************************************************************
3187 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3188 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3189 ****************************************************************************/
3191 static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mode_t mode)
3193 int entry_id = SMB_ACL_FIRST_ENTRY;
3194 SMB_ACL_ENTRY_T entry;
3195 int num_entries = 0;
3197 while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3198 SMB_ACL_TAG_T tagtype;
3199 SMB_ACL_PERMSET_T permset;
3203 if (entry_id == SMB_ACL_FIRST_ENTRY)
3204 entry_id = SMB_ACL_NEXT_ENTRY;
3206 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
3209 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
3215 case SMB_ACL_USER_OBJ:
3216 perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
3218 case SMB_ACL_GROUP_OBJ:
3219 perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
3223 * FIXME: The ACL_MASK entry permissions should really be set to
3224 * the union of the permissions of all ACL_USER,
3225 * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what
3226 * acl_calc_mask() does, but Samba ACLs doesn't provide it.
3228 perms = S_IRUSR|S_IWUSR|S_IXUSR;
3231 perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
3237 if (map_acl_perms_to_permset(conn, perms, &permset) == -1)
3240 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) == -1)
3245 * If this is a simple 3 element ACL or no elements then it's a standard
3246 * UNIX permission set. Just use chmod...
3249 if ((num_entries == 3) || (num_entries == 0))
3255 /****************************************************************************
3256 Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ,
3257 GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the
3258 resulting ACL on TO. Note that name is in UNIX character set.
3259 ****************************************************************************/
3261 static int copy_access_acl(connection_struct *conn, const char *from, const char *to, mode_t mode)
3263 SMB_ACL_T posix_acl = NULL;
3266 if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL)
3269 if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3272 ret = SMB_VFS_SYS_ACL_SET_FILE(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl);
3276 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3280 /****************************************************************************
3281 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3282 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3283 Note that name is in UNIX character set.
3284 ****************************************************************************/
3286 int chmod_acl(connection_struct *conn, const char *name, mode_t mode)
3288 return copy_access_acl(conn, name, name, mode);
3291 /****************************************************************************
3292 If "inherit permissions" is set and the parent directory has no default
3293 ACL but it does have an Access ACL, inherit this Access ACL to file name.
3294 ****************************************************************************/
3296 int inherit_access_acl(connection_struct *conn, const char *name, mode_t mode)
3299 pstrcpy(dirname, parent_dirname(name));
3301 if (!lp_inherit_perms(SNUM(conn)) || directory_has_default_acl(conn, dirname))
3304 return copy_access_acl(conn, dirname, name, mode);
3307 /****************************************************************************
3308 Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3309 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3310 ****************************************************************************/
3312 int fchmod_acl(files_struct *fsp, int fd, mode_t mode)
3314 connection_struct *conn = fsp->conn;
3315 SMB_ACL_T posix_acl = NULL;
3318 if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fd)) == NULL)
3321 if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3324 ret = SMB_VFS_SYS_ACL_SET_FD(fsp, fd, posix_acl);
3328 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3332 /****************************************************************************
3333 Check for an existing default POSIX ACL on a directory.
3334 ****************************************************************************/
3336 BOOL directory_has_default_acl(connection_struct *conn, const char *fname)
3338 SMB_ACL_T dir_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT);
3339 BOOL has_acl = False;
3340 SMB_ACL_ENTRY_T entry;
3342 if (dir_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, dir_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1))
3346 SMB_VFS_SYS_ACL_FREE_ACL(conn, dir_acl);