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.
25 #define DBGC_CLASS DBGC_ACLS
27 /****************************************************************************
28 Data structures representing the internal ACE format.
29 ****************************************************************************/
31 enum ace_owner
{UID_ACE
, GID_ACE
, WORLD_ACE
};
32 enum ace_attribute
{ALLOW_ACE
, DENY_ACE
}; /* Used for incoming NT ACLS. */
34 typedef union posix_id
{
40 typedef struct canon_ace
{
41 struct canon_ace
*next
, *prev
;
43 mode_t perms
; /* Only use S_I(R|W|X)USR mode bits here. */
45 enum ace_owner owner_type
;
46 enum ace_attribute attr
;
51 #define ALL_ACE_PERMS (S_IRUSR|S_IWUSR|S_IXUSR)
54 * EA format of user.SAMBA_PAI (Samba_Posix_Acl_Interitance)
57 * | 1 | 1 | 2 | 2 | ....
58 * +------+------+-------------+---------------------+-------------+--------------------+
59 * | vers | flag | num_entries | num_default_entries | ..entries.. | default_entries... |
60 * +------+------+-------------+---------------------+-------------+--------------------+
63 #define PAI_VERSION_OFFSET 0
64 #define PAI_FLAG_OFFSET 1
65 #define PAI_NUM_ENTRIES_OFFSET 2
66 #define PAI_NUM_DEFAULT_ENTRIES_OFFSET 4
67 #define PAI_ENTRIES_BASE 6
70 #define PAI_ACL_FLAG_PROTECTED 0x1
71 #define PAI_ENTRY_LENGTH 5
74 * In memory format of user.SAMBA_PAI attribute.
78 struct pai_entry
*next
, *prev
;
79 enum ace_owner owner_type
;
85 unsigned int num_entries
;
86 struct pai_entry
*entry_list
;
87 unsigned int num_def_entries
;
88 struct pai_entry
*def_entry_list
;
91 /************************************************************************
92 Return a uint32 of the pai_entry principal.
93 ************************************************************************/
95 static uint32
get_pai_entry_val(struct pai_entry
*paie
)
97 switch (paie
->owner_type
) {
99 DEBUG(10,("get_pai_entry_val: uid = %u\n", (unsigned int)paie
->unix_ug
.uid
));
100 return (uint32
)paie
->unix_ug
.uid
;
102 DEBUG(10,("get_pai_entry_val: gid = %u\n", (unsigned int)paie
->unix_ug
.gid
));
103 return (uint32
)paie
->unix_ug
.gid
;
106 DEBUG(10,("get_pai_entry_val: world ace\n"));
111 /************************************************************************
112 Return a uint32 of the entry principal.
113 ************************************************************************/
115 static uint32
get_entry_val(canon_ace
*ace_entry
)
117 switch (ace_entry
->owner_type
) {
119 DEBUG(10,("get_entry_val: uid = %u\n", (unsigned int)ace_entry
->unix_ug
.uid
));
120 return (uint32
)ace_entry
->unix_ug
.uid
;
122 DEBUG(10,("get_entry_val: gid = %u\n", (unsigned int)ace_entry
->unix_ug
.gid
));
123 return (uint32
)ace_entry
->unix_ug
.gid
;
126 DEBUG(10,("get_entry_val: world ace\n"));
131 /************************************************************************
132 Count the inherited entries.
133 ************************************************************************/
135 static unsigned int num_inherited_entries(canon_ace
*ace_list
)
137 unsigned int num_entries
= 0;
139 for (; ace_list
; ace_list
= ace_list
->next
)
140 if (ace_list
->inherited
)
145 /************************************************************************
146 Create the on-disk format. Caller must free.
147 ************************************************************************/
149 static char *create_pai_buf(canon_ace
*file_ace_list
, canon_ace
*dir_ace_list
, BOOL
protected, size_t *store_size
)
151 char *pai_buf
= NULL
;
152 canon_ace
*ace_list
= NULL
;
153 char *entry_offset
= NULL
;
154 unsigned int num_entries
= 0;
155 unsigned int num_def_entries
= 0;
157 for (ace_list
= file_ace_list
; ace_list
; ace_list
= ace_list
->next
)
158 if (ace_list
->inherited
)
161 for (ace_list
= dir_ace_list
; ace_list
; ace_list
= ace_list
->next
)
162 if (ace_list
->inherited
)
165 DEBUG(10,("create_pai_buf: num_entries = %u, num_def_entries = %u\n", num_entries
, num_def_entries
));
167 *store_size
= PAI_ENTRIES_BASE
+ ((num_entries
+ num_def_entries
)*PAI_ENTRY_LENGTH
);
169 pai_buf
= SMB_MALLOC(*store_size
);
174 /* Set up the header. */
175 memset(pai_buf
, '\0', PAI_ENTRIES_BASE
);
176 SCVAL(pai_buf
,PAI_VERSION_OFFSET
,PAI_VERSION
);
177 SCVAL(pai_buf
,PAI_FLAG_OFFSET
,(protected ? PAI_ACL_FLAG_PROTECTED
: 0));
178 SSVAL(pai_buf
,PAI_NUM_ENTRIES_OFFSET
,num_entries
);
179 SSVAL(pai_buf
,PAI_NUM_DEFAULT_ENTRIES_OFFSET
,num_def_entries
);
181 entry_offset
= pai_buf
+ PAI_ENTRIES_BASE
;
183 for (ace_list
= file_ace_list
; ace_list
; ace_list
= ace_list
->next
) {
184 if (ace_list
->inherited
) {
185 uint8 type_val
= (unsigned char)ace_list
->owner_type
;
186 uint32 entry_val
= get_entry_val(ace_list
);
188 SCVAL(entry_offset
,0,type_val
);
189 SIVAL(entry_offset
,1,entry_val
);
190 entry_offset
+= PAI_ENTRY_LENGTH
;
194 for (ace_list
= dir_ace_list
; ace_list
; ace_list
= ace_list
->next
) {
195 if (ace_list
->inherited
) {
196 uint8 type_val
= (unsigned char)ace_list
->owner_type
;
197 uint32 entry_val
= get_entry_val(ace_list
);
199 SCVAL(entry_offset
,0,type_val
);
200 SIVAL(entry_offset
,1,entry_val
);
201 entry_offset
+= PAI_ENTRY_LENGTH
;
208 /************************************************************************
209 Store the user.SAMBA_PAI attribute on disk.
210 ************************************************************************/
212 static void store_inheritance_attributes(files_struct
*fsp
, canon_ace
*file_ace_list
,
213 canon_ace
*dir_ace_list
, BOOL
protected)
219 if (!lp_map_acl_inherit(SNUM(fsp
->conn
)))
223 * Don't store if this ACL isn't protected and
224 * none of the entries in it are marked as inherited.
227 if (!protected && num_inherited_entries(file_ace_list
) == 0 && num_inherited_entries(dir_ace_list
) == 0) {
228 /* Instead just remove the attribute if it exists. */
230 SMB_VFS_FREMOVEXATTR(fsp
, fsp
->fd
, SAMBA_POSIX_INHERITANCE_EA_NAME
);
232 SMB_VFS_REMOVEXATTR(fsp
->conn
, fsp
->fsp_name
, SAMBA_POSIX_INHERITANCE_EA_NAME
);
236 pai_buf
= create_pai_buf(file_ace_list
, dir_ace_list
, protected, &store_size
);
239 ret
= SMB_VFS_FSETXATTR(fsp
, fsp
->fd
, SAMBA_POSIX_INHERITANCE_EA_NAME
,
240 pai_buf
, store_size
, 0);
242 ret
= SMB_VFS_SETXATTR(fsp
->conn
,fsp
->fsp_name
, SAMBA_POSIX_INHERITANCE_EA_NAME
,
243 pai_buf
, store_size
, 0);
247 DEBUG(10,("store_inheritance_attribute:%s for file %s\n", protected ? " (protected)" : "", fsp
->fsp_name
));
248 if (ret
== -1 && !no_acl_syscall_error(errno
))
249 DEBUG(1,("store_inheritance_attribute: Error %s\n", strerror(errno
) ));
252 /************************************************************************
253 Delete the in memory inheritance info.
254 ************************************************************************/
256 static void free_inherited_info(struct pai_val
*pal
)
259 struct pai_entry
*paie
, *paie_next
;
260 for (paie
= pal
->entry_list
; paie
; paie
= paie_next
) {
261 paie_next
= paie
->next
;
264 for (paie
= pal
->def_entry_list
; paie
; paie
= paie_next
) {
265 paie_next
= paie
->next
;
272 /************************************************************************
273 Was this ACL protected ?
274 ************************************************************************/
276 static BOOL
get_protected_flag(struct pai_val
*pal
)
280 return pal
->protected;
283 /************************************************************************
284 Was this ACE inherited ?
285 ************************************************************************/
287 static BOOL
get_inherited_flag(struct pai_val
*pal
, canon_ace
*ace_entry
, BOOL default_ace
)
289 struct pai_entry
*paie
;
294 /* If the entry exists it is inherited. */
295 for (paie
= (default_ace
? pal
->def_entry_list
: pal
->entry_list
); paie
; paie
= paie
->next
) {
296 if (ace_entry
->owner_type
== paie
->owner_type
&&
297 get_entry_val(ace_entry
) == get_pai_entry_val(paie
))
303 /************************************************************************
304 Ensure an attribute just read is valid.
305 ************************************************************************/
307 static BOOL
check_pai_ok(char *pai_buf
, size_t pai_buf_data_size
)
310 uint16 num_def_entries
;
312 if (pai_buf_data_size
< PAI_ENTRIES_BASE
) {
313 /* Corrupted - too small. */
317 if (CVAL(pai_buf
,PAI_VERSION_OFFSET
) != PAI_VERSION
)
320 num_entries
= SVAL(pai_buf
,PAI_NUM_ENTRIES_OFFSET
);
321 num_def_entries
= SVAL(pai_buf
,PAI_NUM_DEFAULT_ENTRIES_OFFSET
);
323 /* Check the entry lists match. */
324 /* Each entry is 5 bytes (type plus 4 bytes of uid or gid). */
326 if (((num_entries
+ num_def_entries
)*PAI_ENTRY_LENGTH
) + PAI_ENTRIES_BASE
!= pai_buf_data_size
)
333 /************************************************************************
334 Convert to in-memory format.
335 ************************************************************************/
337 static struct pai_val
*create_pai_val(char *buf
, size_t size
)
340 struct pai_val
*paiv
= NULL
;
343 if (!check_pai_ok(buf
, size
))
346 paiv
= SMB_MALLOC_P(struct pai_val
);
350 memset(paiv
, '\0', sizeof(struct pai_val
));
352 paiv
->protected = (CVAL(buf
,PAI_FLAG_OFFSET
) == PAI_ACL_FLAG_PROTECTED
);
354 paiv
->num_entries
= SVAL(buf
,PAI_NUM_ENTRIES_OFFSET
);
355 paiv
->num_def_entries
= SVAL(buf
,PAI_NUM_DEFAULT_ENTRIES_OFFSET
);
357 entry_offset
= buf
+ PAI_ENTRIES_BASE
;
359 DEBUG(10,("create_pai_val:%s num_entries = %u, num_def_entries = %u\n",
360 paiv
->protected ? " (protected)" : "", paiv
->num_entries
, paiv
->num_def_entries
));
362 for (i
= 0; i
< paiv
->num_entries
; i
++) {
363 struct pai_entry
*paie
;
365 paie
= SMB_MALLOC_P(struct pai_entry
);
367 free_inherited_info(paiv
);
371 paie
->owner_type
= (enum ace_owner
)CVAL(entry_offset
,0);
372 switch( paie
->owner_type
) {
374 paie
->unix_ug
.uid
= (uid_t
)IVAL(entry_offset
,1);
375 DEBUG(10,("create_pai_val: uid = %u\n", (unsigned int)paie
->unix_ug
.uid
));
378 paie
->unix_ug
.gid
= (gid_t
)IVAL(entry_offset
,1);
379 DEBUG(10,("create_pai_val: gid = %u\n", (unsigned int)paie
->unix_ug
.gid
));
382 paie
->unix_ug
.world
= -1;
383 DEBUG(10,("create_pai_val: world ace\n"));
386 free_inherited_info(paiv
);
389 entry_offset
+= PAI_ENTRY_LENGTH
;
390 DLIST_ADD(paiv
->entry_list
, paie
);
393 for (i
= 0; i
< paiv
->num_def_entries
; i
++) {
394 struct pai_entry
*paie
;
396 paie
= SMB_MALLOC_P(struct pai_entry
);
398 free_inherited_info(paiv
);
402 paie
->owner_type
= (enum ace_owner
)CVAL(entry_offset
,0);
403 switch( paie
->owner_type
) {
405 paie
->unix_ug
.uid
= (uid_t
)IVAL(entry_offset
,1);
406 DEBUG(10,("create_pai_val: (def) uid = %u\n", (unsigned int)paie
->unix_ug
.uid
));
409 paie
->unix_ug
.gid
= (gid_t
)IVAL(entry_offset
,1);
410 DEBUG(10,("create_pai_val: (def) gid = %u\n", (unsigned int)paie
->unix_ug
.gid
));
413 paie
->unix_ug
.world
= -1;
414 DEBUG(10,("create_pai_val: (def) world ace\n"));
417 free_inherited_info(paiv
);
420 entry_offset
+= PAI_ENTRY_LENGTH
;
421 DLIST_ADD(paiv
->def_entry_list
, paie
);
427 /************************************************************************
428 Load the user.SAMBA_PAI attribute.
429 ************************************************************************/
431 static struct pai_val
*load_inherited_info(files_struct
*fsp
)
434 size_t pai_buf_size
= 1024;
435 struct pai_val
*paiv
= NULL
;
438 if (!lp_map_acl_inherit(SNUM(fsp
->conn
)))
441 if ((pai_buf
= SMB_MALLOC(pai_buf_size
)) == NULL
)
446 ret
= SMB_VFS_FGETXATTR(fsp
, fsp
->fd
, SAMBA_POSIX_INHERITANCE_EA_NAME
,
447 pai_buf
, pai_buf_size
);
449 ret
= SMB_VFS_GETXATTR(fsp
->conn
,fsp
->fsp_name
,SAMBA_POSIX_INHERITANCE_EA_NAME
,
450 pai_buf
, pai_buf_size
);
453 if (errno
!= ERANGE
) {
456 /* Buffer too small - enlarge it. */
459 if (pai_buf_size
> 1024*1024) {
460 return NULL
; /* Limit malloc to 1mb. */
462 if ((pai_buf
= SMB_MALLOC(pai_buf_size
)) == NULL
)
467 DEBUG(10,("load_inherited_info: ret = %lu for file %s\n", (unsigned long)ret
, fsp
->fsp_name
));
470 /* No attribute or not supported. */
472 if (errno
!= ENOATTR
)
473 DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno
) ));
476 DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno
) ));
482 paiv
= create_pai_val(pai_buf
, ret
);
484 if (paiv
&& paiv
->protected)
485 DEBUG(10,("load_inherited_info: ACL is protected for file %s\n", fsp
->fsp_name
));
491 /****************************************************************************
492 Functions to manipulate the internal ACE format.
493 ****************************************************************************/
495 /****************************************************************************
496 Count a linked list of canonical ACE entries.
497 ****************************************************************************/
499 static size_t count_canon_ace_list( canon_ace
*list_head
)
504 for (ace
= list_head
; ace
; ace
= ace
->next
)
510 /****************************************************************************
511 Free a linked list of canonical ACE entries.
512 ****************************************************************************/
514 static void free_canon_ace_list( canon_ace
*list_head
)
517 canon_ace
*old_head
= list_head
;
518 DLIST_REMOVE(list_head
, list_head
);
523 /****************************************************************************
524 Function to duplicate a canon_ace entry.
525 ****************************************************************************/
527 static canon_ace
*dup_canon_ace( canon_ace
*src_ace
)
529 canon_ace
*dst_ace
= SMB_MALLOC_P(canon_ace
);
535 dst_ace
->prev
= dst_ace
->next
= NULL
;
539 /****************************************************************************
540 Print out a canon ace.
541 ****************************************************************************/
543 static void print_canon_ace(canon_ace
*pace
, int num
)
547 dbgtext( "canon_ace index %d. Type = %s ", num
, pace
->attr
== ALLOW_ACE
? "allow" : "deny" );
548 dbgtext( "SID = %s ", sid_to_string( str
, &pace
->trustee
));
549 if (pace
->owner_type
== UID_ACE
) {
550 const char *u_name
= uidtoname(pace
->unix_ug
.uid
);
551 dbgtext( "uid %u (%s) ", (unsigned int)pace
->unix_ug
.uid
, u_name
);
552 } else if (pace
->owner_type
== GID_ACE
) {
553 char *g_name
= gidtoname(pace
->unix_ug
.gid
);
554 dbgtext( "gid %u (%s) ", (unsigned int)pace
->unix_ug
.gid
, g_name
);
557 switch (pace
->type
) {
559 dbgtext( "SMB_ACL_USER ");
561 case SMB_ACL_USER_OBJ
:
562 dbgtext( "SMB_ACL_USER_OBJ ");
565 dbgtext( "SMB_ACL_GROUP ");
567 case SMB_ACL_GROUP_OBJ
:
568 dbgtext( "SMB_ACL_GROUP_OBJ ");
571 dbgtext( "SMB_ACL_OTHER ");
575 dbgtext( "(inherited) ");
577 dbgtext( "%c", pace
->perms
& S_IRUSR
? 'r' : '-');
578 dbgtext( "%c", pace
->perms
& S_IWUSR
? 'w' : '-');
579 dbgtext( "%c\n", pace
->perms
& S_IXUSR
? 'x' : '-');
582 /****************************************************************************
583 Print out a canon ace list.
584 ****************************************************************************/
586 static void print_canon_ace_list(const char *name
, canon_ace
*ace_list
)
590 if( DEBUGLVL( 10 )) {
591 dbgtext( "print_canon_ace_list: %s\n", name
);
592 for (;ace_list
; ace_list
= ace_list
->next
, count
++)
593 print_canon_ace(ace_list
, count
);
597 /****************************************************************************
598 Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
599 ****************************************************************************/
601 static mode_t
convert_permset_to_mode_t(connection_struct
*conn
, SMB_ACL_PERMSET_T permset
)
605 ret
|= (SMB_VFS_SYS_ACL_GET_PERM(conn
, permset
, SMB_ACL_READ
) ? S_IRUSR
: 0);
606 ret
|= (SMB_VFS_SYS_ACL_GET_PERM(conn
, permset
, SMB_ACL_WRITE
) ? S_IWUSR
: 0);
607 ret
|= (SMB_VFS_SYS_ACL_GET_PERM(conn
, permset
, SMB_ACL_EXECUTE
) ? S_IXUSR
: 0);
612 /****************************************************************************
613 Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
614 ****************************************************************************/
616 static mode_t
unix_perms_to_acl_perms(mode_t mode
, int r_mask
, int w_mask
, int x_mask
)
630 /****************************************************************************
631 Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to
632 an SMB_ACL_PERMSET_T.
633 ****************************************************************************/
635 static int map_acl_perms_to_permset(connection_struct
*conn
, mode_t mode
, SMB_ACL_PERMSET_T
*p_permset
)
637 if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn
, *p_permset
) == -1)
639 if (mode
& S_IRUSR
) {
640 if (SMB_VFS_SYS_ACL_ADD_PERM(conn
, *p_permset
, SMB_ACL_READ
) == -1)
643 if (mode
& S_IWUSR
) {
644 if (SMB_VFS_SYS_ACL_ADD_PERM(conn
, *p_permset
, SMB_ACL_WRITE
) == -1)
647 if (mode
& S_IXUSR
) {
648 if (SMB_VFS_SYS_ACL_ADD_PERM(conn
, *p_permset
, SMB_ACL_EXECUTE
) == -1)
653 /****************************************************************************
654 Function to create owner and group SIDs from a SMB_STRUCT_STAT.
655 ****************************************************************************/
657 static void create_file_sids(SMB_STRUCT_STAT
*psbuf
, DOM_SID
*powner_sid
, DOM_SID
*pgroup_sid
)
659 uid_to_sid( powner_sid
, psbuf
->st_uid
);
660 gid_to_sid( pgroup_sid
, psbuf
->st_gid
);
663 /****************************************************************************
664 Merge aces with a common sid - if both are allow or deny, OR the permissions together and
665 delete the second one. If the first is deny, mask the permissions off and delete the allow
666 if the permissions become zero, delete the deny if the permissions are non zero.
667 ****************************************************************************/
669 static void merge_aces( canon_ace
**pp_list_head
)
671 canon_ace
*list_head
= *pp_list_head
;
672 canon_ace
*curr_ace_outer
;
673 canon_ace
*curr_ace_outer_next
;
676 * First, merge allow entries with identical SIDs, and deny entries
677 * with identical SIDs.
680 for (curr_ace_outer
= list_head
; curr_ace_outer
; curr_ace_outer
= curr_ace_outer_next
) {
682 canon_ace
*curr_ace_next
;
684 curr_ace_outer_next
= curr_ace_outer
->next
; /* Save the link in case we delete. */
686 for (curr_ace
= curr_ace_outer
->next
; curr_ace
; curr_ace
= curr_ace_next
) {
688 curr_ace_next
= curr_ace
->next
; /* Save the link in case of delete. */
690 if (sid_equal(&curr_ace
->trustee
, &curr_ace_outer
->trustee
) &&
691 (curr_ace
->attr
== curr_ace_outer
->attr
)) {
693 if( DEBUGLVL( 10 )) {
694 dbgtext("merge_aces: Merging ACE's\n");
695 print_canon_ace( curr_ace_outer
, 0);
696 print_canon_ace( curr_ace
, 0);
699 /* Merge two allow or two deny ACE's. */
701 curr_ace_outer
->perms
|= curr_ace
->perms
;
702 DLIST_REMOVE(list_head
, curr_ace
);
704 curr_ace_outer_next
= curr_ace_outer
->next
; /* We may have deleted the link. */
710 * Now go through and mask off allow permissions with deny permissions.
711 * We can delete either the allow or deny here as we know that each SID
712 * appears only once in the list.
715 for (curr_ace_outer
= list_head
; curr_ace_outer
; curr_ace_outer
= curr_ace_outer_next
) {
717 canon_ace
*curr_ace_next
;
719 curr_ace_outer_next
= curr_ace_outer
->next
; /* Save the link in case we delete. */
721 for (curr_ace
= curr_ace_outer
->next
; curr_ace
; curr_ace
= curr_ace_next
) {
723 curr_ace_next
= curr_ace
->next
; /* Save the link in case of delete. */
726 * Subtract ACE's with different entries. Due to the ordering constraints
727 * we've put on the ACL, we know the deny must be the first one.
730 if (sid_equal(&curr_ace
->trustee
, &curr_ace_outer
->trustee
) &&
731 (curr_ace_outer
->attr
== DENY_ACE
) && (curr_ace
->attr
== ALLOW_ACE
)) {
733 if( DEBUGLVL( 10 )) {
734 dbgtext("merge_aces: Masking ACE's\n");
735 print_canon_ace( curr_ace_outer
, 0);
736 print_canon_ace( curr_ace
, 0);
739 curr_ace
->perms
&= ~curr_ace_outer
->perms
;
741 if (curr_ace
->perms
== 0) {
744 * The deny overrides the allow. Remove the allow.
747 DLIST_REMOVE(list_head
, curr_ace
);
749 curr_ace_outer_next
= curr_ace_outer
->next
; /* We may have deleted the link. */
754 * Even after removing permissions, there
755 * are still allow permissions - delete the deny.
756 * It is safe to delete the deny here,
757 * as we are guarenteed by the deny first
758 * ordering that all the deny entries for
759 * this SID have already been merged into one
760 * before we can get to an allow ace.
763 DLIST_REMOVE(list_head
, curr_ace_outer
);
764 SAFE_FREE(curr_ace_outer
);
769 } /* end for curr_ace */
770 } /* end for curr_ace_outer */
772 /* We may have modified the list. */
774 *pp_list_head
= list_head
;
777 /****************************************************************************
778 Check if we need to return NT4.x compatible ACL entries.
779 ****************************************************************************/
781 static BOOL
nt4_compatible_acls(void)
783 const char *compat
= lp_acl_compatibility();
785 if (*compat
== '\0') {
786 enum remote_arch_types ra_type
= get_remote_arch();
788 /* Automatically adapt to client */
789 return (ra_type
<= RA_WINNT
);
791 return (strequal(compat
, "winnt"));
795 /****************************************************************************
796 Map canon_ace perms to permission bits NT.
797 The attr element is not used here - we only process deny entries on set,
798 not get. Deny entries are implicit on get with ace->perms = 0.
799 ****************************************************************************/
801 static SEC_ACCESS
map_canon_ace_perms(int *pacl_type
, DOM_SID
*powner_sid
, canon_ace
*ace
)
806 *pacl_type
= SEC_ACE_TYPE_ACCESS_ALLOWED
;
808 if ((ace
->perms
& ALL_ACE_PERMS
) == ALL_ACE_PERMS
) {
809 nt_mask
= UNIX_ACCESS_RWX
;
810 } else if ((ace
->perms
& ALL_ACE_PERMS
) == (mode_t
)0) {
812 * Windows NT refuses to display ACEs with no permissions in them (but
813 * they are perfectly legal with Windows 2000). If the ACE has empty
814 * permissions we cannot use 0, so we use the otherwise unused
815 * WRITE_OWNER permission, which we ignore when we set an ACL.
816 * We abstract this into a #define of UNIX_ACCESS_NONE to allow this
817 * to be changed in the future.
820 if (nt4_compatible_acls())
821 nt_mask
= UNIX_ACCESS_NONE
;
825 nt_mask
|= ((ace
->perms
& S_IRUSR
) ? UNIX_ACCESS_R
: 0 );
826 nt_mask
|= ((ace
->perms
& S_IWUSR
) ? UNIX_ACCESS_W
: 0 );
827 nt_mask
|= ((ace
->perms
& S_IXUSR
) ? UNIX_ACCESS_X
: 0 );
830 DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
831 (unsigned int)ace
->perms
, (unsigned int)nt_mask
));
833 init_sec_access(&sa
,nt_mask
);
837 /****************************************************************************
838 Map NT perms to a UNIX mode_t.
839 ****************************************************************************/
841 #define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
842 #define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
843 #define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
845 static mode_t
map_nt_perms( SEC_ACCESS sec_access
, int type
)
851 if(sec_access
.mask
& GENERIC_ALL_ACCESS
)
852 mode
= S_IRUSR
|S_IWUSR
|S_IXUSR
;
854 mode
|= (sec_access
.mask
& (GENERIC_READ_ACCESS
|FILE_SPECIFIC_READ_BITS
)) ? S_IRUSR
: 0;
855 mode
|= (sec_access
.mask
& (GENERIC_WRITE_ACCESS
|FILE_SPECIFIC_WRITE_BITS
)) ? S_IWUSR
: 0;
856 mode
|= (sec_access
.mask
& (GENERIC_EXECUTE_ACCESS
|FILE_SPECIFIC_EXECUTE_BITS
)) ? S_IXUSR
: 0;
860 if(sec_access
.mask
& GENERIC_ALL_ACCESS
)
861 mode
= S_IRGRP
|S_IWGRP
|S_IXGRP
;
863 mode
|= (sec_access
.mask
& (GENERIC_READ_ACCESS
|FILE_SPECIFIC_READ_BITS
)) ? S_IRGRP
: 0;
864 mode
|= (sec_access
.mask
& (GENERIC_WRITE_ACCESS
|FILE_SPECIFIC_WRITE_BITS
)) ? S_IWGRP
: 0;
865 mode
|= (sec_access
.mask
& (GENERIC_EXECUTE_ACCESS
|FILE_SPECIFIC_EXECUTE_BITS
)) ? S_IXGRP
: 0;
869 if(sec_access
.mask
& GENERIC_ALL_ACCESS
)
870 mode
= S_IROTH
|S_IWOTH
|S_IXOTH
;
872 mode
|= (sec_access
.mask
& (GENERIC_READ_ACCESS
|FILE_SPECIFIC_READ_BITS
)) ? S_IROTH
: 0;
873 mode
|= (sec_access
.mask
& (GENERIC_WRITE_ACCESS
|FILE_SPECIFIC_WRITE_BITS
)) ? S_IWOTH
: 0;
874 mode
|= (sec_access
.mask
& (GENERIC_EXECUTE_ACCESS
|FILE_SPECIFIC_EXECUTE_BITS
)) ? S_IXOTH
: 0;
882 /****************************************************************************
883 Unpack a SEC_DESC into a UNIX owner and group.
884 ****************************************************************************/
886 static BOOL
unpack_nt_owners(int snum
, SMB_STRUCT_STAT
*psbuf
, uid_t
*puser
, gid_t
*pgrp
, uint32 security_info_sent
, SEC_DESC
*psd
)
894 if(security_info_sent
== 0) {
895 DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
900 * Validate the owner and group SID's.
903 memset(&owner_sid
, '\0', sizeof(owner_sid
));
904 memset(&grp_sid
, '\0', sizeof(grp_sid
));
906 DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
909 * Don't immediately fail if the owner sid cannot be validated.
910 * This may be a group chown only set.
913 if (security_info_sent
& OWNER_SECURITY_INFORMATION
) {
914 sid_copy(&owner_sid
, psd
->owner_sid
);
915 if (!NT_STATUS_IS_OK(sid_to_uid(&owner_sid
, puser
))) {
916 if (lp_force_unknown_acl_user(snum
)) {
917 /* this allows take ownership to work
919 extern struct current_user current_user
;
920 *puser
= current_user
.uid
;
922 DEBUG(3,("unpack_nt_owners: unable to validate"
923 " owner sid for %s\n",
924 sid_string_static(&owner_sid
)));
931 * Don't immediately fail if the group sid cannot be validated.
932 * This may be an owner chown only set.
935 if (security_info_sent
& GROUP_SECURITY_INFORMATION
) {
936 sid_copy(&grp_sid
, psd
->grp_sid
);
937 if (!NT_STATUS_IS_OK(sid_to_gid( &grp_sid
, pgrp
))) {
938 if (lp_force_unknown_acl_user(snum
)) {
939 /* this allows take group ownership to work
941 extern struct current_user current_user
;
942 *pgrp
= current_user
.gid
;
944 DEBUG(3,("unpack_nt_owners: unable to validate"
951 DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
956 /****************************************************************************
957 Ensure the enforced permissions for this share apply.
958 ****************************************************************************/
960 static void apply_default_perms(files_struct
*fsp
, canon_ace
*pace
, mode_t type
)
962 int snum
= SNUM(fsp
->conn
);
963 mode_t and_bits
= (mode_t
)0;
964 mode_t or_bits
= (mode_t
)0;
966 /* Get the initial bits to apply. */
968 if (fsp
->is_directory
) {
969 and_bits
= lp_dir_security_mask(snum
);
970 or_bits
= lp_force_dir_security_mode(snum
);
972 and_bits
= lp_security_mask(snum
);
973 or_bits
= lp_force_security_mode(snum
);
976 /* Now bounce them into the S_USR space. */
979 /* Ensure owner has read access. */
980 pace
->perms
|= S_IRUSR
;
981 if (fsp
->is_directory
)
982 pace
->perms
|= (S_IWUSR
|S_IXUSR
);
983 and_bits
= unix_perms_to_acl_perms(and_bits
, S_IRUSR
, S_IWUSR
, S_IXUSR
);
984 or_bits
= unix_perms_to_acl_perms(or_bits
, S_IRUSR
, S_IWUSR
, S_IXUSR
);
987 and_bits
= unix_perms_to_acl_perms(and_bits
, S_IRGRP
, S_IWGRP
, S_IXGRP
);
988 or_bits
= unix_perms_to_acl_perms(or_bits
, S_IRGRP
, S_IWGRP
, S_IXGRP
);
991 and_bits
= unix_perms_to_acl_perms(and_bits
, S_IROTH
, S_IWOTH
, S_IXOTH
);
992 or_bits
= unix_perms_to_acl_perms(or_bits
, S_IROTH
, S_IWOTH
, S_IXOTH
);
996 pace
->perms
= ((pace
->perms
& and_bits
)|or_bits
);
999 /****************************************************************************
1000 Check if a given uid/SID is in a group gid/SID. This is probably very
1001 expensive and will need optimisation. A *lot* of optimisation :-). JRA.
1002 ****************************************************************************/
1004 static BOOL
uid_entry_in_group( canon_ace
*uid_ace
, canon_ace
*group_ace
)
1006 extern DOM_SID global_sid_World
;
1009 extern struct current_user current_user
;
1011 /* "Everyone" always matches every uid. */
1013 if (sid_equal(&group_ace
->trustee
, &global_sid_World
))
1016 /* Assume that the current user is in the current group (force group) */
1018 if (uid_ace
->unix_ug
.uid
== current_user
.uid
&& group_ace
->unix_ug
.gid
== current_user
.gid
)
1021 fstrcpy(u_name
, uidtoname(uid_ace
->unix_ug
.uid
));
1022 fstrcpy(g_name
, gidtoname(group_ace
->unix_ug
.gid
));
1025 * Due to the winbind interfaces we need to do this via names,
1029 return user_in_group_list(u_name
, g_name
, NULL
, 0);
1032 /****************************************************************************
1033 A well formed POSIX file or default ACL has at least 3 entries, a
1034 SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
1035 In addition, the owner must always have at least read access.
1036 When using this call on get_acl, the pst struct is valid and contains
1037 the mode of the file. When using this call on set_acl, the pst struct has
1038 been modified to have a mode containing the default for this file or directory
1040 ****************************************************************************/
1042 static BOOL
ensure_canon_entry_valid(canon_ace
**pp_ace
,
1044 DOM_SID
*pfile_owner_sid
,
1045 DOM_SID
*pfile_grp_sid
,
1046 SMB_STRUCT_STAT
*pst
,
1049 extern DOM_SID global_sid_World
;
1051 BOOL got_user
= False
;
1052 BOOL got_grp
= False
;
1053 BOOL got_other
= False
;
1054 canon_ace
*pace_other
= NULL
;
1055 canon_ace
*pace_group
= NULL
;
1057 for (pace
= *pp_ace
; pace
; pace
= pace
->next
) {
1058 if (pace
->type
== SMB_ACL_USER_OBJ
) {
1061 apply_default_perms(fsp
, pace
, S_IRUSR
);
1064 } else if (pace
->type
== SMB_ACL_GROUP_OBJ
) {
1067 * Ensure create mask/force create mode is respected on set.
1071 apply_default_perms(fsp
, pace
, S_IRGRP
);
1075 } else if (pace
->type
== SMB_ACL_OTHER
) {
1078 * Ensure create mask/force create mode is respected on set.
1082 apply_default_perms(fsp
, pace
, S_IROTH
);
1089 if ((pace
= SMB_MALLOC_P(canon_ace
)) == NULL
) {
1090 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1095 pace
->type
= SMB_ACL_USER_OBJ
;
1096 pace
->owner_type
= UID_ACE
;
1097 pace
->unix_ug
.uid
= pst
->st_uid
;
1098 pace
->trustee
= *pfile_owner_sid
;
1099 pace
->attr
= ALLOW_ACE
;
1102 /* If we only got an "everyone" perm, just use that. */
1103 if (!got_grp
&& got_other
)
1104 pace
->perms
= pace_other
->perms
;
1105 else if (got_grp
&& uid_entry_in_group(pace
, pace_group
))
1106 pace
->perms
= pace_group
->perms
;
1110 apply_default_perms(fsp
, pace
, S_IRUSR
);
1112 pace
->perms
= unix_perms_to_acl_perms(pst
->st_mode
, S_IRUSR
, S_IWUSR
, S_IXUSR
);
1115 DLIST_ADD(*pp_ace
, pace
);
1119 if ((pace
= SMB_MALLOC_P(canon_ace
)) == NULL
) {
1120 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1125 pace
->type
= SMB_ACL_GROUP_OBJ
;
1126 pace
->owner_type
= GID_ACE
;
1127 pace
->unix_ug
.uid
= pst
->st_gid
;
1128 pace
->trustee
= *pfile_grp_sid
;
1129 pace
->attr
= ALLOW_ACE
;
1131 /* If we only got an "everyone" perm, just use that. */
1133 pace
->perms
= pace_other
->perms
;
1136 apply_default_perms(fsp
, pace
, S_IRGRP
);
1138 pace
->perms
= unix_perms_to_acl_perms(pst
->st_mode
, S_IRGRP
, S_IWGRP
, S_IXGRP
);
1141 DLIST_ADD(*pp_ace
, pace
);
1145 if ((pace
= SMB_MALLOC_P(canon_ace
)) == NULL
) {
1146 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1151 pace
->type
= SMB_ACL_OTHER
;
1152 pace
->owner_type
= WORLD_ACE
;
1153 pace
->unix_ug
.world
= -1;
1154 pace
->trustee
= global_sid_World
;
1155 pace
->attr
= ALLOW_ACE
;
1158 apply_default_perms(fsp
, pace
, S_IROTH
);
1160 pace
->perms
= unix_perms_to_acl_perms(pst
->st_mode
, S_IROTH
, S_IWOTH
, S_IXOTH
);
1162 DLIST_ADD(*pp_ace
, pace
);
1168 /****************************************************************************
1169 Check if a POSIX ACL has the required SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries.
1170 If it does not have them, check if there are any entries where the trustee is the
1171 file owner or the owning group, and map these to SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ.
1172 ****************************************************************************/
1174 static void check_owning_objs(canon_ace
*ace
, DOM_SID
*pfile_owner_sid
, DOM_SID
*pfile_grp_sid
)
1176 BOOL got_user_obj
, got_group_obj
;
1177 canon_ace
*current_ace
;
1180 entries
= count_canon_ace_list(ace
);
1181 got_user_obj
= False
;
1182 got_group_obj
= False
;
1184 for (i
=0, current_ace
= ace
; i
< entries
; i
++, current_ace
= current_ace
->next
) {
1185 if (current_ace
->type
== SMB_ACL_USER_OBJ
)
1186 got_user_obj
= True
;
1187 else if (current_ace
->type
== SMB_ACL_GROUP_OBJ
)
1188 got_group_obj
= True
;
1190 if (got_user_obj
&& got_group_obj
) {
1191 DEBUG(10,("check_owning_objs: ACL had owning user/group entries.\n"));
1195 for (i
=0, current_ace
= ace
; i
< entries
; i
++, current_ace
= current_ace
->next
) {
1196 if (!got_user_obj
&& current_ace
->owner_type
== UID_ACE
&&
1197 sid_equal(¤t_ace
->trustee
, pfile_owner_sid
)) {
1198 current_ace
->type
= SMB_ACL_USER_OBJ
;
1199 got_user_obj
= True
;
1201 if (!got_group_obj
&& current_ace
->owner_type
== GID_ACE
&&
1202 sid_equal(¤t_ace
->trustee
, pfile_grp_sid
)) {
1203 current_ace
->type
= SMB_ACL_GROUP_OBJ
;
1204 got_group_obj
= True
;
1208 DEBUG(10,("check_owning_objs: ACL is missing an owner entry.\n"));
1210 DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n"));
1213 /****************************************************************************
1214 Unpack a SEC_DESC into two canonical ace lists.
1215 ****************************************************************************/
1217 static BOOL
create_canon_ace_lists(files_struct
*fsp
, SMB_STRUCT_STAT
*pst
,
1218 DOM_SID
*pfile_owner_sid
,
1219 DOM_SID
*pfile_grp_sid
,
1220 canon_ace
**ppfile_ace
, canon_ace
**ppdir_ace
,
1223 extern DOM_SID global_sid_Creator_Owner
;
1224 extern DOM_SID global_sid_Creator_Group
;
1225 extern DOM_SID global_sid_World
;
1226 extern struct generic_mapping file_generic_mapping
;
1227 BOOL all_aces_are_inherit_only
= (fsp
->is_directory
? True
: False
);
1228 canon_ace
*file_ace
= NULL
;
1229 canon_ace
*dir_ace
= NULL
;
1230 canon_ace
*tmp_ace
= NULL
;
1231 canon_ace
*current_ace
= NULL
;
1232 BOOL got_dir_allow
= False
;
1233 BOOL got_file_allow
= False
;
1240 * Convert the incoming ACL into a more regular form.
1243 for(i
= 0; i
< dacl
->num_aces
; i
++) {
1244 SEC_ACE
*psa
= &dacl
->ace
[i
];
1246 if((psa
->type
!= SEC_ACE_TYPE_ACCESS_ALLOWED
) && (psa
->type
!= SEC_ACE_TYPE_ACCESS_DENIED
)) {
1247 DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
1251 if (nt4_compatible_acls()) {
1253 * The security mask may be UNIX_ACCESS_NONE which should map into
1254 * no permissions (we overload the WRITE_OWNER bit for this) or it
1255 * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
1256 * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
1260 * Convert GENERIC bits to specific bits.
1263 se_map_generic(&psa
->info
.mask
, &file_generic_mapping
);
1265 psa
->info
.mask
&= (UNIX_ACCESS_NONE
|FILE_ALL_ACCESS
);
1267 if(psa
->info
.mask
!= UNIX_ACCESS_NONE
)
1268 psa
->info
.mask
&= ~UNIX_ACCESS_NONE
;
1273 * Deal with the fact that NT 4.x re-writes the canonical format
1274 * that we return for default ACLs. If a directory ACE is identical
1275 * to a inherited directory ACE then NT changes the bits so that the
1276 * first ACE is set to OI|IO and the second ACE for this SID is set
1277 * to CI. We need to repair this. JRA.
1280 for(i
= 0; i
< dacl
->num_aces
; i
++) {
1281 SEC_ACE
*psa1
= &dacl
->ace
[i
];
1283 for (j
= i
+ 1; j
< dacl
->num_aces
; j
++) {
1284 SEC_ACE
*psa2
= &dacl
->ace
[j
];
1286 if (psa1
->info
.mask
!= psa2
->info
.mask
)
1289 if (!sid_equal(&psa1
->trustee
, &psa2
->trustee
))
1293 * Ok - permission bits and SIDs are equal.
1294 * Check if flags were re-written.
1297 if (psa1
->flags
& SEC_ACE_FLAG_INHERIT_ONLY
) {
1299 psa1
->flags
|= (psa2
->flags
& (SEC_ACE_FLAG_CONTAINER_INHERIT
|SEC_ACE_FLAG_OBJECT_INHERIT
));
1300 psa2
->flags
&= ~(SEC_ACE_FLAG_CONTAINER_INHERIT
|SEC_ACE_FLAG_OBJECT_INHERIT
);
1302 } else if (psa2
->flags
& SEC_ACE_FLAG_INHERIT_ONLY
) {
1304 psa2
->flags
|= (psa1
->flags
& (SEC_ACE_FLAG_CONTAINER_INHERIT
|SEC_ACE_FLAG_OBJECT_INHERIT
));
1305 psa1
->flags
&= ~(SEC_ACE_FLAG_CONTAINER_INHERIT
|SEC_ACE_FLAG_OBJECT_INHERIT
);
1311 for(i
= 0; i
< dacl
->num_aces
; i
++) {
1312 SEC_ACE
*psa
= &dacl
->ace
[i
];
1315 * Ignore non-mappable SIDs (NT Authority, BUILTIN etc).
1318 if (non_mappable_sid(&psa
->trustee
)) {
1320 DEBUG(10,("create_canon_ace_lists: ignoring non-mappable SID %s\n",
1321 sid_to_string(str
, &psa
->trustee
) ));
1326 * Create a cannon_ace entry representing this NT DACL ACE.
1329 if ((current_ace
= SMB_MALLOC_P(canon_ace
)) == NULL
) {
1330 free_canon_ace_list(file_ace
);
1331 free_canon_ace_list(dir_ace
);
1332 DEBUG(0,("create_canon_ace_lists: malloc fail.\n"));
1336 ZERO_STRUCTP(current_ace
);
1338 sid_copy(¤t_ace
->trustee
, &psa
->trustee
);
1341 * Try and work out if the SID is a user or group
1342 * as we need to flag these differently for POSIX.
1343 * Note what kind of a POSIX ACL this should map to.
1346 if( sid_equal(¤t_ace
->trustee
, &global_sid_World
)) {
1347 current_ace
->owner_type
= WORLD_ACE
;
1348 current_ace
->unix_ug
.world
= -1;
1349 current_ace
->type
= SMB_ACL_OTHER
;
1350 } else if (sid_equal(¤t_ace
->trustee
, &global_sid_Creator_Owner
)) {
1351 current_ace
->owner_type
= UID_ACE
;
1352 current_ace
->unix_ug
.uid
= pst
->st_uid
;
1353 current_ace
->type
= SMB_ACL_USER_OBJ
;
1356 * The Creator Owner entry only specifies inheritable permissions,
1357 * never access permissions. WinNT doesn't always set the ACE to
1358 *INHERIT_ONLY, though.
1361 if (nt4_compatible_acls())
1362 psa
->flags
|= SEC_ACE_FLAG_INHERIT_ONLY
;
1363 } else if (sid_equal(¤t_ace
->trustee
, &global_sid_Creator_Group
)) {
1364 current_ace
->owner_type
= GID_ACE
;
1365 current_ace
->unix_ug
.gid
= pst
->st_gid
;
1366 current_ace
->type
= SMB_ACL_GROUP_OBJ
;
1369 * The Creator Group entry only specifies inheritable permissions,
1370 * never access permissions. WinNT doesn't always set the ACE to
1371 *INHERIT_ONLY, though.
1373 if (nt4_compatible_acls())
1374 psa
->flags
|= SEC_ACE_FLAG_INHERIT_ONLY
;
1376 } else if (NT_STATUS_IS_OK(sid_to_uid( ¤t_ace
->trustee
, ¤t_ace
->unix_ug
.uid
))) {
1377 current_ace
->owner_type
= UID_ACE
;
1378 current_ace
->type
= SMB_ACL_USER
;
1379 } else if (NT_STATUS_IS_OK(sid_to_gid( ¤t_ace
->trustee
, ¤t_ace
->unix_ug
.gid
))) {
1380 current_ace
->owner_type
= GID_ACE
;
1381 current_ace
->type
= SMB_ACL_GROUP
;
1385 free_canon_ace_list(file_ace
);
1386 free_canon_ace_list(dir_ace
);
1387 DEBUG(0,("create_canon_ace_lists: unable to map SID %s to uid or gid.\n",
1388 sid_to_string(str
, ¤t_ace
->trustee
) ));
1389 SAFE_FREE(current_ace
);
1394 * Map the given NT permissions into a UNIX mode_t containing only
1395 * S_I(R|W|X)USR bits.
1398 current_ace
->perms
|= map_nt_perms( psa
->info
, S_IRUSR
);
1399 current_ace
->attr
= (psa
->type
== SEC_ACE_TYPE_ACCESS_ALLOWED
) ? ALLOW_ACE
: DENY_ACE
;
1400 current_ace
->inherited
= ((psa
->flags
& SEC_ACE_FLAG_INHERITED_ACE
) ? True
: False
);
1403 * Now add the created ace to either the file list, the directory
1404 * list, or both. We *MUST* preserve the order here (hence we use
1405 * DLIST_ADD_END) as NT ACLs are order dependent.
1408 if (fsp
->is_directory
) {
1411 * We can only add to the default POSIX ACE list if the ACE is
1412 * designed to be inherited by both files and directories.
1415 if ((psa
->flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|SEC_ACE_FLAG_CONTAINER_INHERIT
)) ==
1416 (SEC_ACE_FLAG_OBJECT_INHERIT
|SEC_ACE_FLAG_CONTAINER_INHERIT
)) {
1418 DLIST_ADD_END(dir_ace
, current_ace
, tmp_ace
);
1421 * Note if this was an allow ace. We can't process
1422 * any further deny ace's after this.
1425 if (current_ace
->attr
== ALLOW_ACE
)
1426 got_dir_allow
= True
;
1428 if ((current_ace
->attr
== DENY_ACE
) && got_dir_allow
) {
1429 DEBUG(0,("create_canon_ace_lists: malformed ACL in inheritable ACL ! \
1430 Deny entry after Allow entry. Failing to set on file %s.\n", fsp
->fsp_name
));
1431 free_canon_ace_list(file_ace
);
1432 free_canon_ace_list(dir_ace
);
1433 SAFE_FREE(current_ace
);
1437 if( DEBUGLVL( 10 )) {
1438 dbgtext("create_canon_ace_lists: adding dir ACL:\n");
1439 print_canon_ace( current_ace
, 0);
1443 * If this is not an inherit only ACE we need to add a duplicate
1447 if (!(psa
->flags
& SEC_ACE_FLAG_INHERIT_ONLY
)) {
1448 canon_ace
*dup_ace
= dup_canon_ace(current_ace
);
1451 DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
1452 free_canon_ace_list(file_ace
);
1453 free_canon_ace_list(dir_ace
);
1458 * We must not free current_ace here as its
1459 * pointer is now owned by the dir_ace list.
1461 current_ace
= dup_ace
;
1464 * We must not free current_ace here as its
1465 * pointer is now owned by the dir_ace list.
1473 * Only add to the file ACL if not inherit only.
1476 if (!(psa
->flags
& SEC_ACE_FLAG_INHERIT_ONLY
)) {
1477 DLIST_ADD_END(file_ace
, current_ace
, tmp_ace
);
1480 * Note if this was an allow ace. We can't process
1481 * any further deny ace's after this.
1484 if (current_ace
->attr
== ALLOW_ACE
)
1485 got_file_allow
= True
;
1487 if ((current_ace
->attr
== DENY_ACE
) && got_file_allow
) {
1488 DEBUG(0,("create_canon_ace_lists: malformed ACL in file ACL ! \
1489 Deny entry after Allow entry. Failing to set on file %s.\n", fsp
->fsp_name
));
1490 free_canon_ace_list(file_ace
);
1491 free_canon_ace_list(dir_ace
);
1492 SAFE_FREE(current_ace
);
1496 if( DEBUGLVL( 10 )) {
1497 dbgtext("create_canon_ace_lists: adding file ACL:\n");
1498 print_canon_ace( current_ace
, 0);
1500 all_aces_are_inherit_only
= False
;
1502 * We must not free current_ace here as its
1503 * pointer is now owned by the file_ace list.
1509 * Free if ACE was not added.
1512 SAFE_FREE(current_ace
);
1515 if (fsp
->is_directory
&& all_aces_are_inherit_only
) {
1517 * Windows 2000 is doing one of these weird 'inherit acl'
1518 * traverses to conserve NTFS ACL resources. Just pretend
1519 * there was no DACL sent. JRA.
1522 DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n"));
1523 free_canon_ace_list(file_ace
);
1524 free_canon_ace_list(dir_ace
);
1529 * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in each
1530 * ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP
1531 * entries can be converted to *_OBJ. Usually we will already have these
1532 * entries in the Default ACL, and the Access ACL will not have them.
1534 check_owning_objs(file_ace
, pfile_owner_sid
, pfile_grp_sid
);
1535 check_owning_objs(dir_ace
, pfile_owner_sid
, pfile_grp_sid
);
1538 *ppfile_ace
= file_ace
;
1539 *ppdir_ace
= dir_ace
;
1544 /****************************************************************************
1545 ASCII art time again... JRA :-).
1547 We have 4 cases to process when moving from an NT ACL to a POSIX ACL. Firstly,
1548 we insist the ACL is in canonical form (ie. all DENY entries preceede ALLOW
1549 entries). Secondly, the merge code has ensured that all duplicate SID entries for
1550 allow or deny have been merged, so the same SID can only appear once in the deny
1551 list or once in the allow list.
1553 We then process as follows :
1555 ---------------------------------------------------------------------------
1556 First pass - look for a Everyone DENY entry.
1558 If it is deny all (rwx) trunate the list at this point.
1559 Else, walk the list from this point and use the deny permissions of this
1560 entry as a mask on all following allow entries. Finally, delete
1561 the Everyone DENY entry (we have applied it to everything possible).
1563 In addition, in this pass we remove any DENY entries that have
1564 no permissions (ie. they are a DENY nothing).
1565 ---------------------------------------------------------------------------
1566 Second pass - only deal with deny user entries.
1568 DENY user1 (perms XXX)
1571 for all following allow group entries where user1 is in group
1572 new_perms |= group_perms;
1574 user1 entry perms = new_perms & ~ XXX;
1576 Convert the deny entry to an allow entry with the new perms and
1577 push to the end of the list. Note if the user was in no groups
1578 this maps to a specific allow nothing entry for this user.
1580 The common case from the NT ACL choser (userX deny all) is
1581 optimised so we don't do the group lookup - we just map to
1582 an allow nothing entry.
1584 What we're doing here is inferring the allow permissions the
1585 person setting the ACE on user1 wanted by looking at the allow
1586 permissions on the groups the user is currently in. This will
1587 be a snapshot, depending on group membership but is the best
1588 we can do and has the advantage of failing closed rather than
1590 ---------------------------------------------------------------------------
1591 Third pass - only deal with deny group entries.
1593 DENY group1 (perms XXX)
1595 for all following allow user entries where user is in group1
1596 user entry perms = user entry perms & ~ XXX;
1598 If there is a group Everyone allow entry with permissions YYY,
1599 convert the group1 entry to an allow entry and modify its
1602 new_perms = YYY & ~ XXX
1604 and push to the end of the list.
1606 If there is no group Everyone allow entry then convert the
1607 group1 entry to a allow nothing entry and push to the end of the list.
1609 Note that the common case from the NT ACL choser (groupX deny all)
1610 cannot be optimised here as we need to modify user entries who are
1611 in the group to change them to a deny all also.
1613 What we're doing here is modifying the allow permissions of
1614 user entries (which are more specific in POSIX ACLs) to mask
1615 out the explicit deny set on the group they are in. This will
1616 be a snapshot depending on current group membership but is the
1617 best we can do and has the advantage of failing closed rather
1619 ---------------------------------------------------------------------------
1620 Fourth pass - cope with cumulative permissions.
1622 for all allow user entries, if there exists an allow group entry with
1623 more permissive permissions, and the user is in that group, rewrite the
1624 allow user permissions to contain both sets of permissions.
1626 Currently the code for this is #ifdef'ed out as these semantics make
1627 no sense to me. JRA.
1628 ---------------------------------------------------------------------------
1630 Note we *MUST* do the deny user pass first as this will convert deny user
1631 entries into allow user entries which can then be processed by the deny
1634 The above algorithm took a *lot* of thinking about - hence this
1635 explaination :-). JRA.
1636 ****************************************************************************/
1638 /****************************************************************************
1639 Process a canon_ace list entries. This is very complex code. We need
1640 to go through and remove the "deny" permissions from any allow entry that matches
1641 the id of this entry. We have already refused any NT ACL that wasn't in correct
1642 order (DENY followed by ALLOW). If any allow entry ends up with zero permissions,
1643 we just remove it (to fail safe). We have already removed any duplicate ace
1644 entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all
1646 ****************************************************************************/
1648 static void process_deny_list( canon_ace
**pp_ace_list
)
1650 extern DOM_SID global_sid_World
;
1651 canon_ace
*ace_list
= *pp_ace_list
;
1652 canon_ace
*curr_ace
= NULL
;
1653 canon_ace
*curr_ace_next
= NULL
;
1655 /* Pass 1 above - look for an Everyone, deny entry. */
1657 for (curr_ace
= ace_list
; curr_ace
; curr_ace
= curr_ace_next
) {
1658 canon_ace
*allow_ace_p
;
1660 curr_ace_next
= curr_ace
->next
; /* So we can't lose the link. */
1662 if (curr_ace
->attr
!= DENY_ACE
)
1665 if (curr_ace
->perms
== (mode_t
)0) {
1667 /* Deny nothing entry - delete. */
1669 DLIST_REMOVE(ace_list
, curr_ace
);
1673 if (!sid_equal(&curr_ace
->trustee
, &global_sid_World
))
1676 /* JRATEST - assert. */
1677 SMB_ASSERT(curr_ace
->owner_type
== WORLD_ACE
);
1679 if (curr_ace
->perms
== ALL_ACE_PERMS
) {
1682 * Optimisation. This is a DENY_ALL to Everyone. Truncate the
1683 * list at this point including this entry.
1686 canon_ace
*prev_entry
= curr_ace
->prev
;
1688 free_canon_ace_list( curr_ace
);
1690 prev_entry
->next
= NULL
;
1692 /* We deleted the entire list. */
1698 for (allow_ace_p
= curr_ace
->next
; allow_ace_p
; allow_ace_p
= allow_ace_p
->next
) {
1701 * Only mask off allow entries.
1704 if (allow_ace_p
->attr
!= ALLOW_ACE
)
1707 allow_ace_p
->perms
&= ~curr_ace
->perms
;
1711 * Now it's been applied, remove it.
1714 DLIST_REMOVE(ace_list
, curr_ace
);
1717 /* Pass 2 above - deal with deny user entries. */
1719 for (curr_ace
= ace_list
; curr_ace
; curr_ace
= curr_ace_next
) {
1720 mode_t new_perms
= (mode_t
)0;
1721 canon_ace
*allow_ace_p
;
1724 curr_ace_next
= curr_ace
->next
; /* So we can't lose the link. */
1726 if (curr_ace
->attr
!= DENY_ACE
)
1729 if (curr_ace
->owner_type
!= UID_ACE
)
1732 if (curr_ace
->perms
== ALL_ACE_PERMS
) {
1735 * Optimisation - this is a deny everything to this user.
1736 * Convert to an allow nothing and push to the end of the list.
1739 curr_ace
->attr
= ALLOW_ACE
;
1740 curr_ace
->perms
= (mode_t
)0;
1741 DLIST_DEMOTE(ace_list
, curr_ace
, tmp_ace
);
1745 for (allow_ace_p
= curr_ace
->next
; allow_ace_p
; allow_ace_p
= allow_ace_p
->next
) {
1747 if (allow_ace_p
->attr
!= ALLOW_ACE
)
1750 /* We process GID_ACE and WORLD_ACE entries only. */
1752 if (allow_ace_p
->owner_type
== UID_ACE
)
1755 if (uid_entry_in_group( curr_ace
, allow_ace_p
))
1756 new_perms
|= allow_ace_p
->perms
;
1760 * Convert to a allow entry, modify the perms and push to the end
1764 curr_ace
->attr
= ALLOW_ACE
;
1765 curr_ace
->perms
= (new_perms
& ~curr_ace
->perms
);
1766 DLIST_DEMOTE(ace_list
, curr_ace
, tmp_ace
);
1769 /* Pass 3 above - deal with deny group entries. */
1771 for (curr_ace
= ace_list
; curr_ace
; curr_ace
= curr_ace_next
) {
1773 canon_ace
*allow_ace_p
;
1774 canon_ace
*allow_everyone_p
= NULL
;
1776 curr_ace_next
= curr_ace
->next
; /* So we can't lose the link. */
1778 if (curr_ace
->attr
!= DENY_ACE
)
1781 if (curr_ace
->owner_type
!= GID_ACE
)
1784 for (allow_ace_p
= curr_ace
->next
; allow_ace_p
; allow_ace_p
= allow_ace_p
->next
) {
1786 if (allow_ace_p
->attr
!= ALLOW_ACE
)
1789 /* Store a pointer to the Everyone allow, if it exists. */
1790 if (allow_ace_p
->owner_type
== WORLD_ACE
)
1791 allow_everyone_p
= allow_ace_p
;
1793 /* We process UID_ACE entries only. */
1795 if (allow_ace_p
->owner_type
!= UID_ACE
)
1798 /* Mask off the deny group perms. */
1800 if (uid_entry_in_group( allow_ace_p
, curr_ace
))
1801 allow_ace_p
->perms
&= ~curr_ace
->perms
;
1805 * Convert the deny to an allow with the correct perms and
1806 * push to the end of the list.
1809 curr_ace
->attr
= ALLOW_ACE
;
1810 if (allow_everyone_p
)
1811 curr_ace
->perms
= allow_everyone_p
->perms
& ~curr_ace
->perms
;
1813 curr_ace
->perms
= (mode_t
)0;
1814 DLIST_DEMOTE(ace_list
, curr_ace
, tmp_ace
);
1818 /* Doing this fourth pass allows Windows semantics to be layered
1819 * on top of POSIX semantics. I'm not sure if this is desirable.
1820 * For example, in W2K ACLs there is no way to say, "Group X no
1821 * access, user Y full access" if user Y is a member of group X.
1822 * This seems completely broken semantics to me.... JRA.
1826 /* Pass 4 above - deal with allow entries. */
1828 for (curr_ace
= ace_list
; curr_ace
; curr_ace
= curr_ace_next
) {
1829 canon_ace
*allow_ace_p
;
1831 curr_ace_next
= curr_ace
->next
; /* So we can't lose the link. */
1833 if (curr_ace
->attr
!= ALLOW_ACE
)
1836 if (curr_ace
->owner_type
!= UID_ACE
)
1839 for (allow_ace_p
= ace_list
; allow_ace_p
; allow_ace_p
= allow_ace_p
->next
) {
1841 if (allow_ace_p
->attr
!= ALLOW_ACE
)
1844 /* We process GID_ACE entries only. */
1846 if (allow_ace_p
->owner_type
!= GID_ACE
)
1849 /* OR in the group perms. */
1851 if (uid_entry_in_group( curr_ace
, allow_ace_p
))
1852 curr_ace
->perms
|= allow_ace_p
->perms
;
1857 *pp_ace_list
= ace_list
;
1860 /****************************************************************************
1861 Create a default mode that will be used if a security descriptor entry has
1862 no user/group/world entries.
1863 ****************************************************************************/
1865 static mode_t
create_default_mode(files_struct
*fsp
, BOOL interitable_mode
)
1867 int snum
= SNUM(fsp
->conn
);
1868 mode_t and_bits
= (mode_t
)0;
1869 mode_t or_bits
= (mode_t
)0;
1870 mode_t mode
= interitable_mode
? unix_mode( fsp
->conn
, FILE_ATTRIBUTE_ARCHIVE
, fsp
->fsp_name
) : S_IRUSR
;
1872 if (fsp
->is_directory
)
1873 mode
|= (S_IWUSR
|S_IXUSR
);
1876 * Now AND with the create mode/directory mode bits then OR with the
1877 * force create mode/force directory mode bits.
1880 if (fsp
->is_directory
) {
1881 and_bits
= lp_dir_security_mask(snum
);
1882 or_bits
= lp_force_dir_security_mode(snum
);
1884 and_bits
= lp_security_mask(snum
);
1885 or_bits
= lp_force_security_mode(snum
);
1888 return ((mode
& and_bits
)|or_bits
);
1891 /****************************************************************************
1892 Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
1894 ****************************************************************************/
1896 static BOOL
unpack_canon_ace(files_struct
*fsp
,
1897 SMB_STRUCT_STAT
*pst
,
1898 DOM_SID
*pfile_owner_sid
,
1899 DOM_SID
*pfile_grp_sid
,
1900 canon_ace
**ppfile_ace
, canon_ace
**ppdir_ace
,
1901 uint32 security_info_sent
, SEC_DESC
*psd
)
1903 canon_ace
*file_ace
= NULL
;
1904 canon_ace
*dir_ace
= NULL
;
1909 if(security_info_sent
== 0) {
1910 DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
1915 * If no DACL then this is a chown only security descriptor.
1918 if(!(security_info_sent
& DACL_SECURITY_INFORMATION
) || !psd
->dacl
)
1922 * Now go through the DACL and create the canon_ace lists.
1925 if (!create_canon_ace_lists( fsp
, pst
, pfile_owner_sid
, pfile_grp_sid
,
1926 &file_ace
, &dir_ace
, psd
->dacl
))
1929 if ((file_ace
== NULL
) && (dir_ace
== NULL
)) {
1930 /* W2K traverse DACL set - ignore. */
1935 * Go through the canon_ace list and merge entries
1936 * belonging to identical users of identical allow or deny type.
1937 * We can do this as all deny entries come first, followed by
1938 * all allow entries (we have mandated this before accepting this acl).
1941 print_canon_ace_list( "file ace - before merge", file_ace
);
1942 merge_aces( &file_ace
);
1944 print_canon_ace_list( "dir ace - before merge", dir_ace
);
1945 merge_aces( &dir_ace
);
1948 * NT ACLs are order dependent. Go through the acl lists and
1949 * process DENY entries by masking the allow entries.
1952 print_canon_ace_list( "file ace - before deny", file_ace
);
1953 process_deny_list( &file_ace
);
1955 print_canon_ace_list( "dir ace - before deny", dir_ace
);
1956 process_deny_list( &dir_ace
);
1959 * A well formed POSIX file or default ACL has at least 3 entries, a
1960 * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
1961 * and optionally a mask entry. Ensure this is the case.
1964 print_canon_ace_list( "file ace - before valid", file_ace
);
1967 * A default 3 element mode entry for a file should be r-- --- ---.
1968 * A default 3 element mode entry for a directory should be rwx --- ---.
1971 pst
->st_mode
= create_default_mode(fsp
, False
);
1973 if (!ensure_canon_entry_valid(&file_ace
, fsp
, pfile_owner_sid
, pfile_grp_sid
, pst
, True
)) {
1974 free_canon_ace_list(file_ace
);
1975 free_canon_ace_list(dir_ace
);
1979 print_canon_ace_list( "dir ace - before valid", dir_ace
);
1982 * A default inheritable 3 element mode entry for a directory should be the
1983 * mode Samba will use to create a file within. Ensure user rwx bits are set if
1987 pst
->st_mode
= create_default_mode(fsp
, True
);
1989 if (dir_ace
&& !ensure_canon_entry_valid(&dir_ace
, fsp
, pfile_owner_sid
, pfile_grp_sid
, pst
, True
)) {
1990 free_canon_ace_list(file_ace
);
1991 free_canon_ace_list(dir_ace
);
1995 print_canon_ace_list( "file ace - return", file_ace
);
1996 print_canon_ace_list( "dir ace - return", dir_ace
);
1998 *ppfile_ace
= file_ace
;
1999 *ppdir_ace
= dir_ace
;
2004 /******************************************************************************
2005 When returning permissions, try and fit NT display
2006 semantics if possible. Note the the canon_entries here must have been malloced.
2007 The list format should be - first entry = owner, followed by group and other user
2008 entries, last entry = other.
2010 Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries
2011 are not ordered, and match on the most specific entry rather than walking a list,
2012 then a simple POSIX permission of rw-r--r-- should really map to 5 entries,
2014 Entry 0: owner : deny all except read and write.
2015 Entry 1: group : deny all except read.
2016 Entry 2: owner : allow read and write.
2017 Entry 3: group : allow read.
2018 Entry 4: Everyone : allow read.
2020 But NT cannot display this in their ACL editor !
2021 ********************************************************************************/
2023 static void arrange_posix_perms( char *filename
, canon_ace
**pp_list_head
)
2025 canon_ace
*list_head
= *pp_list_head
;
2026 canon_ace
*owner_ace
= NULL
;
2027 canon_ace
*other_ace
= NULL
;
2028 canon_ace
*ace
= NULL
;
2030 for (ace
= list_head
; ace
; ace
= ace
->next
) {
2031 if (ace
->type
== SMB_ACL_USER_OBJ
)
2033 else if (ace
->type
== SMB_ACL_OTHER
) {
2034 /* Last ace - this is "other" */
2039 if (!owner_ace
|| !other_ace
) {
2040 DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n",
2046 * The POSIX algorithm applies to owner first, and other last,
2047 * so ensure they are arranged in this order.
2051 DLIST_PROMOTE(list_head
, owner_ace
);
2055 DLIST_DEMOTE(list_head
, other_ace
, ace
);
2058 /* We have probably changed the head of the list. */
2060 *pp_list_head
= list_head
;
2063 /****************************************************************************
2064 Create a linked list of canonical ACE entries.
2065 ****************************************************************************/
2067 static canon_ace
*canonicalise_acl( files_struct
*fsp
, SMB_ACL_T posix_acl
, SMB_STRUCT_STAT
*psbuf
,
2068 DOM_SID
*powner
, DOM_SID
*pgroup
, struct pai_val
*pal
, SMB_ACL_TYPE_T the_acl_type
)
2070 extern DOM_SID global_sid_World
;
2071 connection_struct
*conn
= fsp
->conn
;
2072 mode_t acl_mask
= (S_IRUSR
|S_IWUSR
|S_IXUSR
);
2073 canon_ace
*list_head
= NULL
;
2074 canon_ace
*ace
= NULL
;
2075 canon_ace
*next_ace
= NULL
;
2076 int entry_id
= SMB_ACL_FIRST_ENTRY
;
2077 SMB_ACL_ENTRY_T entry
;
2080 while ( posix_acl
&& (SMB_VFS_SYS_ACL_GET_ENTRY(conn
, posix_acl
, entry_id
, &entry
) == 1)) {
2081 SMB_ACL_TAG_T tagtype
;
2082 SMB_ACL_PERMSET_T permset
;
2085 enum ace_owner owner_type
;
2088 if (entry_id
== SMB_ACL_FIRST_ENTRY
)
2089 entry_id
= SMB_ACL_NEXT_ENTRY
;
2091 /* Is this a MASK entry ? */
2092 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn
, entry
, &tagtype
) == -1)
2095 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn
, entry
, &permset
) == -1)
2098 /* Decide which SID to use based on the ACL type. */
2100 case SMB_ACL_USER_OBJ
:
2101 /* Get the SID from the owner. */
2102 sid_copy(&sid
, powner
);
2103 unix_ug
.uid
= psbuf
->st_uid
;
2104 owner_type
= UID_ACE
;
2108 uid_t
*puid
= (uid_t
*)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn
, entry
);
2110 DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
2114 * A SMB_ACL_USER entry for the owner is shadowed by the
2115 * SMB_ACL_USER_OBJ entry and Windows also cannot represent
2116 * that entry, so we ignore it. We also don't create such
2117 * entries out of the blue when setting ACLs, so a get/set
2118 * cycle will drop them.
2120 if (the_acl_type
== SMB_ACL_TYPE_ACCESS
&& *puid
== psbuf
->st_uid
) {
2121 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn
, (void *)puid
,tagtype
);
2124 uid_to_sid( &sid
, *puid
);
2125 unix_ug
.uid
= *puid
;
2126 owner_type
= UID_ACE
;
2127 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn
, (void *)puid
,tagtype
);
2130 case SMB_ACL_GROUP_OBJ
:
2131 /* Get the SID from the owning group. */
2132 sid_copy(&sid
, pgroup
);
2133 unix_ug
.gid
= psbuf
->st_gid
;
2134 owner_type
= GID_ACE
;
2138 gid_t
*pgid
= (gid_t
*)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn
, entry
);
2140 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
2143 gid_to_sid( &sid
, *pgid
);
2144 unix_ug
.gid
= *pgid
;
2145 owner_type
= GID_ACE
;
2146 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn
, (void *)pgid
,tagtype
);
2150 acl_mask
= convert_permset_to_mode_t(conn
, permset
);
2151 continue; /* Don't count the mask as an entry. */
2153 /* Use the Everyone SID */
2154 sid
= global_sid_World
;
2156 owner_type
= WORLD_ACE
;
2159 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype
));
2164 * Add this entry to the list.
2167 if ((ace
= SMB_MALLOC_P(canon_ace
)) == NULL
)
2171 ace
->type
= tagtype
;
2172 ace
->perms
= convert_permset_to_mode_t(conn
, permset
);
2173 ace
->attr
= ALLOW_ACE
;
2175 ace
->unix_ug
= unix_ug
;
2176 ace
->owner_type
= owner_type
;
2177 ace
->inherited
= get_inherited_flag(pal
, ace
, (the_acl_type
== SMB_ACL_TYPE_DEFAULT
));
2179 DLIST_ADD(list_head
, ace
);
2183 * This next call will ensure we have at least a user/group/world set.
2186 if (!ensure_canon_entry_valid(&list_head
, fsp
, powner
, pgroup
, psbuf
, False
))
2190 * Now go through the list, masking the permissions with the
2191 * acl_mask. Ensure all DENY Entries are at the start of the list.
2194 DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", the_acl_type
== SMB_ACL_TYPE_ACCESS
? "Access" : "Default" ));
2196 for ( ace_count
= 0, ace
= list_head
; ace
; ace
= next_ace
, ace_count
++) {
2197 next_ace
= ace
->next
;
2199 /* Masks are only applied to entries other than USER_OBJ and OTHER. */
2200 if (ace
->type
!= SMB_ACL_OTHER
&& ace
->type
!= SMB_ACL_USER_OBJ
)
2201 ace
->perms
&= acl_mask
;
2203 if (ace
->perms
== 0) {
2204 DLIST_PROMOTE(list_head
, ace
);
2207 if( DEBUGLVL( 10 ) ) {
2208 print_canon_ace(ace
, ace_count
);
2212 arrange_posix_perms(fsp
->fsp_name
,&list_head
);
2214 print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head
);
2220 free_canon_ace_list(list_head
);
2224 /****************************************************************************
2225 Attempt to apply an ACL to a file or directory.
2226 ****************************************************************************/
2228 static BOOL
set_canon_ace_list(files_struct
*fsp
, canon_ace
*the_ace
, BOOL default_ace
, BOOL
*pacl_set_support
)
2230 connection_struct
*conn
= fsp
->conn
;
2232 SMB_ACL_T the_acl
= SMB_VFS_SYS_ACL_INIT(conn
, (int)count_canon_ace_list(the_ace
) + 1);
2235 SMB_ACL_ENTRY_T mask_entry
;
2236 BOOL got_mask_entry
= False
;
2237 SMB_ACL_PERMSET_T mask_permset
;
2238 SMB_ACL_TYPE_T the_acl_type
= (default_ace
? SMB_ACL_TYPE_DEFAULT
: SMB_ACL_TYPE_ACCESS
);
2239 BOOL needs_mask
= False
;
2240 mode_t mask_perms
= 0;
2242 #if defined(POSIX_ACL_NEEDS_MASK)
2243 /* HP-UX always wants to have a mask (called "class" there). */
2247 if (the_acl
== NULL
) {
2249 if (!no_acl_syscall_error(errno
)) {
2251 * Only print this error message if we have some kind of ACL
2252 * support that's not working. Otherwise we would always get this.
2254 DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
2255 default_ace
? "default" : "file", strerror(errno
) ));
2257 *pacl_set_support
= False
;
2261 if( DEBUGLVL( 10 )) {
2262 dbgtext("set_canon_ace_list: setting ACL:\n");
2263 for (i
= 0, p_ace
= the_ace
; p_ace
; p_ace
= p_ace
->next
, i
++ ) {
2264 print_canon_ace( p_ace
, i
);
2268 for (i
= 0, p_ace
= the_ace
; p_ace
; p_ace
= p_ace
->next
, i
++ ) {
2269 SMB_ACL_ENTRY_T the_entry
;
2270 SMB_ACL_PERMSET_T the_permset
;
2273 * ACLs only "need" an ACL_MASK entry if there are any named user or
2274 * named group entries. But if there is an ACL_MASK entry, it applies
2275 * to ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. Set the mask
2276 * so that it doesn't deny (i.e., mask off) any permissions.
2279 if (p_ace
->type
== SMB_ACL_USER
|| p_ace
->type
== SMB_ACL_GROUP
) {
2281 mask_perms
|= p_ace
->perms
;
2282 } else if (p_ace
->type
== SMB_ACL_GROUP_OBJ
) {
2283 mask_perms
|= p_ace
->perms
;
2287 * Get the entry for this ACE.
2290 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn
, &the_acl
, &the_entry
) == -1) {
2291 DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
2292 i
, strerror(errno
) ));
2296 if (p_ace
->type
== SMB_ACL_MASK
) {
2297 mask_entry
= the_entry
;
2298 got_mask_entry
= True
;
2302 * Ok - we now know the ACL calls should be working, don't
2303 * allow fallback to chmod.
2306 *pacl_set_support
= True
;
2309 * Initialise the entry from the canon_ace.
2313 * First tell the entry what type of ACE this is.
2316 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn
, the_entry
, p_ace
->type
) == -1) {
2317 DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
2318 i
, strerror(errno
) ));
2323 * Only set the qualifier (user or group id) if the entry is a user
2327 if ((p_ace
->type
== SMB_ACL_USER
) || (p_ace
->type
== SMB_ACL_GROUP
)) {
2328 if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn
, the_entry
,(void *)&p_ace
->unix_ug
.uid
) == -1) {
2329 DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
2330 i
, strerror(errno
) ));
2336 * Convert the mode_t perms in the canon_ace to a POSIX permset.
2339 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn
, the_entry
, &the_permset
) == -1) {
2340 DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
2341 i
, strerror(errno
) ));
2345 if (map_acl_perms_to_permset(conn
, p_ace
->perms
, &the_permset
) == -1) {
2346 DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
2347 (unsigned int)p_ace
->perms
, i
, strerror(errno
) ));
2352 * ..and apply them to the entry.
2355 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn
, the_entry
, the_permset
) == -1) {
2356 DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
2357 i
, strerror(errno
) ));
2362 print_canon_ace( p_ace
, i
);
2366 if (needs_mask
&& !got_mask_entry
) {
2367 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn
, &the_acl
, &mask_entry
) == -1) {
2368 DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno
) ));
2372 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn
, mask_entry
, SMB_ACL_MASK
) == -1) {
2373 DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno
) ));
2377 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn
, mask_entry
, &mask_permset
) == -1) {
2378 DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno
) ));
2382 if (map_acl_perms_to_permset(conn
, S_IRUSR
|S_IWUSR
|S_IXUSR
, &mask_permset
) == -1) {
2383 DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno
) ));
2387 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn
, mask_entry
, mask_permset
) == -1) {
2388 DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno
) ));
2394 * Check if the ACL is valid.
2397 if (SMB_VFS_SYS_ACL_VALID(conn
, the_acl
) == -1) {
2398 DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n",
2399 the_acl_type
== SMB_ACL_TYPE_DEFAULT
? "directory default" : "file",
2405 * Finally apply it to the file or directory.
2408 if(default_ace
|| fsp
->is_directory
|| fsp
->fd
== -1) {
2409 if (SMB_VFS_SYS_ACL_SET_FILE(conn
, fsp
->fsp_name
, the_acl_type
, the_acl
) == -1) {
2411 * Some systems allow all the above calls and only fail with no ACL support
2412 * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2414 if (no_acl_syscall_error(errno
)) {
2415 *pacl_set_support
= False
;
2418 DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
2419 the_acl_type
== SMB_ACL_TYPE_DEFAULT
? "directory default" : "file",
2420 fsp
->fsp_name
, strerror(errno
) ));
2424 if (SMB_VFS_SYS_ACL_SET_FD(fsp
, fsp
->fd
, the_acl
) == -1) {
2426 * Some systems allow all the above calls and only fail with no ACL support
2427 * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2429 if (no_acl_syscall_error(errno
)) {
2430 *pacl_set_support
= False
;
2433 DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
2434 fsp
->fsp_name
, strerror(errno
) ));
2443 if (the_acl
!= NULL
)
2444 SMB_VFS_SYS_ACL_FREE_ACL(conn
, the_acl
);
2449 /****************************************************************************
2450 Find a particular canon_ace entry.
2451 ****************************************************************************/
2453 static struct canon_ace
*canon_ace_entry_for(struct canon_ace
*list
, SMB_ACL_TAG_T type
, posix_id
*id
)
2456 if (list
->type
== type
&& ((type
!= SMB_ACL_USER
&& type
!= SMB_ACL_GROUP
) ||
2457 (type
== SMB_ACL_USER
&& id
&& id
->uid
== list
->unix_ug
.uid
) ||
2458 (type
== SMB_ACL_GROUP
&& id
&& id
->gid
== list
->unix_ug
.gid
)))
2465 /****************************************************************************
2467 ****************************************************************************/
2469 SMB_ACL_T
free_empty_sys_acl(connection_struct
*conn
, SMB_ACL_T the_acl
)
2471 SMB_ACL_ENTRY_T entry
;
2475 if (SMB_VFS_SYS_ACL_GET_ENTRY(conn
, the_acl
, SMB_ACL_FIRST_ENTRY
, &entry
) != 1) {
2476 SMB_VFS_SYS_ACL_FREE_ACL(conn
, the_acl
);
2482 /****************************************************************************
2483 Convert a canon_ace to a generic 3 element permission - if possible.
2484 ****************************************************************************/
2486 #define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
2488 static BOOL
convert_canon_ace_to_posix_perms( files_struct
*fsp
, canon_ace
*file_ace_list
, mode_t
*posix_perms
)
2490 int snum
= SNUM(fsp
->conn
);
2491 size_t ace_count
= count_canon_ace_list(file_ace_list
);
2493 canon_ace
*owner_ace
= NULL
;
2494 canon_ace
*group_ace
= NULL
;
2495 canon_ace
*other_ace
= NULL
;
2499 if (ace_count
!= 3) {
2500 DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \
2501 posix perms.\n", fsp
->fsp_name
));
2505 for (ace_p
= file_ace_list
; ace_p
; ace_p
= ace_p
->next
) {
2506 if (ace_p
->owner_type
== UID_ACE
)
2508 else if (ace_p
->owner_type
== GID_ACE
)
2510 else if (ace_p
->owner_type
== WORLD_ACE
)
2514 if (!owner_ace
|| !group_ace
|| !other_ace
) {
2515 DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n",
2520 *posix_perms
= (mode_t
)0;
2522 *posix_perms
|= owner_ace
->perms
;
2523 *posix_perms
|= MAP_PERM(group_ace
->perms
, S_IRUSR
, S_IRGRP
);
2524 *posix_perms
|= MAP_PERM(group_ace
->perms
, S_IWUSR
, S_IWGRP
);
2525 *posix_perms
|= MAP_PERM(group_ace
->perms
, S_IXUSR
, S_IXGRP
);
2526 *posix_perms
|= MAP_PERM(other_ace
->perms
, S_IRUSR
, S_IROTH
);
2527 *posix_perms
|= MAP_PERM(other_ace
->perms
, S_IWUSR
, S_IWOTH
);
2528 *posix_perms
|= MAP_PERM(other_ace
->perms
, S_IXUSR
, S_IXOTH
);
2530 /* The owner must have at least read access. */
2532 *posix_perms
|= S_IRUSR
;
2533 if (fsp
->is_directory
)
2534 *posix_perms
|= (S_IWUSR
|S_IXUSR
);
2536 /* If requested apply the masks. */
2538 /* Get the initial bits to apply. */
2540 if (fsp
->is_directory
) {
2541 and_bits
= lp_dir_security_mask(snum
);
2542 or_bits
= lp_force_dir_security_mode(snum
);
2544 and_bits
= lp_security_mask(snum
);
2545 or_bits
= lp_force_security_mode(snum
);
2548 *posix_perms
= (((*posix_perms
) & and_bits
)|or_bits
);
2550 DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n",
2551 (int)owner_ace
->perms
, (int)group_ace
->perms
, (int)other_ace
->perms
, (int)*posix_perms
,
2557 /****************************************************************************
2558 Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and
2559 a normal POSIX acl. Win2k needs these split acls re-merging into one ACL
2560 with CI|OI set so it is inherited and also applies to the directory.
2561 Based on code from "Jim McDonough" <jmcd@us.ibm.com>.
2562 ****************************************************************************/
2564 static size_t merge_default_aces( SEC_ACE
*nt_ace_list
, size_t num_aces
)
2568 for (i
= 0; i
< num_aces
; i
++) {
2569 for (j
= i
+1; j
< num_aces
; j
++) {
2570 uint32 i_flags_ni
= (nt_ace_list
[i
].flags
& ~SEC_ACE_FLAG_INHERITED_ACE
);
2571 uint32 j_flags_ni
= (nt_ace_list
[j
].flags
& ~SEC_ACE_FLAG_INHERITED_ACE
);
2572 BOOL i_inh
= (nt_ace_list
[i
].flags
& SEC_ACE_FLAG_INHERITED_ACE
) ? True
: False
;
2573 BOOL j_inh
= (nt_ace_list
[j
].flags
& SEC_ACE_FLAG_INHERITED_ACE
) ? True
: False
;
2575 /* We know the lower number ACE's are file entries. */
2576 if ((nt_ace_list
[i
].type
== nt_ace_list
[j
].type
) &&
2577 (nt_ace_list
[i
].size
== nt_ace_list
[j
].size
) &&
2578 (nt_ace_list
[i
].info
.mask
== nt_ace_list
[j
].info
.mask
) &&
2579 sid_equal(&nt_ace_list
[i
].trustee
, &nt_ace_list
[j
].trustee
) &&
2581 (i_flags_ni
== 0) &&
2582 (j_flags_ni
== (SEC_ACE_FLAG_OBJECT_INHERIT
|
2583 SEC_ACE_FLAG_CONTAINER_INHERIT
|
2584 SEC_ACE_FLAG_INHERIT_ONLY
))) {
2586 * W2K wants to have access allowed zero access ACE's
2587 * at the end of the list. If the mask is zero, merge
2588 * the non-inherited ACE onto the inherited ACE.
2591 if (nt_ace_list
[i
].info
.mask
== 0) {
2592 nt_ace_list
[j
].flags
= SEC_ACE_FLAG_OBJECT_INHERIT
|SEC_ACE_FLAG_CONTAINER_INHERIT
|
2593 (i_inh
? SEC_ACE_FLAG_INHERITED_ACE
: 0);
2594 if (num_aces
- i
- 1 > 0)
2595 memmove(&nt_ace_list
[i
], &nt_ace_list
[i
+1], (num_aces
-i
-1) *
2598 DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n",
2599 (unsigned int)i
, (unsigned int)j
));
2602 * These are identical except for the flags.
2603 * Merge the inherited ACE onto the non-inherited ACE.
2606 nt_ace_list
[i
].flags
= SEC_ACE_FLAG_OBJECT_INHERIT
|SEC_ACE_FLAG_CONTAINER_INHERIT
|
2607 (i_inh
? SEC_ACE_FLAG_INHERITED_ACE
: 0);
2608 if (num_aces
- j
- 1 > 0)
2609 memmove(&nt_ace_list
[j
], &nt_ace_list
[j
+1], (num_aces
-j
-1) *
2612 DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n",
2613 (unsigned int)j
, (unsigned int)i
));
2623 /****************************************************************************
2624 Reply to query a security descriptor from an fsp. If it succeeds it allocates
2625 the space for the return elements and returns the size needed to return the
2626 security descriptor. This should be the only external function needed for
2627 the UNIX style get ACL.
2628 ****************************************************************************/
2630 size_t get_nt_acl(files_struct
*fsp
, uint32 security_info
, SEC_DESC
**ppdesc
)
2632 extern DOM_SID global_sid_Builtin_Administrators
;
2633 extern DOM_SID global_sid_Builtin_Users
;
2634 extern DOM_SID global_sid_Creator_Owner
;
2635 extern DOM_SID global_sid_Creator_Group
;
2636 connection_struct
*conn
= fsp
->conn
;
2637 SMB_STRUCT_STAT sbuf
;
2638 SEC_ACE
*nt_ace_list
= NULL
;
2642 SEC_ACL
*psa
= NULL
;
2643 size_t num_acls
= 0;
2644 size_t num_dir_acls
= 0;
2645 size_t num_aces
= 0;
2646 SMB_ACL_T posix_acl
= NULL
;
2647 SMB_ACL_T dir_acl
= NULL
;
2648 canon_ace
*file_ace
= NULL
;
2649 canon_ace
*dir_ace
= NULL
;
2650 size_t num_profile_acls
= 0;
2651 struct pai_val
*pal
= NULL
;
2652 SEC_DESC
*psd
= NULL
;
2656 DEBUG(10,("get_nt_acl: called for file %s\n", fsp
->fsp_name
));
2658 if(fsp
->is_directory
|| fsp
->fd
== -1) {
2660 /* Get the stat struct for the owner info. */
2661 if(SMB_VFS_STAT(fsp
->conn
,fsp
->fsp_name
, &sbuf
) != 0) {
2665 * Get the ACL from the path.
2668 posix_acl
= SMB_VFS_SYS_ACL_GET_FILE(conn
, fsp
->fsp_name
, SMB_ACL_TYPE_ACCESS
);
2671 * If it's a directory get the default POSIX ACL.
2674 if(fsp
->is_directory
) {
2675 dir_acl
= SMB_VFS_SYS_ACL_GET_FILE(conn
, fsp
->fsp_name
, SMB_ACL_TYPE_DEFAULT
);
2676 dir_acl
= free_empty_sys_acl(conn
, dir_acl
);
2681 /* Get the stat struct for the owner info. */
2682 if(SMB_VFS_FSTAT(fsp
,fsp
->fd
,&sbuf
) != 0) {
2686 * Get the ACL from the fd.
2688 posix_acl
= SMB_VFS_SYS_ACL_GET_FD(fsp
, fsp
->fd
);
2691 DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
2692 posix_acl
? "present" : "absent",
2693 dir_acl
? "present" : "absent" ));
2695 pal
= load_inherited_info(fsp
);
2698 * Get the owner, group and world SIDs.
2701 if (lp_profile_acls(SNUM(fsp
->conn
))) {
2702 /* For WXP SP1 the owner must be administrators. */
2703 sid_copy(&owner_sid
, &global_sid_Builtin_Administrators
);
2704 sid_copy(&group_sid
, &global_sid_Builtin_Users
);
2705 num_profile_acls
= 2;
2707 create_file_sids(&sbuf
, &owner_sid
, &group_sid
);
2710 if ((security_info
& DACL_SECURITY_INFORMATION
) && !(security_info
& PROTECTED_DACL_SECURITY_INFORMATION
)) {
2713 * In the optimum case Creator Owner and Creator Group would be used for
2714 * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this
2715 * would lead to usability problems under Windows: The Creator entries
2716 * are only available in browse lists of directories and not for files;
2717 * additionally the identity of the owning group couldn't be determined.
2718 * We therefore use those identities only for Default ACLs.
2721 /* Create the canon_ace lists. */
2722 file_ace
= canonicalise_acl( fsp
, posix_acl
, &sbuf
, &owner_sid
, &group_sid
, pal
, SMB_ACL_TYPE_ACCESS
);
2724 /* We must have *some* ACLS. */
2726 if (count_canon_ace_list(file_ace
) == 0) {
2727 DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp
->fsp_name
));
2731 if (fsp
->is_directory
&& dir_acl
) {
2732 dir_ace
= canonicalise_acl(fsp
, dir_acl
, &sbuf
,
2733 &global_sid_Creator_Owner
,
2734 &global_sid_Creator_Group
, pal
, SMB_ACL_TYPE_DEFAULT
);
2738 * Create the NT ACE list from the canonical ace lists.
2746 if (nt4_compatible_acls() && dir_ace
) {
2748 * NT 4 chokes if an ACL contains an INHERIT_ONLY entry
2749 * but no non-INHERIT_ONLY entry for one SID. So we only
2750 * remove entries from the Access ACL if the
2751 * corresponding Default ACL entries have also been
2752 * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP
2753 * are exceptions. We can do nothing
2754 * intelligent if the Default ACL contains entries that
2755 * are not also contained in the Access ACL, so this
2756 * case will still fail under NT 4.
2759 ace
= canon_ace_entry_for(dir_ace
, SMB_ACL_OTHER
, NULL
);
2760 if (ace
&& !ace
->perms
) {
2761 DLIST_REMOVE(dir_ace
, ace
);
2764 ace
= canon_ace_entry_for(file_ace
, SMB_ACL_OTHER
, NULL
);
2765 if (ace
&& !ace
->perms
) {
2766 DLIST_REMOVE(file_ace
, ace
);
2772 * WinNT doesn't usually have Creator Group
2773 * in browse lists, so we send this entry to
2774 * WinNT even if it contains no relevant
2775 * permissions. Once we can add
2776 * Creator Group to browse lists we can
2781 ace
= canon_ace_entry_for(dir_ace
, SMB_ACL_GROUP_OBJ
, NULL
);
2782 if (ace
&& !ace
->perms
) {
2783 DLIST_REMOVE(dir_ace
, ace
);
2788 ace
= canon_ace_entry_for(file_ace
, SMB_ACL_GROUP_OBJ
, NULL
);
2789 if (ace
&& !ace
->perms
) {
2790 DLIST_REMOVE(file_ace
, ace
);
2795 num_acls
= count_canon_ace_list(file_ace
);
2796 num_dir_acls
= count_canon_ace_list(dir_ace
);
2798 /* Allocate the ace list. */
2799 if ((nt_ace_list
= SMB_MALLOC_ARRAY(SEC_ACE
, num_acls
+ num_profile_acls
+ num_dir_acls
)) == NULL
) {
2800 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
2804 memset(nt_ace_list
, '\0', (num_acls
+ num_dir_acls
) * sizeof(SEC_ACE
) );
2807 * Create the NT ACE list from the canonical ace lists.
2812 for (i
= 0; i
< num_acls
; i
++, ace
= ace
->next
) {
2815 acc
= map_canon_ace_perms(&nt_acl_type
, &owner_sid
, ace
);
2816 init_sec_ace(&nt_ace_list
[num_aces
++], &ace
->trustee
, nt_acl_type
, acc
, ace
->inherited
? SEC_ACE_FLAG_INHERITED_ACE
: 0);
2819 /* The User must have access to a profile share - even if we can't map the SID. */
2820 if (lp_profile_acls(SNUM(fsp
->conn
))) {
2823 init_sec_access(&acc
,FILE_GENERIC_ALL
);
2824 init_sec_ace(&nt_ace_list
[num_aces
++], &global_sid_Builtin_Users
, SEC_ACE_TYPE_ACCESS_ALLOWED
,
2830 for (i
= 0; i
< num_dir_acls
; i
++, ace
= ace
->next
) {
2833 acc
= map_canon_ace_perms(&nt_acl_type
, &owner_sid
, ace
);
2834 init_sec_ace(&nt_ace_list
[num_aces
++], &ace
->trustee
, nt_acl_type
, acc
,
2835 SEC_ACE_FLAG_OBJECT_INHERIT
|SEC_ACE_FLAG_CONTAINER_INHERIT
|
2836 SEC_ACE_FLAG_INHERIT_ONLY
|
2837 (ace
->inherited
? SEC_ACE_FLAG_INHERITED_ACE
: 0));
2840 /* The User must have access to a profile share - even if we can't map the SID. */
2841 if (lp_profile_acls(SNUM(fsp
->conn
))) {
2844 init_sec_access(&acc
,FILE_GENERIC_ALL
);
2845 init_sec_ace(&nt_ace_list
[num_aces
++], &global_sid_Builtin_Users
, SEC_ACE_TYPE_ACCESS_ALLOWED
, acc
,
2846 SEC_ACE_FLAG_OBJECT_INHERIT
|SEC_ACE_FLAG_CONTAINER_INHERIT
|
2847 SEC_ACE_FLAG_INHERIT_ONLY
|0);
2851 * Merge POSIX default ACLs and normal ACLs into one NT ACE.
2852 * Win2K needs this to get the inheritance correct when replacing ACLs
2853 * on a directory tree. Based on work by Jim @ IBM.
2856 num_aces
= merge_default_aces(nt_ace_list
, num_aces
);
2861 if((psa
= make_sec_acl( main_loop_talloc_get(), NT4_ACL_REVISION
, num_aces
, nt_ace_list
)) == NULL
) {
2862 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
2866 } /* security_info & DACL_SECURITY_INFORMATION */
2868 psd
= make_standard_sec_desc( main_loop_talloc_get(),
2869 (security_info
& OWNER_SECURITY_INFORMATION
) ? &owner_sid
: NULL
,
2870 (security_info
& GROUP_SECURITY_INFORMATION
) ? &group_sid
: NULL
,
2875 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
2879 * Windows 2000: The DACL_PROTECTED flag in the security
2880 * descriptor marks the ACL as non-inheriting, i.e., no
2881 * ACEs from higher level directories propagate to this
2882 * ACL. In the POSIX ACL model permissions are only
2883 * inherited at file create time, so ACLs never contain
2884 * any ACEs that are inherited dynamically. The DACL_PROTECTED
2885 * flag doesn't seem to bother Windows NT.
2887 if (get_protected_flag(pal
))
2888 psd
->type
|= SE_DESC_DACL_PROTECTED
;
2892 dacl_sort_into_canonical_order(psd
->dacl
->ace
, (unsigned int)psd
->dacl
->num_aces
);
2899 SMB_VFS_SYS_ACL_FREE_ACL(conn
, posix_acl
);
2901 SMB_VFS_SYS_ACL_FREE_ACL(conn
, dir_acl
);
2902 free_canon_ace_list(file_ace
);
2903 free_canon_ace_list(dir_ace
);
2904 free_inherited_info(pal
);
2905 SAFE_FREE(nt_ace_list
);
2910 /****************************************************************************
2911 Try to chown a file. We will be able to chown it under the following conditions.
2913 1) If we have root privileges, then it will just work.
2914 2) If we have write permission to the file and dos_filemodes is set
2915 then allow chown to the currently authenticated user.
2916 ****************************************************************************/
2918 static int try_chown(connection_struct
*conn
, const char *fname
, uid_t uid
, gid_t gid
)
2921 extern struct current_user current_user
;
2925 /* try the direct way first */
2926 ret
= SMB_VFS_CHOWN(conn
, fname
, uid
, gid
);
2930 if(!CAN_WRITE(conn
) || !lp_dos_filemode(SNUM(conn
)))
2933 if (SMB_VFS_STAT(conn
,fname
,&st
))
2936 fsp
= open_file_fchmod(conn
,fname
,&st
);
2940 /* only allow chown to the current user. This is more secure,
2941 and also copes with the case where the SID in a take ownership ACL is
2942 a local SID on the users workstation
2944 uid
= current_user
.uid
;
2947 /* Keep the current file gid the same. */
2948 ret
= SMB_VFS_FCHOWN(fsp
, fsp
->fd
, uid
, (gid_t
)-1);
2951 close_file_fchmod(fsp
);
2956 /****************************************************************************
2957 Reply to set a security descriptor on an fsp. security_info_sent is the
2958 description of the following NT ACL.
2959 This should be the only external function needed for the UNIX style set ACL.
2960 ****************************************************************************/
2962 BOOL
set_nt_acl(files_struct
*fsp
, uint32 security_info_sent
, SEC_DESC
*psd
)
2964 connection_struct
*conn
= fsp
->conn
;
2965 uid_t user
= (uid_t
)-1;
2966 gid_t grp
= (gid_t
)-1;
2967 SMB_STRUCT_STAT sbuf
;
2968 DOM_SID file_owner_sid
;
2969 DOM_SID file_grp_sid
;
2970 canon_ace
*file_ace_list
= NULL
;
2971 canon_ace
*dir_ace_list
= NULL
;
2972 BOOL acl_perms
= False
;
2973 mode_t orig_mode
= (mode_t
)0;
2976 BOOL need_chown
= False
;
2977 extern struct current_user current_user
;
2979 DEBUG(10,("set_nt_acl: called for file %s\n", fsp
->fsp_name
));
2981 if (!CAN_WRITE(conn
)) {
2982 DEBUG(10,("set acl rejected on read-only share\n"));
2987 * Get the current state of the file.
2990 if(fsp
->is_directory
|| fsp
->fd
== -1) {
2991 if(SMB_VFS_STAT(fsp
->conn
,fsp
->fsp_name
, &sbuf
) != 0)
2994 if(SMB_VFS_FSTAT(fsp
,fsp
->fd
,&sbuf
) != 0)
2998 /* Save the original elements we check against. */
2999 orig_mode
= sbuf
.st_mode
;
3000 orig_uid
= sbuf
.st_uid
;
3001 orig_gid
= sbuf
.st_gid
;
3004 * Unpack the user/group/world id's.
3007 if (!unpack_nt_owners( SNUM(conn
), &sbuf
, &user
, &grp
, security_info_sent
, psd
))
3011 * Do we need to chown ?
3014 if (((user
!= (uid_t
)-1) && (orig_uid
!= user
)) || (( grp
!= (gid_t
)-1) && (orig_gid
!= grp
)))
3018 * Chown before setting ACL only if we don't change the user, or
3019 * if we change to the current user, but not if we want to give away
3023 if (need_chown
&& (user
== (uid_t
)-1 || user
== current_user
.uid
)) {
3025 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3026 fsp
->fsp_name
, (unsigned int)user
, (unsigned int)grp
));
3028 if(try_chown( fsp
->conn
, fsp
->fsp_name
, user
, grp
) == -1) {
3029 DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3030 fsp
->fsp_name
, (unsigned int)user
, (unsigned int)grp
, strerror(errno
) ));
3035 * Recheck the current state of the file, which may have changed.
3036 * (suid/sgid bits, for instance)
3039 if(fsp
->is_directory
) {
3040 if(SMB_VFS_STAT(fsp
->conn
, fsp
->fsp_name
, &sbuf
) != 0) {
3048 ret
= SMB_VFS_STAT(fsp
->conn
, fsp
->fsp_name
, &sbuf
);
3050 ret
= SMB_VFS_FSTAT(fsp
,fsp
->fd
,&sbuf
);
3056 /* Save the original elements we check against. */
3057 orig_mode
= sbuf
.st_mode
;
3058 orig_uid
= sbuf
.st_uid
;
3059 orig_gid
= sbuf
.st_gid
;
3061 /* We did it, don't try again */
3065 create_file_sids(&sbuf
, &file_owner_sid
, &file_grp_sid
);
3067 acl_perms
= unpack_canon_ace( fsp
, &sbuf
, &file_owner_sid
, &file_grp_sid
,
3068 &file_ace_list
, &dir_ace_list
, security_info_sent
, psd
);
3070 /* Ignore W2K traverse DACL set. */
3071 if (file_ace_list
|| dir_ace_list
) {
3074 DEBUG(3,("set_nt_acl: cannot set permissions\n"));
3075 free_canon_ace_list(file_ace_list
);
3076 free_canon_ace_list(dir_ace_list
);
3081 * Only change security if we got a DACL.
3084 if((security_info_sent
& DACL_SECURITY_INFORMATION
) && (psd
->dacl
!= NULL
)) {
3086 BOOL acl_set_support
= False
;
3090 * Try using the POSIX ACL set first. Fall back to chmod if
3091 * we have no ACL support on this filesystem.
3094 if (acl_perms
&& file_ace_list
) {
3095 ret
= set_canon_ace_list(fsp
, file_ace_list
, False
, &acl_set_support
);
3096 if (acl_set_support
&& ret
== False
) {
3097 DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp
->fsp_name
, strerror(errno
) ));
3098 free_canon_ace_list(file_ace_list
);
3099 free_canon_ace_list(dir_ace_list
);
3104 if (acl_perms
&& acl_set_support
&& fsp
->is_directory
) {
3106 if (!set_canon_ace_list(fsp
, dir_ace_list
, True
, &acl_set_support
)) {
3107 DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp
->fsp_name
, strerror(errno
) ));
3108 free_canon_ace_list(file_ace_list
);
3109 free_canon_ace_list(dir_ace_list
);
3115 * No default ACL - delete one if it exists.
3118 if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn
, fsp
->fsp_name
) == -1) {
3119 DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno
)));
3120 free_canon_ace_list(file_ace_list
);
3121 free_canon_ace_list(dir_ace_list
);
3127 if (acl_set_support
)
3128 store_inheritance_attributes(fsp
, file_ace_list
, dir_ace_list
,
3129 (psd
->type
& SE_DESC_DACL_PROTECTED
) ? True
: False
);
3132 * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
3135 if(!acl_set_support
&& acl_perms
) {
3138 if (!convert_canon_ace_to_posix_perms( fsp
, file_ace_list
, &posix_perms
)) {
3139 free_canon_ace_list(file_ace_list
);
3140 free_canon_ace_list(dir_ace_list
);
3141 DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
3146 if (orig_mode
!= posix_perms
) {
3148 DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
3149 fsp
->fsp_name
, (unsigned int)posix_perms
));
3151 if(SMB_VFS_CHMOD(conn
,fsp
->fsp_name
, posix_perms
) == -1) {
3152 DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
3153 fsp
->fsp_name
, (unsigned int)posix_perms
, strerror(errno
) ));
3154 free_canon_ace_list(file_ace_list
);
3155 free_canon_ace_list(dir_ace_list
);
3162 free_canon_ace_list(file_ace_list
);
3163 free_canon_ace_list(dir_ace_list
);
3166 /* Any chown pending? */
3169 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3170 fsp
->fsp_name
, (unsigned int)user
, (unsigned int)grp
));
3172 if(try_chown( fsp
->conn
, fsp
->fsp_name
, user
, grp
) == -1) {
3173 DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3174 fsp
->fsp_name
, (unsigned int)user
, (unsigned int)grp
, strerror(errno
) ));
3182 /****************************************************************************
3183 Get the actual group bits stored on a file with an ACL. Has no effect if
3184 the file has no ACL. Needed in dosmode code where the stat() will return
3185 the mask bits, not the real group bits, for a file with an ACL.
3186 ****************************************************************************/
3188 int get_acl_group_bits( connection_struct
*conn
, const char *fname
, mode_t
*mode
)
3190 int entry_id
= SMB_ACL_FIRST_ENTRY
;
3191 SMB_ACL_ENTRY_T entry
;
3192 SMB_ACL_T posix_acl
;
3195 posix_acl
= SMB_VFS_SYS_ACL_GET_FILE(conn
, fname
, SMB_ACL_TYPE_ACCESS
);
3196 if (posix_acl
== (SMB_ACL_T
)NULL
)
3199 while (SMB_VFS_SYS_ACL_GET_ENTRY(conn
, posix_acl
, entry_id
, &entry
) == 1) {
3200 SMB_ACL_TAG_T tagtype
;
3201 SMB_ACL_PERMSET_T permset
;
3204 if (entry_id
== SMB_ACL_FIRST_ENTRY
)
3205 entry_id
= SMB_ACL_NEXT_ENTRY
;
3207 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn
, entry
, &tagtype
) ==-1)
3210 if (tagtype
== SMB_ACL_GROUP_OBJ
) {
3211 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn
, entry
, &permset
) == -1) {
3214 *mode
&= ~(S_IRGRP
|S_IWGRP
|S_IXGRP
);
3215 *mode
|= (SMB_VFS_SYS_ACL_GET_PERM(conn
, permset
, SMB_ACL_READ
) ? S_IRGRP
: 0);
3216 *mode
|= (SMB_VFS_SYS_ACL_GET_PERM(conn
, permset
, SMB_ACL_WRITE
) ? S_IWGRP
: 0);
3217 *mode
|= (SMB_VFS_SYS_ACL_GET_PERM(conn
, permset
, SMB_ACL_EXECUTE
) ? S_IXGRP
: 0);
3223 SMB_VFS_SYS_ACL_FREE_ACL(conn
, posix_acl
);
3227 /****************************************************************************
3228 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3229 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3230 ****************************************************************************/
3232 static int chmod_acl_internals( connection_struct
*conn
, SMB_ACL_T posix_acl
, mode_t mode
)
3234 int entry_id
= SMB_ACL_FIRST_ENTRY
;
3235 SMB_ACL_ENTRY_T entry
;
3236 int num_entries
= 0;
3238 while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn
, posix_acl
, entry_id
, &entry
) == 1) {
3239 SMB_ACL_TAG_T tagtype
;
3240 SMB_ACL_PERMSET_T permset
;
3244 if (entry_id
== SMB_ACL_FIRST_ENTRY
)
3245 entry_id
= SMB_ACL_NEXT_ENTRY
;
3247 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn
, entry
, &tagtype
) == -1)
3250 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn
, entry
, &permset
) == -1)
3256 case SMB_ACL_USER_OBJ
:
3257 perms
= unix_perms_to_acl_perms(mode
, S_IRUSR
, S_IWUSR
, S_IXUSR
);
3259 case SMB_ACL_GROUP_OBJ
:
3260 perms
= unix_perms_to_acl_perms(mode
, S_IRGRP
, S_IWGRP
, S_IXGRP
);
3264 * FIXME: The ACL_MASK entry permissions should really be set to
3265 * the union of the permissions of all ACL_USER,
3266 * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what
3267 * acl_calc_mask() does, but Samba ACLs doesn't provide it.
3269 perms
= S_IRUSR
|S_IWUSR
|S_IXUSR
;
3272 perms
= unix_perms_to_acl_perms(mode
, S_IROTH
, S_IWOTH
, S_IXOTH
);
3278 if (map_acl_perms_to_permset(conn
, perms
, &permset
) == -1)
3281 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn
, entry
, permset
) == -1)
3286 * If this is a simple 3 element ACL or no elements then it's a standard
3287 * UNIX permission set. Just use chmod...
3290 if ((num_entries
== 3) || (num_entries
== 0))
3296 /****************************************************************************
3297 Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ,
3298 GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the
3299 resulting ACL on TO. Note that name is in UNIX character set.
3300 ****************************************************************************/
3302 static int copy_access_acl(connection_struct
*conn
, const char *from
, const char *to
, mode_t mode
)
3304 SMB_ACL_T posix_acl
= NULL
;
3307 if ((posix_acl
= SMB_VFS_SYS_ACL_GET_FILE(conn
, from
, SMB_ACL_TYPE_ACCESS
)) == NULL
)
3310 if ((ret
= chmod_acl_internals(conn
, posix_acl
, mode
)) == -1)
3313 ret
= SMB_VFS_SYS_ACL_SET_FILE(conn
, to
, SMB_ACL_TYPE_ACCESS
, posix_acl
);
3317 SMB_VFS_SYS_ACL_FREE_ACL(conn
, posix_acl
);
3321 /****************************************************************************
3322 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3323 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3324 Note that name is in UNIX character set.
3325 ****************************************************************************/
3327 int chmod_acl(connection_struct
*conn
, const char *name
, mode_t mode
)
3329 return copy_access_acl(conn
, name
, name
, mode
);
3332 /****************************************************************************
3333 If "inherit permissions" is set and the parent directory has no default
3334 ACL but it does have an Access ACL, inherit this Access ACL to file name.
3335 ****************************************************************************/
3337 int inherit_access_acl(connection_struct
*conn
, const char *name
, mode_t mode
)
3340 pstrcpy(dirname
, parent_dirname(name
));
3342 if (!lp_inherit_perms(SNUM(conn
)) || directory_has_default_acl(conn
, dirname
))
3345 return copy_access_acl(conn
, dirname
, name
, mode
);
3348 /****************************************************************************
3349 Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3350 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3351 ****************************************************************************/
3353 int fchmod_acl(files_struct
*fsp
, int fd
, mode_t mode
)
3355 connection_struct
*conn
= fsp
->conn
;
3356 SMB_ACL_T posix_acl
= NULL
;
3359 if ((posix_acl
= SMB_VFS_SYS_ACL_GET_FD(fsp
, fd
)) == NULL
)
3362 if ((ret
= chmod_acl_internals(conn
, posix_acl
, mode
)) == -1)
3365 ret
= SMB_VFS_SYS_ACL_SET_FD(fsp
, fd
, posix_acl
);
3369 SMB_VFS_SYS_ACL_FREE_ACL(conn
, posix_acl
);
3373 /****************************************************************************
3374 Check for an existing default POSIX ACL on a directory.
3375 ****************************************************************************/
3377 BOOL
directory_has_default_acl(connection_struct
*conn
, const char *fname
)
3379 SMB_ACL_T dir_acl
= SMB_VFS_SYS_ACL_GET_FILE( conn
, fname
, SMB_ACL_TYPE_DEFAULT
);
3380 BOOL has_acl
= False
;
3381 SMB_ACL_ENTRY_T entry
;
3383 if (dir_acl
!= NULL
&& (SMB_VFS_SYS_ACL_GET_ENTRY(conn
, dir_acl
, SMB_ACL_FIRST_ENTRY
, &entry
) == 1))
3387 SMB_VFS_SYS_ACL_FREE_ACL(conn
, dir_acl
);