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 PAI_VERSION_OFFSET 0
61 #define PAI_FLAG_OFFSET 1
62 #define PAI_NUM_ENTRIES_OFFSET 2
63 #define PAI_NUM_DEFAULT_ENTRIES_OFFSET 4
64 #define PAI_ENTRIES_BASE 6
67 #define PAI_ACL_FLAG_PROTECTED 0x1
68 #define PAI_ENTRY_LENGTH 5
71 * In memory format of user.SAMBA_PAI attribute.
75 struct pai_entry *next, *prev;
76 enum ace_owner owner_type;
82 unsigned int num_entries;
83 struct pai_entry *entry_list;
84 unsigned int num_def_entries;
85 struct pai_entry *def_entry_list;
88 /************************************************************************
89 Return a uint32 of the pai_entry principal.
90 ************************************************************************/
92 static uint32 get_pai_entry_val(struct pai_entry *paie)
94 switch (paie->owner_type) {
96 DEBUG(10,("get_pai_entry_val: uid = %u\n", (unsigned int)paie->unix_ug.uid ));
97 return (uint32)paie->unix_ug.uid;
99 DEBUG(10,("get_pai_entry_val: gid = %u\n", (unsigned int)paie->unix_ug.gid ));
100 return (uint32)paie->unix_ug.gid;
103 DEBUG(10,("get_pai_entry_val: world ace\n"));
108 /************************************************************************
109 Return a uint32 of the entry principal.
110 ************************************************************************/
112 static uint32 get_entry_val(canon_ace *ace_entry)
114 switch (ace_entry->owner_type) {
116 DEBUG(10,("get_entry_val: uid = %u\n", (unsigned int)ace_entry->unix_ug.uid ));
117 return (uint32)ace_entry->unix_ug.uid;
119 DEBUG(10,("get_entry_val: gid = %u\n", (unsigned int)ace_entry->unix_ug.gid ));
120 return (uint32)ace_entry->unix_ug.gid;
123 DEBUG(10,("get_entry_val: world ace\n"));
128 /************************************************************************
129 Count the inherited entries.
130 ************************************************************************/
132 static unsigned int num_inherited_entries(canon_ace *ace_list)
134 unsigned int num_entries = 0;
136 for (; ace_list; ace_list = ace_list->next)
137 if (ace_list->inherited)
142 /************************************************************************
143 Create the on-disk format. Caller must free.
144 ************************************************************************/
146 static char *create_pai_buf(canon_ace *file_ace_list, canon_ace *dir_ace_list, BOOL protected, size_t *store_size)
148 char *pai_buf = NULL;
149 canon_ace *ace_list = NULL;
150 char *entry_offset = NULL;
151 unsigned int num_entries = 0;
152 unsigned int num_def_entries = 0;
154 for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next)
155 if (ace_list->inherited)
158 for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next)
159 if (ace_list->inherited)
162 DEBUG(10,("create_pai_buf: num_entries = %u, num_def_entries = %u\n", num_entries, num_def_entries ));
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 = %lu for file %s\n", (unsigned long)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) ", (unsigned int)pace->unix_ug.uid, u_name );
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( "(inherited) ");
571 dbgtext( "%c", pace->perms & S_IRUSR ? 'r' : '-');
572 dbgtext( "%c", pace->perms & S_IWUSR ? 'w' : '-');
573 dbgtext( "%c\n", pace->perms & S_IXUSR ? 'x' : '-');
576 /****************************************************************************
577 Print out a canon ace list.
578 ****************************************************************************/
580 static void print_canon_ace_list(const char *name, canon_ace *ace_list)
584 if( DEBUGLVL( 10 )) {
585 dbgtext( "print_canon_ace_list: %s\n", name );
586 for (;ace_list; ace_list = ace_list->next, count++)
587 print_canon_ace(ace_list, count );
591 /****************************************************************************
592 Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
593 ****************************************************************************/
595 static mode_t convert_permset_to_mode_t(connection_struct *conn, SMB_ACL_PERMSET_T permset)
599 ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRUSR : 0);
600 ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
601 ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
606 /****************************************************************************
607 Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
608 ****************************************************************************/
610 static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
624 /****************************************************************************
625 Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to
626 an SMB_ACL_PERMSET_T.
627 ****************************************************************************/
629 static int map_acl_perms_to_permset(connection_struct *conn, mode_t mode, SMB_ACL_PERMSET_T *p_permset)
631 if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) == -1)
633 if (mode & S_IRUSR) {
634 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1)
637 if (mode & S_IWUSR) {
638 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1)
641 if (mode & S_IXUSR) {
642 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1)
647 /****************************************************************************
648 Function to create owner and group SIDs from a SMB_STRUCT_STAT.
649 ****************************************************************************/
651 static void create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
653 uid_to_sid( powner_sid, psbuf->st_uid );
654 gid_to_sid( pgroup_sid, psbuf->st_gid );
657 /****************************************************************************
658 Merge aces with a common sid - if both are allow or deny, OR the permissions together and
659 delete the second one. If the first is deny, mask the permissions off and delete the allow
660 if the permissions become zero, delete the deny if the permissions are non zero.
661 ****************************************************************************/
663 static void merge_aces( canon_ace **pp_list_head )
665 canon_ace *list_head = *pp_list_head;
666 canon_ace *curr_ace_outer;
667 canon_ace *curr_ace_outer_next;
670 * First, merge allow entries with identical SIDs, and deny entries
671 * with identical SIDs.
674 for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
676 canon_ace *curr_ace_next;
678 curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
680 for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
682 curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
684 if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
685 (curr_ace->attr == curr_ace_outer->attr)) {
687 if( DEBUGLVL( 10 )) {
688 dbgtext("merge_aces: Merging ACE's\n");
689 print_canon_ace( curr_ace_outer, 0);
690 print_canon_ace( curr_ace, 0);
693 /* Merge two allow or two deny ACE's. */
695 curr_ace_outer->perms |= curr_ace->perms;
696 DLIST_REMOVE(list_head, curr_ace);
698 curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
704 * Now go through and mask off allow permissions with deny permissions.
705 * We can delete either the allow or deny here as we know that each SID
706 * appears only once in the list.
709 for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
711 canon_ace *curr_ace_next;
713 curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
715 for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
717 curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
720 * Subtract ACE's with different entries. Due to the ordering constraints
721 * we've put on the ACL, we know the deny must be the first one.
724 if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
725 (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
727 if( DEBUGLVL( 10 )) {
728 dbgtext("merge_aces: Masking ACE's\n");
729 print_canon_ace( curr_ace_outer, 0);
730 print_canon_ace( curr_ace, 0);
733 curr_ace->perms &= ~curr_ace_outer->perms;
735 if (curr_ace->perms == 0) {
738 * The deny overrides the allow. Remove the allow.
741 DLIST_REMOVE(list_head, curr_ace);
743 curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
748 * Even after removing permissions, there
749 * are still allow permissions - delete the deny.
750 * It is safe to delete the deny here,
751 * as we are guarenteed by the deny first
752 * ordering that all the deny entries for
753 * this SID have already been merged into one
754 * before we can get to an allow ace.
757 DLIST_REMOVE(list_head, curr_ace_outer);
758 SAFE_FREE(curr_ace_outer);
763 } /* end for curr_ace */
764 } /* end for curr_ace_outer */
766 /* We may have modified the list. */
768 *pp_list_head = list_head;
771 /****************************************************************************
772 Check if we need to return NT4.x compatible ACL entries.
773 ****************************************************************************/
775 static BOOL nt4_compatible_acls(void)
777 const char *compat = lp_acl_compatibility();
779 if (*compat == '\0') {
780 enum remote_arch_types ra_type = get_remote_arch();
782 /* Automatically adapt to client */
783 return (ra_type <= RA_WINNT);
785 return (strequal(compat, "winnt"));
789 /****************************************************************************
790 Map canon_ace perms to permission bits NT.
791 The attr element is not used here - we only process deny entries on set,
792 not get. Deny entries are implicit on get with ace->perms = 0.
793 ****************************************************************************/
795 static SEC_ACCESS map_canon_ace_perms(int *pacl_type, DOM_SID *powner_sid, canon_ace *ace)
800 *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
802 if ((ace->perms & ALL_ACE_PERMS) == ALL_ACE_PERMS) {
803 nt_mask = UNIX_ACCESS_RWX;
804 } else if ((ace->perms & ALL_ACE_PERMS) == (mode_t)0) {
806 * Windows NT refuses to display ACEs with no permissions in them (but
807 * they are perfectly legal with Windows 2000). If the ACE has empty
808 * permissions we cannot use 0, so we use the otherwise unused
809 * WRITE_OWNER permission, which we ignore when we set an ACL.
810 * We abstract this into a #define of UNIX_ACCESS_NONE to allow this
811 * to be changed in the future.
814 if (nt4_compatible_acls())
815 nt_mask = UNIX_ACCESS_NONE;
819 nt_mask |= ((ace->perms & S_IRUSR) ? UNIX_ACCESS_R : 0 );
820 nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
821 nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_ACCESS_X : 0 );
824 DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
825 (unsigned int)ace->perms, (unsigned int)nt_mask ));
827 init_sec_access(&sa,nt_mask);
831 /****************************************************************************
832 Map NT perms to a UNIX mode_t.
833 ****************************************************************************/
835 #define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
836 #define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
837 #define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
839 static mode_t map_nt_perms( SEC_ACCESS sec_access, int type)
845 if(sec_access.mask & GENERIC_ALL_ACCESS)
846 mode = S_IRUSR|S_IWUSR|S_IXUSR;
848 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
849 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
850 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
854 if(sec_access.mask & GENERIC_ALL_ACCESS)
855 mode = S_IRGRP|S_IWGRP|S_IXGRP;
857 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
858 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
859 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
863 if(sec_access.mask & GENERIC_ALL_ACCESS)
864 mode = S_IROTH|S_IWOTH|S_IXOTH;
866 mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
867 mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
868 mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
876 /****************************************************************************
877 Unpack a SEC_DESC into a UNIX owner and group.
878 ****************************************************************************/
880 static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
888 if(security_info_sent == 0) {
889 DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
894 * Validate the owner and group SID's.
897 memset(&owner_sid, '\0', sizeof(owner_sid));
898 memset(&grp_sid, '\0', sizeof(grp_sid));
900 DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
903 * Don't immediately fail if the owner sid cannot be validated.
904 * This may be a group chown only set.
907 if (security_info_sent & OWNER_SECURITY_INFORMATION) {
908 sid_copy(&owner_sid, psd->owner_sid);
909 if (!NT_STATUS_IS_OK(sid_to_uid(&owner_sid, puser))) {
910 #if ACL_FORCE_UNMAPPABLE
911 /* this allows take ownership to work reasonably */
912 extern struct current_user current_user;
913 *puser = current_user.uid;
915 DEBUG(3,("unpack_nt_owners: unable to validate owner sid for %s\n",
916 sid_string_static(&owner_sid)));
923 * Don't immediately fail if the group sid cannot be validated.
924 * This may be an owner chown only set.
927 if (security_info_sent & GROUP_SECURITY_INFORMATION) {
928 sid_copy(&grp_sid, psd->grp_sid);
929 if (!NT_STATUS_IS_OK(sid_to_gid( &grp_sid, pgrp))) {
930 #if ACL_FORCE_UNMAPPABLE
931 /* this allows take group ownership to work reasonably */
932 extern struct current_user current_user;
933 *pgrp = current_user.gid;
935 DEBUG(3,("unpack_nt_owners: unable to validate group sid.\n"));
941 DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
946 /****************************************************************************
947 Ensure the enforced permissions for this share apply.
948 ****************************************************************************/
950 static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type)
952 int snum = SNUM(fsp->conn);
953 mode_t and_bits = (mode_t)0;
954 mode_t or_bits = (mode_t)0;
956 /* Get the initial bits to apply. */
958 if (fsp->is_directory) {
959 and_bits = lp_dir_security_mask(snum);
960 or_bits = lp_force_dir_security_mode(snum);
962 and_bits = lp_security_mask(snum);
963 or_bits = lp_force_security_mode(snum);
966 /* Now bounce them into the S_USR space. */
969 /* Ensure owner has read access. */
970 pace->perms |= S_IRUSR;
971 if (fsp->is_directory)
972 pace->perms |= (S_IWUSR|S_IXUSR);
973 and_bits = unix_perms_to_acl_perms(and_bits, S_IRUSR, S_IWUSR, S_IXUSR);
974 or_bits = unix_perms_to_acl_perms(or_bits, S_IRUSR, S_IWUSR, S_IXUSR);
977 and_bits = unix_perms_to_acl_perms(and_bits, S_IRGRP, S_IWGRP, S_IXGRP);
978 or_bits = unix_perms_to_acl_perms(or_bits, S_IRGRP, S_IWGRP, S_IXGRP);
981 and_bits = unix_perms_to_acl_perms(and_bits, S_IROTH, S_IWOTH, S_IXOTH);
982 or_bits = unix_perms_to_acl_perms(or_bits, S_IROTH, S_IWOTH, S_IXOTH);
986 pace->perms = ((pace->perms & and_bits)|or_bits);
989 /****************************************************************************
990 Check if a given uid/SID is in a group gid/SID. This is probably very
991 expensive and will need optimisation. A *lot* of optimisation :-). JRA.
992 ****************************************************************************/
994 static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
996 extern DOM_SID global_sid_World;
999 extern struct current_user current_user;
1001 /* "Everyone" always matches every uid. */
1003 if (sid_equal(&group_ace->trustee, &global_sid_World))
1006 /* Assume that the current user is in the current group (force group) */
1008 if (uid_ace->unix_ug.uid == current_user.uid && group_ace->unix_ug.gid == current_user.gid)
1011 fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid));
1012 fstrcpy(g_name, gidtoname(group_ace->unix_ug.gid));
1015 * Due to the winbind interfaces we need to do this via names,
1019 return user_in_group_list(u_name, g_name, NULL, 0);
1022 /****************************************************************************
1023 A well formed POSIX file or default ACL has at least 3 entries, a
1024 SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
1025 In addition, the owner must always have at least read access.
1026 When using this call on get_acl, the pst struct is valid and contains
1027 the mode of the file. When using this call on set_acl, the pst struct has
1028 been modified to have a mode containing the default for this file or directory
1030 ****************************************************************************/
1032 static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
1034 DOM_SID *pfile_owner_sid,
1035 DOM_SID *pfile_grp_sid,
1036 SMB_STRUCT_STAT *pst,
1039 extern DOM_SID global_sid_World;
1041 BOOL got_user = False;
1042 BOOL got_grp = False;
1043 BOOL got_other = False;
1044 canon_ace *pace_other = NULL;
1045 canon_ace *pace_group = NULL;
1047 for (pace = *pp_ace; pace; pace = pace->next) {
1048 if (pace->type == SMB_ACL_USER_OBJ) {
1051 apply_default_perms(fsp, pace, S_IRUSR);
1054 } else if (pace->type == SMB_ACL_GROUP_OBJ) {
1057 * Ensure create mask/force create mode is respected on set.
1061 apply_default_perms(fsp, pace, S_IRGRP);
1065 } else if (pace->type == SMB_ACL_OTHER) {
1068 * Ensure create mask/force create mode is respected on set.
1072 apply_default_perms(fsp, pace, S_IROTH);
1079 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
1080 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1085 pace->type = SMB_ACL_USER_OBJ;
1086 pace->owner_type = UID_ACE;
1087 pace->unix_ug.uid = pst->st_uid;
1088 pace->trustee = *pfile_owner_sid;
1089 pace->attr = ALLOW_ACE;
1092 /* If we only got an "everyone" perm, just use that. */
1093 if (!got_grp && got_other)
1094 pace->perms = pace_other->perms;
1095 else if (got_grp && uid_entry_in_group(pace, pace_group))
1096 pace->perms = pace_group->perms;
1100 apply_default_perms(fsp, pace, S_IRUSR);
1102 pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
1105 DLIST_ADD(*pp_ace, pace);
1109 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
1110 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1115 pace->type = SMB_ACL_GROUP_OBJ;
1116 pace->owner_type = GID_ACE;
1117 pace->unix_ug.uid = pst->st_gid;
1118 pace->trustee = *pfile_grp_sid;
1119 pace->attr = ALLOW_ACE;
1121 /* If we only got an "everyone" perm, just use that. */
1123 pace->perms = pace_other->perms;
1126 apply_default_perms(fsp, pace, S_IRGRP);
1128 pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
1131 DLIST_ADD(*pp_ace, pace);
1135 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
1136 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1141 pace->type = SMB_ACL_OTHER;
1142 pace->owner_type = WORLD_ACE;
1143 pace->unix_ug.world = -1;
1144 pace->trustee = global_sid_World;
1145 pace->attr = ALLOW_ACE;
1148 apply_default_perms(fsp, pace, S_IROTH);
1150 pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
1152 DLIST_ADD(*pp_ace, pace);
1158 /****************************************************************************
1159 Check if a POSIX ACL has the required SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries.
1160 If it does not have them, check if there are any entries where the trustee is the
1161 file owner or the owning group, and map these to SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ.
1162 ****************************************************************************/
1164 static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid)
1166 BOOL got_user_obj, got_group_obj;
1167 canon_ace *current_ace;
1170 entries = count_canon_ace_list(ace);
1171 got_user_obj = False;
1172 got_group_obj = False;
1174 for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1175 if (current_ace->type == SMB_ACL_USER_OBJ)
1176 got_user_obj = True;
1177 else if (current_ace->type == SMB_ACL_GROUP_OBJ)
1178 got_group_obj = True;
1180 if (got_user_obj && got_group_obj) {
1181 DEBUG(10,("check_owning_objs: ACL had owning user/group entries.\n"));
1185 for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1186 if (!got_user_obj && current_ace->owner_type == UID_ACE &&
1187 sid_equal(¤t_ace->trustee, pfile_owner_sid)) {
1188 current_ace->type = SMB_ACL_USER_OBJ;
1189 got_user_obj = True;
1191 if (!got_group_obj && current_ace->owner_type == GID_ACE &&
1192 sid_equal(¤t_ace->trustee, pfile_grp_sid)) {
1193 current_ace->type = SMB_ACL_GROUP_OBJ;
1194 got_group_obj = True;
1198 DEBUG(10,("check_owning_objs: ACL is missing an owner entry.\n"));
1200 DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n"));
1203 /****************************************************************************
1204 Unpack a SEC_DESC into two canonical ace lists.
1205 ****************************************************************************/
1207 static BOOL create_canon_ace_lists(files_struct *fsp, SMB_STRUCT_STAT *pst,
1208 DOM_SID *pfile_owner_sid,
1209 DOM_SID *pfile_grp_sid,
1210 canon_ace **ppfile_ace, canon_ace **ppdir_ace,
1213 extern DOM_SID global_sid_Creator_Owner;
1214 extern DOM_SID global_sid_Creator_Group;
1215 extern DOM_SID global_sid_World;
1216 extern struct generic_mapping file_generic_mapping;
1217 BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
1218 canon_ace *file_ace = NULL;
1219 canon_ace *dir_ace = NULL;
1220 canon_ace *tmp_ace = NULL;
1221 canon_ace *current_ace = NULL;
1222 BOOL got_dir_allow = False;
1223 BOOL got_file_allow = False;
1230 * Convert the incoming ACL into a more regular form.
1233 for(i = 0; i < dacl->num_aces; i++) {
1234 SEC_ACE *psa = &dacl->ace[i];
1236 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
1237 DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
1241 if (nt4_compatible_acls()) {
1243 * The security mask may be UNIX_ACCESS_NONE which should map into
1244 * no permissions (we overload the WRITE_OWNER bit for this) or it
1245 * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
1246 * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
1250 * Convert GENERIC bits to specific bits.
1253 se_map_generic(&psa->info.mask, &file_generic_mapping);
1255 psa->info.mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS);
1257 if(psa->info.mask != UNIX_ACCESS_NONE)
1258 psa->info.mask &= ~UNIX_ACCESS_NONE;
1263 * Deal with the fact that NT 4.x re-writes the canonical format
1264 * that we return for default ACLs. If a directory ACE is identical
1265 * to a inherited directory ACE then NT changes the bits so that the
1266 * first ACE is set to OI|IO and the second ACE for this SID is set
1267 * to CI. We need to repair this. JRA.
1270 for(i = 0; i < dacl->num_aces; i++) {
1271 SEC_ACE *psa1 = &dacl->ace[i];
1273 for (j = i + 1; j < dacl->num_aces; j++) {
1274 SEC_ACE *psa2 = &dacl->ace[j];
1276 if (psa1->info.mask != psa2->info.mask)
1279 if (!sid_equal(&psa1->trustee, &psa2->trustee))
1283 * Ok - permission bits and SIDs are equal.
1284 * Check if flags were re-written.
1287 if (psa1->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1289 psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1290 psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1292 } else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1294 psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1295 psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1301 for(i = 0; i < dacl->num_aces; i++) {
1302 SEC_ACE *psa = &dacl->ace[i];
1305 * Ignore non-mappable SIDs (NT Authority, BUILTIN etc).
1308 if (non_mappable_sid(&psa->trustee)) {
1310 DEBUG(10,("create_canon_ace_lists: ignoring non-mappable SID %s\n",
1311 sid_to_string(str, &psa->trustee) ));
1316 * Create a cannon_ace entry representing this NT DACL ACE.
1319 if ((current_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
1320 free_canon_ace_list(file_ace);
1321 free_canon_ace_list(dir_ace);
1322 DEBUG(0,("create_canon_ace_lists: malloc fail.\n"));
1326 ZERO_STRUCTP(current_ace);
1328 sid_copy(¤t_ace->trustee, &psa->trustee);
1331 * Try and work out if the SID is a user or group
1332 * as we need to flag these differently for POSIX.
1333 * Note what kind of a POSIX ACL this should map to.
1336 if( sid_equal(¤t_ace->trustee, &global_sid_World)) {
1337 current_ace->owner_type = WORLD_ACE;
1338 current_ace->unix_ug.world = -1;
1339 current_ace->type = SMB_ACL_OTHER;
1340 } else if (sid_equal(¤t_ace->trustee, &global_sid_Creator_Owner)) {
1341 current_ace->owner_type = UID_ACE;
1342 current_ace->unix_ug.uid = pst->st_uid;
1343 current_ace->type = SMB_ACL_USER_OBJ;
1346 * The Creator Owner entry only specifies inheritable permissions,
1347 * never access permissions. WinNT doesn't always set the ACE to
1348 *INHERIT_ONLY, though.
1351 if (nt4_compatible_acls())
1352 psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1353 } else if (sid_equal(¤t_ace->trustee, &global_sid_Creator_Group)) {
1354 current_ace->owner_type = GID_ACE;
1355 current_ace->unix_ug.gid = pst->st_gid;
1356 current_ace->type = SMB_ACL_GROUP_OBJ;
1359 * The Creator Group entry only specifies inheritable permissions,
1360 * never access permissions. WinNT doesn't always set the ACE to
1361 *INHERIT_ONLY, though.
1363 if (nt4_compatible_acls())
1364 psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1366 } else if (NT_STATUS_IS_OK(sid_to_gid( ¤t_ace->trustee, ¤t_ace->unix_ug.gid))) {
1367 current_ace->owner_type = GID_ACE;
1368 current_ace->type = SMB_ACL_GROUP;
1369 } else if (NT_STATUS_IS_OK(sid_to_uid( ¤t_ace->trustee, ¤t_ace->unix_ug.uid))) {
1370 current_ace->owner_type = UID_ACE;
1371 current_ace->type = SMB_ACL_USER;
1375 free_canon_ace_list(file_ace);
1376 free_canon_ace_list(dir_ace);
1377 DEBUG(0,("create_canon_ace_lists: unable to map SID %s to uid or gid.\n",
1378 sid_to_string(str, ¤t_ace->trustee) ));
1379 SAFE_FREE(current_ace);
1384 * Map the given NT permissions into a UNIX mode_t containing only
1385 * S_I(R|W|X)USR bits.
1388 current_ace->perms |= map_nt_perms( psa->info, S_IRUSR);
1389 current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
1390 current_ace->inherited = ((psa->flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False);
1393 * Now add the created ace to either the file list, the directory
1394 * list, or both. We *MUST* preserve the order here (hence we use
1395 * DLIST_ADD_END) as NT ACLs are order dependent.
1398 if (fsp->is_directory) {
1401 * We can only add to the default POSIX ACE list if the ACE is
1402 * designed to be inherited by both files and directories.
1405 if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
1406 (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
1408 DLIST_ADD_END(dir_ace, current_ace, tmp_ace);
1411 * Note if this was an allow ace. We can't process
1412 * any further deny ace's after this.
1415 if (current_ace->attr == ALLOW_ACE)
1416 got_dir_allow = True;
1418 if ((current_ace->attr == DENY_ACE) && got_dir_allow) {
1419 DEBUG(0,("create_canon_ace_lists: malformed ACL in inheritable ACL ! \
1420 Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
1421 free_canon_ace_list(file_ace);
1422 free_canon_ace_list(dir_ace);
1423 SAFE_FREE(current_ace);
1427 if( DEBUGLVL( 10 )) {
1428 dbgtext("create_canon_ace_lists: adding dir ACL:\n");
1429 print_canon_ace( current_ace, 0);
1433 * If this is not an inherit only ACE we need to add a duplicate
1437 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1438 canon_ace *dup_ace = dup_canon_ace(current_ace);
1441 DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
1442 free_canon_ace_list(file_ace);
1443 free_canon_ace_list(dir_ace);
1448 * We must not free current_ace here as its
1449 * pointer is now owned by the dir_ace list.
1451 current_ace = dup_ace;
1454 * We must not free current_ace here as its
1455 * pointer is now owned by the dir_ace list.
1463 * Only add to the file ACL if not inherit only.
1466 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1467 DLIST_ADD_END(file_ace, current_ace, tmp_ace);
1470 * Note if this was an allow ace. We can't process
1471 * any further deny ace's after this.
1474 if (current_ace->attr == ALLOW_ACE)
1475 got_file_allow = True;
1477 if ((current_ace->attr == DENY_ACE) && got_file_allow) {
1478 DEBUG(0,("create_canon_ace_lists: malformed ACL in file ACL ! \
1479 Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
1480 free_canon_ace_list(file_ace);
1481 free_canon_ace_list(dir_ace);
1482 SAFE_FREE(current_ace);
1486 if( DEBUGLVL( 10 )) {
1487 dbgtext("create_canon_ace_lists: adding file ACL:\n");
1488 print_canon_ace( current_ace, 0);
1490 all_aces_are_inherit_only = False;
1492 * We must not free current_ace here as its
1493 * pointer is now owned by the file_ace list.
1499 * Free if ACE was not added.
1502 SAFE_FREE(current_ace);
1505 if (fsp->is_directory && all_aces_are_inherit_only) {
1507 * Windows 2000 is doing one of these weird 'inherit acl'
1508 * traverses to conserve NTFS ACL resources. Just pretend
1509 * there was no DACL sent. JRA.
1512 DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n"));
1513 free_canon_ace_list(file_ace);
1514 free_canon_ace_list(dir_ace);
1519 * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in each
1520 * ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP
1521 * entries can be converted to *_OBJ. Usually we will already have these
1522 * entries in the Default ACL, and the Access ACL will not have them.
1524 check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);
1525 check_owning_objs(dir_ace, pfile_owner_sid, pfile_grp_sid);
1528 *ppfile_ace = file_ace;
1529 *ppdir_ace = dir_ace;
1534 /****************************************************************************
1535 ASCII art time again... JRA :-).
1537 We have 4 cases to process when moving from an NT ACL to a POSIX ACL. Firstly,
1538 we insist the ACL is in canonical form (ie. all DENY entries preceede ALLOW
1539 entries). Secondly, the merge code has ensured that all duplicate SID entries for
1540 allow or deny have been merged, so the same SID can only appear once in the deny
1541 list or once in the allow list.
1543 We then process as follows :
1545 ---------------------------------------------------------------------------
1546 First pass - look for a Everyone DENY entry.
1548 If it is deny all (rwx) trunate the list at this point.
1549 Else, walk the list from this point and use the deny permissions of this
1550 entry as a mask on all following allow entries. Finally, delete
1551 the Everyone DENY entry (we have applied it to everything possible).
1553 In addition, in this pass we remove any DENY entries that have
1554 no permissions (ie. they are a DENY nothing).
1555 ---------------------------------------------------------------------------
1556 Second pass - only deal with deny user entries.
1558 DENY user1 (perms XXX)
1561 for all following allow group entries where user1 is in group
1562 new_perms |= group_perms;
1564 user1 entry perms = new_perms & ~ XXX;
1566 Convert the deny entry to an allow entry with the new perms and
1567 push to the end of the list. Note if the user was in no groups
1568 this maps to a specific allow nothing entry for this user.
1570 The common case from the NT ACL choser (userX deny all) is
1571 optimised so we don't do the group lookup - we just map to
1572 an allow nothing entry.
1574 What we're doing here is inferring the allow permissions the
1575 person setting the ACE on user1 wanted by looking at the allow
1576 permissions on the groups the user is currently in. This will
1577 be a snapshot, depending on group membership but is the best
1578 we can do and has the advantage of failing closed rather than
1580 ---------------------------------------------------------------------------
1581 Third pass - only deal with deny group entries.
1583 DENY group1 (perms XXX)
1585 for all following allow user entries where user is in group1
1586 user entry perms = user entry perms & ~ XXX;
1588 If there is a group Everyone allow entry with permissions YYY,
1589 convert the group1 entry to an allow entry and modify its
1592 new_perms = YYY & ~ XXX
1594 and push to the end of the list.
1596 If there is no group Everyone allow entry then convert the
1597 group1 entry to a allow nothing entry and push to the end of the list.
1599 Note that the common case from the NT ACL choser (groupX deny all)
1600 cannot be optimised here as we need to modify user entries who are
1601 in the group to change them to a deny all also.
1603 What we're doing here is modifying the allow permissions of
1604 user entries (which are more specific in POSIX ACLs) to mask
1605 out the explicit deny set on the group they are in. This will
1606 be a snapshot depending on current group membership but is the
1607 best we can do and has the advantage of failing closed rather
1609 ---------------------------------------------------------------------------
1610 Fourth pass - cope with cumulative permissions.
1612 for all allow user entries, if there exists an allow group entry with
1613 more permissive permissions, and the user is in that group, rewrite the
1614 allow user permissions to contain both sets of permissions.
1616 Currently the code for this is #ifdef'ed out as these semantics make
1617 no sense to me. JRA.
1618 ---------------------------------------------------------------------------
1620 Note we *MUST* do the deny user pass first as this will convert deny user
1621 entries into allow user entries which can then be processed by the deny
1624 The above algorithm took a *lot* of thinking about - hence this
1625 explaination :-). JRA.
1626 ****************************************************************************/
1628 /****************************************************************************
1629 Process a canon_ace list entries. This is very complex code. We need
1630 to go through and remove the "deny" permissions from any allow entry that matches
1631 the id of this entry. We have already refused any NT ACL that wasn't in correct
1632 order (DENY followed by ALLOW). If any allow entry ends up with zero permissions,
1633 we just remove it (to fail safe). We have already removed any duplicate ace
1634 entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all
1636 ****************************************************************************/
1638 static void process_deny_list( canon_ace **pp_ace_list )
1640 extern DOM_SID global_sid_World;
1641 canon_ace *ace_list = *pp_ace_list;
1642 canon_ace *curr_ace = NULL;
1643 canon_ace *curr_ace_next = NULL;
1645 /* Pass 1 above - look for an Everyone, deny entry. */
1647 for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1648 canon_ace *allow_ace_p;
1650 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1652 if (curr_ace->attr != DENY_ACE)
1655 if (curr_ace->perms == (mode_t)0) {
1657 /* Deny nothing entry - delete. */
1659 DLIST_REMOVE(ace_list, curr_ace);
1663 if (!sid_equal(&curr_ace->trustee, &global_sid_World))
1666 /* JRATEST - assert. */
1667 SMB_ASSERT(curr_ace->owner_type == WORLD_ACE);
1669 if (curr_ace->perms == ALL_ACE_PERMS) {
1672 * Optimisation. This is a DENY_ALL to Everyone. Truncate the
1673 * list at this point including this entry.
1676 canon_ace *prev_entry = curr_ace->prev;
1678 free_canon_ace_list( curr_ace );
1680 prev_entry->next = NULL;
1682 /* We deleted the entire list. */
1688 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1691 * Only mask off allow entries.
1694 if (allow_ace_p->attr != ALLOW_ACE)
1697 allow_ace_p->perms &= ~curr_ace->perms;
1701 * Now it's been applied, remove it.
1704 DLIST_REMOVE(ace_list, curr_ace);
1707 /* Pass 2 above - deal with deny user entries. */
1709 for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1710 mode_t new_perms = (mode_t)0;
1711 canon_ace *allow_ace_p;
1714 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1716 if (curr_ace->attr != DENY_ACE)
1719 if (curr_ace->owner_type != UID_ACE)
1722 if (curr_ace->perms == ALL_ACE_PERMS) {
1725 * Optimisation - this is a deny everything to this user.
1726 * Convert to an allow nothing and push to the end of the list.
1729 curr_ace->attr = ALLOW_ACE;
1730 curr_ace->perms = (mode_t)0;
1731 DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1735 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1737 if (allow_ace_p->attr != ALLOW_ACE)
1740 /* We process GID_ACE and WORLD_ACE entries only. */
1742 if (allow_ace_p->owner_type == UID_ACE)
1745 if (uid_entry_in_group( curr_ace, allow_ace_p))
1746 new_perms |= allow_ace_p->perms;
1750 * Convert to a allow entry, modify the perms and push to the end
1754 curr_ace->attr = ALLOW_ACE;
1755 curr_ace->perms = (new_perms & ~curr_ace->perms);
1756 DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1759 /* Pass 3 above - deal with deny group entries. */
1761 for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1763 canon_ace *allow_ace_p;
1764 canon_ace *allow_everyone_p = NULL;
1766 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1768 if (curr_ace->attr != DENY_ACE)
1771 if (curr_ace->owner_type != GID_ACE)
1774 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1776 if (allow_ace_p->attr != ALLOW_ACE)
1779 /* Store a pointer to the Everyone allow, if it exists. */
1780 if (allow_ace_p->owner_type == WORLD_ACE)
1781 allow_everyone_p = allow_ace_p;
1783 /* We process UID_ACE entries only. */
1785 if (allow_ace_p->owner_type != UID_ACE)
1788 /* Mask off the deny group perms. */
1790 if (uid_entry_in_group( allow_ace_p, curr_ace))
1791 allow_ace_p->perms &= ~curr_ace->perms;
1795 * Convert the deny to an allow with the correct perms and
1796 * push to the end of the list.
1799 curr_ace->attr = ALLOW_ACE;
1800 if (allow_everyone_p)
1801 curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms;
1803 curr_ace->perms = (mode_t)0;
1804 DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1808 /* Doing this fourth pass allows Windows semantics to be layered
1809 * on top of POSIX semantics. I'm not sure if this is desirable.
1810 * For example, in W2K ACLs there is no way to say, "Group X no
1811 * access, user Y full access" if user Y is a member of group X.
1812 * This seems completely broken semantics to me.... JRA.
1816 /* Pass 4 above - deal with allow entries. */
1818 for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1819 canon_ace *allow_ace_p;
1821 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1823 if (curr_ace->attr != ALLOW_ACE)
1826 if (curr_ace->owner_type != UID_ACE)
1829 for (allow_ace_p = ace_list; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1831 if (allow_ace_p->attr != ALLOW_ACE)
1834 /* We process GID_ACE entries only. */
1836 if (allow_ace_p->owner_type != GID_ACE)
1839 /* OR in the group perms. */
1841 if (uid_entry_in_group( curr_ace, allow_ace_p))
1842 curr_ace->perms |= allow_ace_p->perms;
1847 *pp_ace_list = ace_list;
1850 /****************************************************************************
1851 Create a default mode that will be used if a security descriptor entry has
1852 no user/group/world entries.
1853 ****************************************************************************/
1855 static mode_t create_default_mode(files_struct *fsp, BOOL interitable_mode)
1857 int snum = SNUM(fsp->conn);
1858 mode_t and_bits = (mode_t)0;
1859 mode_t or_bits = (mode_t)0;
1860 mode_t mode = interitable_mode ? unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name) : S_IRUSR;
1862 if (fsp->is_directory)
1863 mode |= (S_IWUSR|S_IXUSR);
1866 * Now AND with the create mode/directory mode bits then OR with the
1867 * force create mode/force directory mode bits.
1870 if (fsp->is_directory) {
1871 and_bits = lp_dir_security_mask(snum);
1872 or_bits = lp_force_dir_security_mode(snum);
1874 and_bits = lp_security_mask(snum);
1875 or_bits = lp_force_security_mode(snum);
1878 return ((mode & and_bits)|or_bits);
1881 /****************************************************************************
1882 Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
1884 ****************************************************************************/
1886 static BOOL unpack_canon_ace(files_struct *fsp,
1887 SMB_STRUCT_STAT *pst,
1888 DOM_SID *pfile_owner_sid,
1889 DOM_SID *pfile_grp_sid,
1890 canon_ace **ppfile_ace, canon_ace **ppdir_ace,
1891 uint32 security_info_sent, SEC_DESC *psd)
1893 canon_ace *file_ace = NULL;
1894 canon_ace *dir_ace = NULL;
1899 if(security_info_sent == 0) {
1900 DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
1905 * If no DACL then this is a chown only security descriptor.
1908 if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !psd->dacl)
1912 * Now go through the DACL and create the canon_ace lists.
1915 if (!create_canon_ace_lists( fsp, pst, pfile_owner_sid, pfile_grp_sid,
1916 &file_ace, &dir_ace, psd->dacl))
1919 if ((file_ace == NULL) && (dir_ace == NULL)) {
1920 /* W2K traverse DACL set - ignore. */
1925 * Go through the canon_ace list and merge entries
1926 * belonging to identical users of identical allow or deny type.
1927 * We can do this as all deny entries come first, followed by
1928 * all allow entries (we have mandated this before accepting this acl).
1931 print_canon_ace_list( "file ace - before merge", file_ace);
1932 merge_aces( &file_ace );
1934 print_canon_ace_list( "dir ace - before merge", dir_ace);
1935 merge_aces( &dir_ace );
1938 * NT ACLs are order dependent. Go through the acl lists and
1939 * process DENY entries by masking the allow entries.
1942 print_canon_ace_list( "file ace - before deny", file_ace);
1943 process_deny_list( &file_ace);
1945 print_canon_ace_list( "dir ace - before deny", dir_ace);
1946 process_deny_list( &dir_ace);
1949 * A well formed POSIX file or default ACL has at least 3 entries, a
1950 * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
1951 * and optionally a mask entry. Ensure this is the case.
1954 print_canon_ace_list( "file ace - before valid", file_ace);
1957 * A default 3 element mode entry for a file should be r-- --- ---.
1958 * A default 3 element mode entry for a directory should be rwx --- ---.
1961 pst->st_mode = create_default_mode(fsp, False);
1963 if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
1964 free_canon_ace_list(file_ace);
1965 free_canon_ace_list(dir_ace);
1969 print_canon_ace_list( "dir ace - before valid", dir_ace);
1972 * A default inheritable 3 element mode entry for a directory should be the
1973 * mode Samba will use to create a file within. Ensure user rwx bits are set if
1977 pst->st_mode = create_default_mode(fsp, True);
1979 if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
1980 free_canon_ace_list(file_ace);
1981 free_canon_ace_list(dir_ace);
1985 print_canon_ace_list( "file ace - return", file_ace);
1986 print_canon_ace_list( "dir ace - return", dir_ace);
1988 *ppfile_ace = file_ace;
1989 *ppdir_ace = dir_ace;
1994 /******************************************************************************
1995 When returning permissions, try and fit NT display
1996 semantics if possible. Note the the canon_entries here must have been malloced.
1997 The list format should be - first entry = owner, followed by group and other user
1998 entries, last entry = other.
2000 Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries
2001 are not ordered, and match on the most specific entry rather than walking a list,
2002 then a simple POSIX permission of rw-r--r-- should really map to 5 entries,
2004 Entry 0: owner : deny all except read and write.
2005 Entry 1: group : deny all except read.
2006 Entry 2: owner : allow read and write.
2007 Entry 3: group : allow read.
2008 Entry 4: Everyone : allow read.
2010 But NT cannot display this in their ACL editor !
2011 ********************************************************************************/
2013 static void arrange_posix_perms( char *filename, canon_ace **pp_list_head)
2015 canon_ace *list_head = *pp_list_head;
2016 canon_ace *owner_ace = NULL;
2017 canon_ace *other_ace = NULL;
2018 canon_ace *ace = NULL;
2020 for (ace = list_head; ace; ace = ace->next) {
2021 if (ace->type == SMB_ACL_USER_OBJ)
2023 else if (ace->type == SMB_ACL_OTHER) {
2024 /* Last ace - this is "other" */
2029 if (!owner_ace || !other_ace) {
2030 DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n",
2036 * The POSIX algorithm applies to owner first, and other last,
2037 * so ensure they are arranged in this order.
2041 DLIST_PROMOTE(list_head, owner_ace);
2045 DLIST_DEMOTE(list_head, other_ace, ace);
2048 /* We have probably changed the head of the list. */
2050 *pp_list_head = list_head;
2053 /****************************************************************************
2054 Create a linked list of canonical ACE entries.
2055 ****************************************************************************/
2057 static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf,
2058 DOM_SID *powner, DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type)
2060 extern DOM_SID global_sid_World;
2061 connection_struct *conn = fsp->conn;
2062 mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
2063 canon_ace *list_head = NULL;
2064 canon_ace *ace = NULL;
2065 canon_ace *next_ace = NULL;
2066 int entry_id = SMB_ACL_FIRST_ENTRY;
2067 SMB_ACL_ENTRY_T entry;
2070 while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
2071 SMB_ACL_TAG_T tagtype;
2072 SMB_ACL_PERMSET_T permset;
2075 enum ace_owner owner_type;
2078 if (entry_id == SMB_ACL_FIRST_ENTRY)
2079 entry_id = SMB_ACL_NEXT_ENTRY;
2081 /* Is this a MASK entry ? */
2082 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
2085 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
2088 /* Decide which SID to use based on the ACL type. */
2090 case SMB_ACL_USER_OBJ:
2091 /* Get the SID from the owner. */
2092 sid_copy(&sid, powner);
2093 unix_ug.uid = psbuf->st_uid;
2094 owner_type = UID_ACE;
2098 uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
2100 DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
2104 * A SMB_ACL_USER entry for the owner is shadowed by the
2105 * SMB_ACL_USER_OBJ entry and Windows also cannot represent
2106 * that entry, so we ignore it. We also don't create such
2107 * entries out of the blue when setting ACLs, so a get/set
2108 * cycle will drop them.
2110 if (the_acl_type == SMB_ACL_TYPE_ACCESS && *puid == psbuf->st_uid)
2112 uid_to_sid( &sid, *puid);
2113 unix_ug.uid = *puid;
2114 owner_type = UID_ACE;
2115 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
2118 case SMB_ACL_GROUP_OBJ:
2119 /* Get the SID from the owning group. */
2120 sid_copy(&sid, pgroup);
2121 unix_ug.gid = psbuf->st_gid;
2122 owner_type = GID_ACE;
2126 gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
2128 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
2131 gid_to_sid( &sid, *pgid);
2132 unix_ug.gid = *pgid;
2133 owner_type = GID_ACE;
2134 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
2138 acl_mask = convert_permset_to_mode_t(conn, permset);
2139 continue; /* Don't count the mask as an entry. */
2141 /* Use the Everyone SID */
2142 sid = global_sid_World;
2144 owner_type = WORLD_ACE;
2147 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
2152 * Add this entry to the list.
2155 if ((ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
2159 ace->type = tagtype;
2160 ace->perms = convert_permset_to_mode_t(conn, permset);
2161 ace->attr = ALLOW_ACE;
2163 ace->unix_ug = unix_ug;
2164 ace->owner_type = owner_type;
2165 ace->inherited = get_inherited_flag(pal, ace, (the_acl_type == SMB_ACL_TYPE_DEFAULT));
2167 DLIST_ADD(list_head, ace);
2171 * This next call will ensure we have at least a user/group/world set.
2174 if (!ensure_canon_entry_valid(&list_head, fsp, powner, pgroup, psbuf, False))
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: %s ace entries before arrange :\n", the_acl_type == SMB_ACL_TYPE_ACCESS ? "Access" : "Default" ));
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 arrange_posix_perms(fsp->fsp_name,&list_head );
2202 print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head );
2208 free_canon_ace_list(list_head);
2212 /****************************************************************************
2213 Attempt to apply an ACL to a file or directory.
2214 ****************************************************************************/
2216 static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, BOOL *pacl_set_support)
2218 connection_struct *conn = fsp->conn;
2220 SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, (int)count_canon_ace_list(the_ace) + 1);
2223 SMB_ACL_ENTRY_T mask_entry;
2224 BOOL got_mask_entry = False;
2225 SMB_ACL_PERMSET_T mask_permset;
2226 SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
2227 BOOL needs_mask = False;
2228 mode_t mask_perms = 0;
2230 #if defined(POSIX_ACL_NEEDS_MASK)
2231 /* HP-UX always wants to have a mask (called "class" there). */
2235 if (the_acl == NULL) {
2237 if (errno != ENOSYS) {
2239 * Only print this error message if we have some kind of ACL
2240 * support that's not working. Otherwise we would always get this.
2242 DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
2243 default_ace ? "default" : "file", strerror(errno) ));
2245 *pacl_set_support = False;
2249 if( DEBUGLVL( 10 )) {
2250 dbgtext("set_canon_ace_list: setting ACL:\n");
2251 for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2252 print_canon_ace( p_ace, i);
2256 for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2257 SMB_ACL_ENTRY_T the_entry;
2258 SMB_ACL_PERMSET_T the_permset;
2261 * ACLs only "need" an ACL_MASK entry if there are any named user or
2262 * named group entries. But if there is an ACL_MASK entry, it applies
2263 * to ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. Set the mask
2264 * so that it doesn't deny (i.e., mask off) any permissions.
2267 if (p_ace->type == SMB_ACL_USER || p_ace->type == SMB_ACL_GROUP) {
2269 mask_perms |= p_ace->perms;
2270 } else if (p_ace->type == SMB_ACL_GROUP_OBJ) {
2271 mask_perms |= p_ace->perms;
2275 * Get the entry for this ACE.
2278 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
2279 DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
2280 i, strerror(errno) ));
2284 if (p_ace->type == SMB_ACL_MASK) {
2285 mask_entry = the_entry;
2286 got_mask_entry = True;
2290 * Ok - we now know the ACL calls should be working, don't
2291 * allow fallback to chmod.
2294 *pacl_set_support = True;
2297 * Initialise the entry from the canon_ace.
2301 * First tell the entry what type of ACE this is.
2304 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, p_ace->type) == -1) {
2305 DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
2306 i, strerror(errno) ));
2311 * Only set the qualifier (user or group id) if the entry is a user
2315 if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
2316 if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
2317 DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
2318 i, strerror(errno) ));
2324 * Convert the mode_t perms in the canon_ace to a POSIX permset.
2327 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
2328 DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
2329 i, strerror(errno) ));
2333 if (map_acl_perms_to_permset(conn, p_ace->perms, &the_permset) == -1) {
2334 DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
2335 (unsigned int)p_ace->perms, i, strerror(errno) ));
2340 * ..and apply them to the entry.
2343 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
2344 DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
2345 i, strerror(errno) ));
2350 print_canon_ace( p_ace, i);
2354 if (needs_mask && !got_mask_entry) {
2355 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &mask_entry) == -1) {
2356 DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
2360 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, mask_entry, SMB_ACL_MASK) == -1) {
2361 DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
2365 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, mask_entry, &mask_permset) == -1) {
2366 DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
2370 if (map_acl_perms_to_permset(conn, S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
2371 DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
2375 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, mask_entry, mask_permset) == -1) {
2376 DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
2382 * Check if the ACL is valid.
2385 if (SMB_VFS_SYS_ACL_VALID(conn, the_acl) == -1) {
2386 DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n",
2387 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
2393 * Finally apply it to the file or directory.
2396 if(default_ace || fsp->is_directory || fsp->fd == -1) {
2397 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl) == -1) {
2399 * Some systems allow all the above calls and only fail with no ACL support
2400 * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2402 if (errno == ENOSYS)
2403 *pacl_set_support = False;
2406 if (errno == ENOTSUP)
2407 *pacl_set_support = False;
2410 DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
2411 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
2412 fsp->fsp_name, strerror(errno) ));
2416 if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fd, the_acl) == -1) {
2418 * Some systems allow all the above calls and only fail with no ACL support
2419 * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2421 if (errno == ENOSYS)
2422 *pacl_set_support = False;
2425 if (errno == ENOTSUP)
2426 *pacl_set_support = False;
2429 DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
2430 fsp->fsp_name, strerror(errno) ));
2439 if (the_acl != NULL)
2440 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2445 /****************************************************************************
2446 Find a particular canon_ace entry.
2447 ****************************************************************************/
2449 static struct canon_ace *canon_ace_entry_for(struct canon_ace *list, SMB_ACL_TAG_T type, posix_id *id)
2452 if (list->type == type && ((type != SMB_ACL_USER && type != SMB_ACL_GROUP) ||
2453 (type == SMB_ACL_USER && id && id->uid == list->unix_ug.uid) ||
2454 (type == SMB_ACL_GROUP && id && id->gid == list->unix_ug.gid)))
2461 /****************************************************************************
2463 ****************************************************************************/
2465 SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl)
2467 SMB_ACL_ENTRY_T entry;
2471 if (SMB_VFS_SYS_ACL_GET_ENTRY(conn, the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
2472 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2478 /****************************************************************************
2479 Convert a canon_ace to a generic 3 element permission - if possible.
2480 ****************************************************************************/
2482 #define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
2484 static BOOL convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
2486 int snum = SNUM(fsp->conn);
2487 size_t ace_count = count_canon_ace_list(file_ace_list);
2489 canon_ace *owner_ace = NULL;
2490 canon_ace *group_ace = NULL;
2491 canon_ace *other_ace = NULL;
2495 if (ace_count != 3) {
2496 DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \
2497 posix perms.\n", fsp->fsp_name ));
2501 for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
2502 if (ace_p->owner_type == UID_ACE)
2504 else if (ace_p->owner_type == GID_ACE)
2506 else if (ace_p->owner_type == WORLD_ACE)
2510 if (!owner_ace || !group_ace || !other_ace) {
2511 DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n",
2516 *posix_perms = (mode_t)0;
2518 *posix_perms |= owner_ace->perms;
2519 *posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP);
2520 *posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP);
2521 *posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP);
2522 *posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH);
2523 *posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH);
2524 *posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH);
2526 /* The owner must have at least read access. */
2528 *posix_perms |= S_IRUSR;
2529 if (fsp->is_directory)
2530 *posix_perms |= (S_IWUSR|S_IXUSR);
2532 /* If requested apply the masks. */
2534 /* Get the initial bits to apply. */
2536 if (fsp->is_directory) {
2537 and_bits = lp_dir_security_mask(snum);
2538 or_bits = lp_force_dir_security_mode(snum);
2540 and_bits = lp_security_mask(snum);
2541 or_bits = lp_force_security_mode(snum);
2544 *posix_perms = (((*posix_perms) & and_bits)|or_bits);
2546 DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n",
2547 (int)owner_ace->perms, (int)group_ace->perms, (int)other_ace->perms, (int)*posix_perms,
2553 /****************************************************************************
2554 Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and
2555 a normal POSIX acl. Win2k needs these split acls re-merging into one ACL
2556 with CI|OI set so it is inherited and also applies to the directory.
2557 Based on code from "Jim McDonough" <jmcd@us.ibm.com>.
2558 ****************************************************************************/
2560 static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
2564 for (i = 0; i < num_aces; i++) {
2565 for (j = i+1; j < num_aces; j++) {
2566 uint32 i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
2567 uint32 j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
2568 BOOL i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
2569 BOOL j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
2571 /* We know the lower number ACE's are file entries. */
2572 if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
2573 (nt_ace_list[i].size == nt_ace_list[j].size) &&
2574 (nt_ace_list[i].info.mask == nt_ace_list[j].info.mask) &&
2575 sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
2577 (i_flags_ni == 0) &&
2578 (j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT|
2579 SEC_ACE_FLAG_CONTAINER_INHERIT|
2580 SEC_ACE_FLAG_INHERIT_ONLY))) {
2582 * W2K wants to have access allowed zero access ACE's
2583 * at the end of the list. If the mask is zero, merge
2584 * the non-inherited ACE onto the inherited ACE.
2587 if (nt_ace_list[i].info.mask == 0) {
2588 nt_ace_list[j].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2589 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2590 if (num_aces - i - 1 > 0)
2591 memmove(&nt_ace_list[i], &nt_ace_list[i+1], (num_aces-i-1) *
2594 DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n",
2595 (unsigned int)i, (unsigned int)j ));
2598 * These are identical except for the flags.
2599 * Merge the inherited ACE onto the non-inherited ACE.
2602 nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2603 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2604 if (num_aces - j - 1 > 0)
2605 memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) *
2608 DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n",
2609 (unsigned int)j, (unsigned int)i ));
2619 /****************************************************************************
2620 Reply to query a security descriptor from an fsp. If it succeeds it allocates
2621 the space for the return elements and returns the size needed to return the
2622 security descriptor. This should be the only external function needed for
2623 the UNIX style get ACL.
2624 ****************************************************************************/
2626 size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
2628 extern DOM_SID global_sid_Builtin_Administrators;
2629 extern DOM_SID global_sid_Builtin_Users;
2630 extern DOM_SID global_sid_Creator_Owner;
2631 extern DOM_SID global_sid_Creator_Group;
2632 connection_struct *conn = fsp->conn;
2633 SMB_STRUCT_STAT sbuf;
2634 SEC_ACE *nt_ace_list = NULL;
2638 SEC_ACL *psa = NULL;
2639 size_t num_acls = 0;
2640 size_t num_dir_acls = 0;
2641 size_t num_aces = 0;
2642 SMB_ACL_T posix_acl = NULL;
2643 SMB_ACL_T dir_acl = NULL;
2644 canon_ace *file_ace = NULL;
2645 canon_ace *dir_ace = NULL;
2646 size_t num_profile_acls = 0;
2647 struct pai_val *pal = NULL;
2648 SEC_DESC *psd = NULL;
2652 DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name ));
2654 if(fsp->is_directory || fsp->fd == -1) {
2656 /* Get the stat struct for the owner info. */
2657 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
2661 * Get the ACL from the path.
2664 posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
2667 * If it's a directory get the default POSIX ACL.
2670 if(fsp->is_directory) {
2671 dir_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
2672 dir_acl = free_empty_sys_acl(conn, dir_acl);
2677 /* Get the stat struct for the owner info. */
2678 if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) {
2682 * Get the ACL from the fd.
2684 posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd);
2687 DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
2688 posix_acl ? "present" : "absent",
2689 dir_acl ? "present" : "absent" ));
2691 pal = load_inherited_info(fsp);
2694 * Get the owner, group and world SIDs.
2697 if (lp_profile_acls(SNUM(fsp->conn))) {
2698 /* For WXP SP1 the owner must be administrators. */
2699 sid_copy(&owner_sid, &global_sid_Builtin_Administrators);
2700 sid_copy(&group_sid, &global_sid_Builtin_Users);
2701 num_profile_acls = 2;
2703 create_file_sids(&sbuf, &owner_sid, &group_sid);
2706 if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) {
2709 * In the optimum case Creator Owner and Creator Group would be used for
2710 * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this
2711 * would lead to usability problems under Windows: The Creator entries
2712 * are only available in browse lists of directories and not for files;
2713 * additionally the identity of the owning group couldn't be determined.
2714 * We therefore use those identities only for Default ACLs.
2717 /* Create the canon_ace lists. */
2718 file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid, pal, SMB_ACL_TYPE_ACCESS );
2720 /* We must have *some* ACLS. */
2722 if (count_canon_ace_list(file_ace) == 0) {
2723 DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name ));
2727 if (fsp->is_directory && dir_acl) {
2728 dir_ace = canonicalise_acl(fsp, dir_acl, &sbuf,
2729 &global_sid_Creator_Owner,
2730 &global_sid_Creator_Group, pal, SMB_ACL_TYPE_DEFAULT );
2734 * Create the NT ACE list from the canonical ace lists.
2742 if (nt4_compatible_acls() && dir_ace) {
2744 * NT 4 chokes if an ACL contains an INHERIT_ONLY entry
2745 * but no non-INHERIT_ONLY entry for one SID. So we only
2746 * remove entries from the Access ACL if the
2747 * corresponding Default ACL entries have also been
2748 * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP
2749 * are exceptions. We can do nothing
2750 * intelligent if the Default ACL contains entries that
2751 * are not also contained in the Access ACL, so this
2752 * case will still fail under NT 4.
2755 ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL);
2756 if (ace && !ace->perms) {
2757 DLIST_REMOVE(dir_ace, ace);
2760 ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL);
2761 if (ace && !ace->perms) {
2762 DLIST_REMOVE(file_ace, ace);
2768 * WinNT doesn't usually have Creator Group
2769 * in browse lists, so we send this entry to
2770 * WinNT even if it contains no relevant
2771 * permissions. Once we can add
2772 * Creator Group to browse lists we can
2777 ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL);
2778 if (ace && !ace->perms) {
2779 DLIST_REMOVE(dir_ace, ace);
2784 ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL);
2785 if (ace && !ace->perms) {
2786 DLIST_REMOVE(file_ace, ace);
2791 num_acls = count_canon_ace_list(file_ace);
2792 num_dir_acls = count_canon_ace_list(dir_ace);
2794 /* Allocate the ace list. */
2795 if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_profile_acls + num_dir_acls)* sizeof(SEC_ACE))) == NULL) {
2796 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
2800 memset(nt_ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) );
2803 * Create the NT ACE list from the canonical ace lists.
2808 for (i = 0; i < num_acls; i++, ace = ace->next) {
2811 acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
2812 init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2815 /* The User must have access to a profile share - even if we can't map the SID. */
2816 if (lp_profile_acls(SNUM(fsp->conn))) {
2819 init_sec_access(&acc,FILE_GENERIC_ALL);
2820 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED,
2826 for (i = 0; i < num_dir_acls; i++, ace = ace->next) {
2829 acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
2830 init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc,
2831 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2832 SEC_ACE_FLAG_INHERIT_ONLY|
2833 (ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0));
2836 /* The User must have access to a profile share - even if we can't map the SID. */
2837 if (lp_profile_acls(SNUM(fsp->conn))) {
2840 init_sec_access(&acc,FILE_GENERIC_ALL);
2841 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc,
2842 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2843 SEC_ACE_FLAG_INHERIT_ONLY|0);
2847 * Merge POSIX default ACLs and normal ACLs into one NT ACE.
2848 * Win2K needs this to get the inheritance correct when replacing ACLs
2849 * on a directory tree. Based on work by Jim @ IBM.
2852 num_aces = merge_default_aces(nt_ace_list, num_aces);
2857 if((psa = make_sec_acl( main_loop_talloc_get(), ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
2858 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
2862 } /* security_info & DACL_SECURITY_INFORMATION */
2864 psd = make_standard_sec_desc( main_loop_talloc_get(),
2865 (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL,
2866 (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL,
2871 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
2875 * Windows 2000: The DACL_PROTECTED flag in the security
2876 * descriptor marks the ACL as non-inheriting, i.e., no
2877 * ACEs from higher level directories propagate to this
2878 * ACL. In the POSIX ACL model permissions are only
2879 * inherited at file create time, so ACLs never contain
2880 * any ACEs that are inherited dynamically. The DACL_PROTECTED
2881 * flag doesn't seem to bother Windows NT.
2883 if (get_protected_flag(pal))
2884 psd->type |= SE_DESC_DACL_PROTECTED;
2888 dacl_sort_into_canonical_order(psd->dacl->ace, (unsigned int)psd->dacl->num_aces);
2895 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
2897 SMB_VFS_SYS_ACL_FREE_ACL(conn, dir_acl);
2898 free_canon_ace_list(file_ace);
2899 free_canon_ace_list(dir_ace);
2900 free_inherited_info(pal);
2901 SAFE_FREE(nt_ace_list);
2906 /****************************************************************************
2907 Try to chown a file. We will be able to chown it under the following conditions.
2909 1) If we have root privileges, then it will just work.
2910 2) If we have write permission to the file and dos_filemodes is set
2911 then allow chown to the currently authenticated user.
2912 ****************************************************************************/
2914 static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
2917 extern struct current_user current_user;
2921 /* try the direct way first */
2922 ret = SMB_VFS_CHOWN(conn, fname, uid, gid);
2926 if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
2929 if (SMB_VFS_STAT(conn,fname,&st))
2932 fsp = open_file_fchmod(conn,fname,&st);
2936 /* only allow chown to the current user. This is more secure,
2937 and also copes with the case where the SID in a take ownership ACL is
2938 a local SID on the users workstation
2940 uid = current_user.uid;
2943 /* Keep the current file gid the same. */
2944 ret = SMB_VFS_FCHOWN(fsp, fsp->fd, uid, (gid_t)-1);
2947 close_file_fchmod(fsp);
2952 /****************************************************************************
2953 Reply to set a security descriptor on an fsp. security_info_sent is the
2954 description of the following NT ACL.
2955 This should be the only external function needed for the UNIX style set ACL.
2956 ****************************************************************************/
2958 BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
2960 connection_struct *conn = fsp->conn;
2961 uid_t user = (uid_t)-1;
2962 gid_t grp = (gid_t)-1;
2963 SMB_STRUCT_STAT sbuf;
2964 DOM_SID file_owner_sid;
2965 DOM_SID file_grp_sid;
2966 canon_ace *file_ace_list = NULL;
2967 canon_ace *dir_ace_list = NULL;
2968 BOOL acl_perms = False;
2969 mode_t orig_mode = (mode_t)0;
2972 BOOL need_chown = False;
2973 extern struct current_user current_user;
2975 DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
2977 if (!CAN_WRITE(conn)) {
2978 DEBUG(10,("set acl rejected on read-only share\n"));
2983 * Get the current state of the file.
2986 if(fsp->is_directory || fsp->fd == -1) {
2987 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0)
2990 if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0)
2994 /* Save the original elements we check against. */
2995 orig_mode = sbuf.st_mode;
2996 orig_uid = sbuf.st_uid;
2997 orig_gid = sbuf.st_gid;
3000 * Unpack the user/group/world id's.
3003 if (!unpack_nt_owners( &sbuf, &user, &grp, security_info_sent, psd))
3007 * Do we need to chown ?
3010 if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp)))
3014 * Chown before setting ACL only if we don't change the user, or
3015 * if we change to the current user, but not if we want to give away
3019 if (need_chown && (user == (uid_t)-1 || user == current_user.uid)) {
3021 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3022 fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
3024 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
3025 DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3026 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
3031 * Recheck the current state of the file, which may have changed.
3032 * (suid/sgid bits, for instance)
3035 if(fsp->is_directory) {
3036 if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
3044 ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf);
3046 ret = SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf);
3052 /* Save the original elements we check against. */
3053 orig_mode = sbuf.st_mode;
3054 orig_uid = sbuf.st_uid;
3055 orig_gid = sbuf.st_gid;
3057 /* We did it, don't try again */
3061 create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
3063 acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
3064 &file_ace_list, &dir_ace_list, security_info_sent, psd);
3066 /* Ignore W2K traverse DACL set. */
3067 if (file_ace_list || dir_ace_list) {
3070 DEBUG(3,("set_nt_acl: cannot set permissions\n"));
3071 free_canon_ace_list(file_ace_list);
3072 free_canon_ace_list(dir_ace_list);
3077 * Only change security if we got a DACL.
3080 if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
3082 BOOL acl_set_support = False;
3086 * Try using the POSIX ACL set first. Fall back to chmod if
3087 * we have no ACL support on this filesystem.
3090 if (acl_perms && file_ace_list) {
3091 ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support);
3092 if (acl_set_support && ret == False) {
3093 DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
3094 free_canon_ace_list(file_ace_list);
3095 free_canon_ace_list(dir_ace_list);
3100 if (acl_perms && acl_set_support && fsp->is_directory) {
3102 if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) {
3103 DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
3104 free_canon_ace_list(file_ace_list);
3105 free_canon_ace_list(dir_ace_list);
3111 * No default ACL - delete one if it exists.
3114 if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name) == -1) {
3115 DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
3116 free_canon_ace_list(file_ace_list);
3117 free_canon_ace_list(dir_ace_list);
3123 if (acl_set_support)
3124 store_inheritance_attributes(fsp, file_ace_list, dir_ace_list,
3125 (psd->type & SE_DESC_DACL_PROTECTED) ? True : False);
3128 * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
3131 if(!acl_set_support && acl_perms) {
3134 if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
3135 free_canon_ace_list(file_ace_list);
3136 free_canon_ace_list(dir_ace_list);
3137 DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
3142 if (orig_mode != posix_perms) {
3144 DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
3145 fsp->fsp_name, (unsigned int)posix_perms ));
3147 if(SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms) == -1) {
3148 DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
3149 fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
3150 free_canon_ace_list(file_ace_list);
3151 free_canon_ace_list(dir_ace_list);
3158 free_canon_ace_list(file_ace_list);
3159 free_canon_ace_list(dir_ace_list);
3162 /* Any chown pending? */
3165 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3166 fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
3168 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
3169 DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3170 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
3178 /****************************************************************************
3179 Get the actual group bits stored on a file with an ACL. Has no effect if
3180 the file has no ACL. Needed in dosmode code where the stat() will return
3181 the mask bits, not the real group bits, for a file with an ACL.
3182 ****************************************************************************/
3184 int get_acl_group_bits( connection_struct *conn, char *fname, mode_t *mode )
3186 int entry_id = SMB_ACL_FIRST_ENTRY;
3187 SMB_ACL_ENTRY_T entry;
3188 SMB_ACL_T posix_acl;
3190 posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS);
3191 if (posix_acl == (SMB_ACL_T)NULL)
3194 while (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3195 SMB_ACL_TAG_T tagtype;
3196 SMB_ACL_PERMSET_T permset;
3199 if (entry_id == SMB_ACL_FIRST_ENTRY)
3200 entry_id = SMB_ACL_NEXT_ENTRY;
3202 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) ==-1)
3205 if (tagtype == SMB_ACL_GROUP_OBJ) {
3206 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3209 *mode &= ~(S_IRGRP|S_IWGRP|S_IXGRP);
3210 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRGRP : 0);
3211 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWGRP : 0);
3212 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXGRP : 0);
3220 /****************************************************************************
3221 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3222 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3223 ****************************************************************************/
3225 static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mode_t mode)
3227 int entry_id = SMB_ACL_FIRST_ENTRY;
3228 SMB_ACL_ENTRY_T entry;
3229 int num_entries = 0;
3231 while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3232 SMB_ACL_TAG_T tagtype;
3233 SMB_ACL_PERMSET_T permset;
3237 if (entry_id == SMB_ACL_FIRST_ENTRY)
3238 entry_id = SMB_ACL_NEXT_ENTRY;
3240 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
3243 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
3249 case SMB_ACL_USER_OBJ:
3250 perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
3252 case SMB_ACL_GROUP_OBJ:
3253 perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
3257 * FIXME: The ACL_MASK entry permissions should really be set to
3258 * the union of the permissions of all ACL_USER,
3259 * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what
3260 * acl_calc_mask() does, but Samba ACLs doesn't provide it.
3262 perms = S_IRUSR|S_IWUSR|S_IXUSR;
3265 perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
3271 if (map_acl_perms_to_permset(conn, perms, &permset) == -1)
3274 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) == -1)
3279 * If this is a simple 3 element ACL or no elements then it's a standard
3280 * UNIX permission set. Just use chmod...
3283 if ((num_entries == 3) || (num_entries == 0))
3289 /****************************************************************************
3290 Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ,
3291 GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the
3292 resulting ACL on TO. Note that name is in UNIX character set.
3293 ****************************************************************************/
3295 static int copy_access_acl(connection_struct *conn, const char *from, const char *to, mode_t mode)
3297 SMB_ACL_T posix_acl = NULL;
3300 if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL)
3303 if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3306 ret = SMB_VFS_SYS_ACL_SET_FILE(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl);
3310 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3314 /****************************************************************************
3315 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3316 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3317 Note that name is in UNIX character set.
3318 ****************************************************************************/
3320 int chmod_acl(connection_struct *conn, const char *name, mode_t mode)
3322 return copy_access_acl(conn, name, name, mode);
3325 /****************************************************************************
3326 If "inherit permissions" is set and the parent directory has no default
3327 ACL but it does have an Access ACL, inherit this Access ACL to file name.
3328 ****************************************************************************/
3330 int inherit_access_acl(connection_struct *conn, const char *name, mode_t mode)
3333 pstrcpy(dirname, parent_dirname(name));
3335 if (!lp_inherit_perms(SNUM(conn)) || directory_has_default_acl(conn, dirname))
3338 return copy_access_acl(conn, dirname, name, mode);
3341 /****************************************************************************
3342 Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3343 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3344 ****************************************************************************/
3346 int fchmod_acl(files_struct *fsp, int fd, mode_t mode)
3348 connection_struct *conn = fsp->conn;
3349 SMB_ACL_T posix_acl = NULL;
3352 if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fd)) == NULL)
3355 if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3358 ret = SMB_VFS_SYS_ACL_SET_FD(fsp, fd, posix_acl);
3362 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3366 /****************************************************************************
3367 Check for an existing default POSIX ACL on a directory.
3368 ****************************************************************************/
3370 BOOL directory_has_default_acl(connection_struct *conn, const char *fname)
3372 SMB_ACL_T dir_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT);
3373 BOOL has_acl = False;
3374 SMB_ACL_ENTRY_T entry;
3376 if (dir_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, dir_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1))
3380 SMB_VFS_SYS_ACL_FREE_ACL(conn, dir_acl);