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_ERR(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_ERR(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))
2175 arrange_posix_perms(fsp->fsp_name,&list_head );
2178 * Now go through the list, masking the permissions with the
2179 * acl_mask. Ensure all DENY Entries are at the start of the list.
2182 DEBUG(10,("canonicalise_acl: ace entries before arrange :\n"));
2184 for ( ace_count = 0, ace = list_head; ace; ace = next_ace, ace_count++) {
2185 next_ace = ace->next;
2187 /* Masks are only applied to entries other than USER_OBJ and OTHER. */
2188 if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
2189 ace->perms &= acl_mask;
2191 if (ace->perms == 0) {
2192 DLIST_PROMOTE(list_head, ace);
2195 if( DEBUGLVL( 10 ) ) {
2196 print_canon_ace(ace, ace_count);
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 /* We know the lower number ACE's are file entries. */
2575 if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
2576 (nt_ace_list[i].size == nt_ace_list[j].size) &&
2577 (nt_ace_list[i].info.mask == nt_ace_list[j].info.mask) &&
2578 sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
2579 (nt_ace_list[i].flags == 0) &&
2580 (nt_ace_list[j].flags == (SEC_ACE_FLAG_OBJECT_INHERIT|
2581 SEC_ACE_FLAG_CONTAINER_INHERIT|
2582 SEC_ACE_FLAG_INHERIT_ONLY))) {
2584 * These are identical except for the flags.
2585 * Merge the inherited ACE onto the non-inherited ACE.
2588 nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT;
2589 if (num_aces - j - 1 > 0)
2590 memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) *
2600 /****************************************************************************
2601 Reply to query a security descriptor from an fsp. If it succeeds it allocates
2602 the space for the return elements and returns the size needed to return the
2603 security descriptor. This should be the only external function needed for
2604 the UNIX style get ACL.
2605 ****************************************************************************/
2607 size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
2609 extern DOM_SID global_sid_Builtin_Administrators;
2610 extern DOM_SID global_sid_Builtin_Users;
2611 extern DOM_SID global_sid_Creator_Owner;
2612 extern DOM_SID global_sid_Creator_Group;
2613 connection_struct *conn = fsp->conn;
2614 SMB_STRUCT_STAT sbuf;
2615 SEC_ACE *nt_ace_list = NULL;
2619 SEC_ACL *psa = NULL;
2620 size_t num_acls = 0;
2621 size_t num_dir_acls = 0;
2622 size_t num_aces = 0;
2623 SMB_ACL_T posix_acl = NULL;
2624 SMB_ACL_T dir_acl = NULL;
2625 canon_ace *file_ace = NULL;
2626 canon_ace *dir_ace = NULL;
2627 size_t num_profile_acls = 0;
2628 struct pai_val *pal = NULL;
2632 DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name ));
2634 if(fsp->is_directory || fsp->fd == -1) {
2636 /* Get the stat struct for the owner info. */
2637 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
2641 * Get the ACL from the path.
2644 posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
2647 * If it's a directory get the default POSIX ACL.
2650 if(fsp->is_directory) {
2651 dir_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
2652 dir_acl = free_empty_sys_acl(conn, dir_acl);
2657 /* Get the stat struct for the owner info. */
2658 if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) {
2662 * Get the ACL from the fd.
2664 posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd);
2667 DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
2668 posix_acl ? "present" : "absent",
2669 dir_acl ? "present" : "absent" ));
2671 pal = load_inherited_info(fsp);
2674 * Get the owner, group and world SIDs.
2677 if (lp_profile_acls(SNUM(fsp->conn))) {
2678 /* For WXP SP1 the owner must be administrators. */
2679 sid_copy(&owner_sid, &global_sid_Builtin_Administrators);
2680 sid_copy(&group_sid, &global_sid_Builtin_Users);
2681 num_profile_acls = 2;
2683 create_file_sids(&sbuf, &owner_sid, &group_sid);
2686 if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) {
2689 * In the optimum case Creator Owner and Creator Group would be used for
2690 * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this
2691 * would lead to usability problems under Windows: The Creator entries
2692 * are only available in browse lists of directories and not for files;
2693 * additionally the identity of the owning group couldn't be determined.
2694 * We therefore use those identities only for Default ACLs.
2697 /* Create the canon_ace lists. */
2698 file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid, pal, SMB_ACL_TYPE_ACCESS );
2700 /* We must have *some* ACLS. */
2702 if (count_canon_ace_list(file_ace) == 0) {
2703 DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name ));
2707 if (fsp->is_directory && dir_acl) {
2708 dir_ace = canonicalise_acl(fsp, dir_acl, &sbuf,
2709 &global_sid_Creator_Owner,
2710 &global_sid_Creator_Group, pal, SMB_ACL_TYPE_DEFAULT );
2714 * Create the NT ACE list from the canonical ace lists.
2722 if (nt4_compatible_acls() && dir_ace) {
2724 * NT 4 chokes if an ACL contains an INHERIT_ONLY entry
2725 * but no non-INHERIT_ONLY entry for one SID. So we only
2726 * remove entries from the Access ACL if the
2727 * corresponding Default ACL entries have also been
2728 * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP
2729 * are exceptions. We can do nothing
2730 * intelligent if the Default ACL contains entries that
2731 * are not also contained in the Access ACL, so this
2732 * case will still fail under NT 4.
2735 ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL);
2736 if (ace && !ace->perms) {
2737 DLIST_REMOVE(dir_ace, ace);
2740 ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL);
2741 if (ace && !ace->perms) {
2742 DLIST_REMOVE(file_ace, ace);
2748 * WinNT doesn't usually have Creator Group
2749 * in browse lists, so we send this entry to
2750 * WinNT even if it contains no relevant
2751 * permissions. Once we can add
2752 * Creator Group to browse lists we can
2757 ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL);
2758 if (ace && !ace->perms) {
2759 DLIST_REMOVE(dir_ace, ace);
2764 ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL);
2765 if (ace && !ace->perms) {
2766 DLIST_REMOVE(file_ace, ace);
2771 num_acls = count_canon_ace_list(file_ace);
2772 num_dir_acls = count_canon_ace_list(dir_ace);
2774 /* Allocate the ace list. */
2775 if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_profile_acls + num_dir_acls)* sizeof(SEC_ACE))) == NULL) {
2776 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
2780 memset(nt_ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) );
2783 * Create the NT ACE list from the canonical ace lists.
2788 for (i = 0; i < num_acls; i++, ace = ace->next) {
2791 acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
2792 init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2795 /* The User must have access to a profile share - even if we can't map the SID. */
2796 if (lp_profile_acls(SNUM(fsp->conn))) {
2799 init_sec_access(&acc,FILE_GENERIC_ALL);
2800 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED,
2806 for (i = 0; i < num_dir_acls; i++, ace = ace->next) {
2809 acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
2810 init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc,
2811 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2812 SEC_ACE_FLAG_INHERIT_ONLY|
2813 (ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0));
2816 /* The User must have access to a profile share - even if we can't map the SID. */
2817 if (lp_profile_acls(SNUM(fsp->conn))) {
2820 init_sec_access(&acc,FILE_GENERIC_ALL);
2821 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc,
2822 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2823 SEC_ACE_FLAG_INHERIT_ONLY|0);
2827 * Merge POSIX default ACLs and normal ACLs into one NT ACE.
2828 * Win2K needs this to get the inheritance correct when replacing ACLs
2829 * on a directory tree. Based on work by Jim @ IBM.
2832 num_aces = merge_default_aces(nt_ace_list, num_aces);
2835 * Sort to force deny entries to the front.
2839 qsort( nt_ace_list, num_aces, sizeof(nt_ace_list[0]), QSORT_CAST nt_ace_comp);
2843 if((psa = make_sec_acl( main_loop_talloc_get(), ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
2844 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
2848 } /* security_info & DACL_SECURITY_INFORMATION */
2850 *ppdesc = make_standard_sec_desc( main_loop_talloc_get(),
2851 (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL,
2852 (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL,
2857 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
2861 * Windows 2000: The DACL_PROTECTED flag in the security
2862 * descriptor marks the ACL as non-inheriting, i.e., no
2863 * ACEs from higher level directories propagate to this
2864 * ACL. In the POSIX ACL model permissions are only
2865 * inherited at file create time, so ACLs never contain
2866 * any ACEs that are inherited dynamically. The DACL_PROTECTED
2867 * flag doesn't seem to bother Windows NT.
2869 if (get_protected_flag(pal))
2870 (*ppdesc)->type |= SE_DESC_DACL_PROTECTED;
2876 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
2878 SMB_VFS_SYS_ACL_FREE_ACL(conn, dir_acl);
2879 free_canon_ace_list(file_ace);
2880 free_canon_ace_list(dir_ace);
2881 free_inherited_info(pal);
2882 SAFE_FREE(nt_ace_list);
2887 /****************************************************************************
2888 Try to chown a file. We will be able to chown it under the following conditions.
2890 1) If we have root privileges, then it will just work.
2891 2) If we have write permission to the file and dos_filemodes is set
2892 then allow chown to the currently authenticated user.
2893 ****************************************************************************/
2895 static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
2898 extern struct current_user current_user;
2902 /* try the direct way first */
2903 ret = SMB_VFS_CHOWN(conn, fname, uid, gid);
2907 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
2910 if (SMB_VFS_STAT(conn,fname,&st))
2913 fsp = open_file_fchmod(conn,fname,&st);
2917 /* only allow chown to the current user. This is more secure,
2918 and also copes with the case where the SID in a take ownership ACL is
2919 a local SID on the users workstation
2921 uid = current_user.uid;
2924 /* Keep the current file gid the same. */
2925 ret = SMB_VFS_FCHOWN(fsp, fsp->fd, uid, (gid_t)-1);
2928 close_file_fchmod(fsp);
2933 /****************************************************************************
2934 Reply to set a security descriptor on an fsp. security_info_sent is the
2935 description of the following NT ACL.
2936 This should be the only external function needed for the UNIX style set ACL.
2937 ****************************************************************************/
2939 BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
2941 connection_struct *conn = fsp->conn;
2942 uid_t user = (uid_t)-1;
2943 gid_t grp = (gid_t)-1;
2944 SMB_STRUCT_STAT sbuf;
2945 DOM_SID file_owner_sid;
2946 DOM_SID file_grp_sid;
2947 canon_ace *file_ace_list = NULL;
2948 canon_ace *dir_ace_list = NULL;
2949 BOOL acl_perms = False;
2950 mode_t orig_mode = (mode_t)0;
2953 BOOL need_chown = False;
2954 extern struct current_user current_user;
2956 DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
2958 if (!CAN_WRITE(conn)) {
2959 DEBUG(10,("set acl rejected on read-only share\n"));
2964 * Get the current state of the file.
2967 if(fsp->is_directory || fsp->fd == -1) {
2968 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0)
2971 if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0)
2975 /* Save the original elements we check against. */
2976 orig_mode = sbuf.st_mode;
2977 orig_uid = sbuf.st_uid;
2978 orig_gid = sbuf.st_gid;
2981 * Unpack the user/group/world id's.
2984 if (!unpack_nt_owners( &sbuf, &user, &grp, security_info_sent, psd))
2988 * Do we need to chown ?
2991 if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp)))
2995 * Chown before setting ACL only if we don't change the user, or
2996 * if we change to the current user, but not if we want to give away
3000 if (need_chown && (user == (uid_t)-1 || user == current_user.uid)) {
3002 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3003 fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
3005 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
3006 DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3007 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
3012 * Recheck the current state of the file, which may have changed.
3013 * (suid/sgid bits, for instance)
3016 if(fsp->is_directory) {
3017 if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
3025 ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf);
3027 ret = SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf);
3033 /* Save the original elements we check against. */
3034 orig_mode = sbuf.st_mode;
3035 orig_uid = sbuf.st_uid;
3036 orig_gid = sbuf.st_gid;
3038 /* We did it, don't try again */
3042 create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
3044 acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
3045 &file_ace_list, &dir_ace_list, security_info_sent, psd);
3047 /* Ignore W2K traverse DACL set. */
3048 if (file_ace_list || dir_ace_list) {
3051 DEBUG(3,("set_nt_acl: cannot set permissions\n"));
3052 free_canon_ace_list(file_ace_list);
3053 free_canon_ace_list(dir_ace_list);
3058 * Only change security if we got a DACL.
3061 if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
3063 BOOL acl_set_support = False;
3067 * Try using the POSIX ACL set first. Fall back to chmod if
3068 * we have no ACL support on this filesystem.
3071 if (acl_perms && file_ace_list) {
3072 ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support);
3073 if (acl_set_support && ret == False) {
3074 DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
3075 free_canon_ace_list(file_ace_list);
3076 free_canon_ace_list(dir_ace_list);
3081 if (acl_perms && acl_set_support && fsp->is_directory) {
3083 if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) {
3084 DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
3085 free_canon_ace_list(file_ace_list);
3086 free_canon_ace_list(dir_ace_list);
3092 * No default ACL - delete one if it exists.
3095 if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name) == -1) {
3096 DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
3097 free_canon_ace_list(file_ace_list);
3098 free_canon_ace_list(dir_ace_list);
3104 if (acl_set_support)
3105 store_inheritance_attributes(fsp, file_ace_list, dir_ace_list,
3106 (psd->type & SE_DESC_DACL_PROTECTED) ? True : False);
3109 * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
3112 if(!acl_set_support && acl_perms) {
3115 if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
3116 free_canon_ace_list(file_ace_list);
3117 free_canon_ace_list(dir_ace_list);
3118 DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
3123 if (orig_mode != posix_perms) {
3125 DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
3126 fsp->fsp_name, (unsigned int)posix_perms ));
3128 if(SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms) == -1) {
3129 DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
3130 fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
3131 free_canon_ace_list(file_ace_list);
3132 free_canon_ace_list(dir_ace_list);
3139 free_canon_ace_list(file_ace_list);
3140 free_canon_ace_list(dir_ace_list);
3143 /* Any chown pending? */
3146 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3147 fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
3149 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
3150 DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3151 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
3159 /****************************************************************************
3160 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3161 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3162 ****************************************************************************/
3164 static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mode_t mode)
3166 int entry_id = SMB_ACL_FIRST_ENTRY;
3167 SMB_ACL_ENTRY_T entry;
3168 int num_entries = 0;
3170 while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3171 SMB_ACL_TAG_T tagtype;
3172 SMB_ACL_PERMSET_T permset;
3176 if (entry_id == SMB_ACL_FIRST_ENTRY)
3177 entry_id = SMB_ACL_NEXT_ENTRY;
3179 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
3182 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
3188 case SMB_ACL_USER_OBJ:
3189 perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
3191 case SMB_ACL_GROUP_OBJ:
3192 perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
3196 * FIXME: The ACL_MASK entry permissions should really be set to
3197 * the union of the permissions of all ACL_USER,
3198 * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what
3199 * acl_calc_mask() does, but Samba ACLs doesn't provide it.
3201 perms = S_IRUSR|S_IWUSR|S_IXUSR;
3204 perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
3210 if (map_acl_perms_to_permset(conn, perms, &permset) == -1)
3213 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) == -1)
3218 * If this is a simple 3 element ACL or no elements then it's a standard
3219 * UNIX permission set. Just use chmod...
3222 if ((num_entries == 3) || (num_entries == 0))
3228 /****************************************************************************
3229 Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ,
3230 GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the
3231 resulting ACL on TO. Note that name is in UNIX character set.
3232 ****************************************************************************/
3234 static int copy_access_acl(connection_struct *conn, const char *from, const char *to, mode_t mode)
3236 SMB_ACL_T posix_acl = NULL;
3239 if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL)
3242 if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3245 ret = SMB_VFS_SYS_ACL_SET_FILE(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl);
3249 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3253 /****************************************************************************
3254 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3255 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3256 Note that name is in UNIX character set.
3257 ****************************************************************************/
3259 int chmod_acl(connection_struct *conn, const char *name, mode_t mode)
3261 return copy_access_acl(conn, name, name, mode);
3264 /****************************************************************************
3265 If "inherit permissions" is set and the parent directory has no default
3266 ACL but it does have an Access ACL, inherit this Access ACL to file name.
3267 ****************************************************************************/
3269 int inherit_access_acl(connection_struct *conn, const char *name, mode_t mode)
3272 pstrcpy(dirname, parent_dirname(name));
3274 if (!lp_inherit_perms(SNUM(conn)) || directory_has_default_acl(conn, dirname))
3277 return copy_access_acl(conn, dirname, name, mode);
3280 /****************************************************************************
3281 Do an fchmod 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 ****************************************************************************/
3285 int fchmod_acl(files_struct *fsp, int fd, mode_t mode)
3287 connection_struct *conn = fsp->conn;
3288 SMB_ACL_T posix_acl = NULL;
3291 if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fd)) == NULL)
3294 if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3297 ret = SMB_VFS_SYS_ACL_SET_FD(fsp, fd, posix_acl);
3301 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3305 /****************************************************************************
3306 Check for an existing default POSIX ACL on a directory.
3307 ****************************************************************************/
3309 BOOL directory_has_default_acl(connection_struct *conn, const char *fname)
3311 SMB_ACL_T dir_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT);
3312 BOOL has_acl = False;
3313 SMB_ACL_ENTRY_T entry;
3315 if (dir_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, dir_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1))
3319 SMB_VFS_SYS_ACL_FREE_ACL(conn, dir_acl);