2 Unix SMB/CIFS implementation.
3 SMB NT Security Descriptor / Unix permission conversion.
4 Copyright (C) Jeremy Allison 1994-2009.
5 Copyright (C) Andreas Gruenbacher 2002.
6 Copyright (C) Simo Sorce <idra@samba.org> 2009.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 extern struct current_user current_user;
25 extern const struct generic_mapping file_generic_mapping;
28 #define DBGC_CLASS DBGC_ACLS
30 /****************************************************************************
31 Data structures representing the internal ACE format.
32 ****************************************************************************/
34 enum ace_owner {UID_ACE, GID_ACE, WORLD_ACE};
35 enum ace_attribute {ALLOW_ACE, DENY_ACE}; /* Used for incoming NT ACLS. */
37 typedef union posix_id {
43 typedef struct canon_ace {
44 struct canon_ace *next, *prev;
46 mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */
48 enum ace_owner owner_type;
49 enum ace_attribute attr;
51 uint8_t ace_flags; /* From windows ACE entry. */
54 #define ALL_ACE_PERMS (S_IRUSR|S_IWUSR|S_IXUSR)
57 * EA format of user.SAMBA_PAI (Samba_Posix_Acl_Interitance)
58 * attribute on disk - version 1.
59 * All values are little endian.
61 * | 1 | 1 | 2 | 2 | ....
62 * +------+------+-------------+---------------------+-------------+--------------------+
63 * | vers | flag | num_entries | num_default_entries | ..entries.. | default_entries... |
64 * +------+------+-------------+---------------------+-------------+--------------------+
69 * +------+-------------------+
70 * | value| uid/gid or world |
72 * +------+-------------------+
74 * Version 2 format. Stores extra Windows metadata about an ACL.
76 * | 1 | 2 | 2 | 2 | ....
77 * +------+----------+-------------+---------------------+-------------+--------------------+
78 * | vers | ace | num_entries | num_default_entries | ..entries.. | default_entries... |
79 * | 2 | type | | | | |
80 * +------+----------+-------------+---------------------+-------------+--------------------+
85 * +------+------+-------------------+
86 * | ace | value| uid/gid or world |
87 * | flag | type | value |
88 * +------+-------------------+------+
92 #define PAI_VERSION_OFFSET 0
94 #define PAI_V1_FLAG_OFFSET 1
95 #define PAI_V1_NUM_ENTRIES_OFFSET 2
96 #define PAI_V1_NUM_DEFAULT_ENTRIES_OFFSET 4
97 #define PAI_V1_ENTRIES_BASE 6
98 #define PAI_V1_ACL_FLAG_PROTECTED 0x1
99 #define PAI_V1_ENTRY_LENGTH 5
101 #define PAI_V1_VERSION 1
103 #define PAI_V2_TYPE_OFFSET 1
104 #define PAI_V2_NUM_ENTRIES_OFFSET 3
105 #define PAI_V2_NUM_DEFAULT_ENTRIES_OFFSET 5
106 #define PAI_V2_ENTRIES_BASE 7
107 #define PAI_V2_ENTRY_LENGTH 6
109 #define PAI_V2_VERSION 2
112 * In memory format of user.SAMBA_PAI attribute.
116 struct pai_entry *next, *prev;
118 enum ace_owner owner_type;
124 unsigned int num_entries;
125 struct pai_entry *entry_list;
126 unsigned int num_def_entries;
127 struct pai_entry *def_entry_list;
130 /************************************************************************
131 Return a uint32 of the pai_entry principal.
132 ************************************************************************/
134 static uint32_t get_pai_entry_val(struct pai_entry *paie)
136 switch (paie->owner_type) {
138 DEBUG(10,("get_pai_entry_val: uid = %u\n", (unsigned int)paie->unix_ug.uid ));
139 return (uint32_t)paie->unix_ug.uid;
141 DEBUG(10,("get_pai_entry_val: gid = %u\n", (unsigned int)paie->unix_ug.gid ));
142 return (uint32_t)paie->unix_ug.gid;
145 DEBUG(10,("get_pai_entry_val: world ace\n"));
150 /************************************************************************
151 Return a uint32 of the entry principal.
152 ************************************************************************/
154 static uint32_t get_entry_val(canon_ace *ace_entry)
156 switch (ace_entry->owner_type) {
158 DEBUG(10,("get_entry_val: uid = %u\n", (unsigned int)ace_entry->unix_ug.uid ));
159 return (uint32_t)ace_entry->unix_ug.uid;
161 DEBUG(10,("get_entry_val: gid = %u\n", (unsigned int)ace_entry->unix_ug.gid ));
162 return (uint32_t)ace_entry->unix_ug.gid;
165 DEBUG(10,("get_entry_val: world ace\n"));
170 /************************************************************************
171 Create the on-disk format (always v2 now). Caller must free.
172 ************************************************************************/
174 static char *create_pai_buf_v2(canon_ace *file_ace_list,
175 canon_ace *dir_ace_list,
179 char *pai_buf = NULL;
180 canon_ace *ace_list = NULL;
181 char *entry_offset = NULL;
182 unsigned int num_entries = 0;
183 unsigned int num_def_entries = 0;
186 for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) {
190 for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next) {
194 DEBUG(10,("create_pai_buf_v2: num_entries = %u, num_def_entries = %u\n", num_entries, num_def_entries ));
196 *store_size = PAI_V2_ENTRIES_BASE +
197 ((num_entries + num_def_entries)*PAI_V2_ENTRY_LENGTH);
199 pai_buf = (char *)SMB_MALLOC(*store_size);
204 /* Set up the header. */
205 memset(pai_buf, '\0', PAI_V2_ENTRIES_BASE);
206 SCVAL(pai_buf,PAI_VERSION_OFFSET,PAI_V2_VERSION);
207 SSVAL(pai_buf,PAI_V2_TYPE_OFFSET, sd_type);
208 SSVAL(pai_buf,PAI_V2_NUM_ENTRIES_OFFSET,num_entries);
209 SSVAL(pai_buf,PAI_V2_NUM_DEFAULT_ENTRIES_OFFSET,num_def_entries);
211 DEBUG(10,("create_pai_buf_v2: sd_type = 0x%x\n",
212 (unsigned int)sd_type ));
214 entry_offset = pai_buf + PAI_V2_ENTRIES_BASE;
217 for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) {
218 uint8_t type_val = (uint8_t)ace_list->owner_type;
219 uint32_t entry_val = get_entry_val(ace_list);
221 SCVAL(entry_offset,0,ace_list->ace_flags);
222 SCVAL(entry_offset,1,type_val);
223 SIVAL(entry_offset,2,entry_val);
224 DEBUG(10,("create_pai_buf_v2: entry %u [0x%x] [0x%x] [0x%x]\n",
226 (unsigned int)ace_list->ace_flags,
227 (unsigned int)type_val,
228 (unsigned int)entry_val ));
230 entry_offset += PAI_V2_ENTRY_LENGTH;
233 for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next) {
234 uint8_t type_val = (uint8_t)ace_list->owner_type;
235 uint32_t entry_val = get_entry_val(ace_list);
237 SCVAL(entry_offset,0,ace_list->ace_flags);
238 SCVAL(entry_offset,1,type_val);
239 SIVAL(entry_offset,2,entry_val);
240 DEBUG(10,("create_pai_buf_v2: entry %u [0x%x] [0x%x] [0x%x]\n",
242 (unsigned int)ace_list->ace_flags,
243 (unsigned int)type_val,
244 (unsigned int)entry_val ));
246 entry_offset += PAI_V2_ENTRY_LENGTH;
252 /************************************************************************
253 Store the user.SAMBA_PAI attribute on disk.
254 ************************************************************************/
256 static void store_inheritance_attributes(files_struct *fsp,
257 canon_ace *file_ace_list,
258 canon_ace *dir_ace_list,
265 if (!lp_map_acl_inherit(SNUM(fsp->conn))) {
269 pai_buf = create_pai_buf_v2(file_ace_list, dir_ace_list,
270 sd_type, &store_size);
272 if (fsp->fh->fd != -1) {
273 ret = SMB_VFS_FSETXATTR(fsp, SAMBA_POSIX_INHERITANCE_EA_NAME,
274 pai_buf, store_size, 0);
276 ret = SMB_VFS_SETXATTR(fsp->conn, fsp->fsp_name->base_name,
277 SAMBA_POSIX_INHERITANCE_EA_NAME,
278 pai_buf, store_size, 0);
283 DEBUG(10,("store_inheritance_attribute: type 0x%x for file %s\n",
284 (unsigned int)sd_type,
287 if (ret == -1 && !no_acl_syscall_error(errno)) {
288 DEBUG(1,("store_inheritance_attribute: Error %s\n", strerror(errno) ));
292 /************************************************************************
293 Delete the in memory inheritance info.
294 ************************************************************************/
296 static void free_inherited_info(struct pai_val *pal)
299 struct pai_entry *paie, *paie_next;
300 for (paie = pal->entry_list; paie; paie = paie_next) {
301 paie_next = paie->next;
304 for (paie = pal->def_entry_list; paie; paie = paie_next) {
305 paie_next = paie->next;
312 /************************************************************************
313 Get any stored ACE flags.
314 ************************************************************************/
316 static uint16_t get_pai_flags(struct pai_val *pal, canon_ace *ace_entry, bool default_ace)
318 struct pai_entry *paie;
324 /* If the entry exists it is inherited. */
325 for (paie = (default_ace ? pal->def_entry_list : pal->entry_list); paie; paie = paie->next) {
326 if (ace_entry->owner_type == paie->owner_type &&
327 get_entry_val(ace_entry) == get_pai_entry_val(paie))
328 return paie->ace_flags;
333 /************************************************************************
334 Ensure an attribute just read is valid - v1.
335 ************************************************************************/
337 static bool check_pai_ok_v1(const char *pai_buf, size_t pai_buf_data_size)
340 uint16 num_def_entries;
342 if (pai_buf_data_size < PAI_V1_ENTRIES_BASE) {
343 /* Corrupted - too small. */
347 if (CVAL(pai_buf,PAI_VERSION_OFFSET) != PAI_V1_VERSION) {
351 num_entries = SVAL(pai_buf,PAI_V1_NUM_ENTRIES_OFFSET);
352 num_def_entries = SVAL(pai_buf,PAI_V1_NUM_DEFAULT_ENTRIES_OFFSET);
354 /* Check the entry lists match. */
355 /* Each entry is 5 bytes (type plus 4 bytes of uid or gid). */
357 if (((num_entries + num_def_entries)*PAI_V1_ENTRY_LENGTH) +
358 PAI_V1_ENTRIES_BASE != pai_buf_data_size) {
365 /************************************************************************
366 Ensure an attribute just read is valid - v2.
367 ************************************************************************/
369 static bool check_pai_ok_v2(const char *pai_buf, size_t pai_buf_data_size)
372 uint16 num_def_entries;
374 if (pai_buf_data_size < PAI_V2_ENTRIES_BASE) {
375 /* Corrupted - too small. */
379 if (CVAL(pai_buf,PAI_VERSION_OFFSET) != PAI_V2_VERSION) {
383 num_entries = SVAL(pai_buf,PAI_V2_NUM_ENTRIES_OFFSET);
384 num_def_entries = SVAL(pai_buf,PAI_V2_NUM_DEFAULT_ENTRIES_OFFSET);
386 /* Check the entry lists match. */
387 /* Each entry is 6 bytes (flags + type + 4 bytes of uid or gid). */
389 if (((num_entries + num_def_entries)*PAI_V2_ENTRY_LENGTH) +
390 PAI_V2_ENTRIES_BASE != pai_buf_data_size) {
397 /************************************************************************
399 ************************************************************************/
401 static bool get_pai_owner_type(struct pai_entry *paie, const char *entry_offset)
403 paie->owner_type = (enum ace_owner)CVAL(entry_offset,0);
404 switch( paie->owner_type) {
406 paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1);
407 DEBUG(10,("get_pai_owner_type: uid = %u\n",
408 (unsigned int)paie->unix_ug.uid ));
411 paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1);
412 DEBUG(10,("get_pai_owner_type: gid = %u\n",
413 (unsigned int)paie->unix_ug.gid ));
416 paie->unix_ug.world = -1;
417 DEBUG(10,("get_pai_owner_type: world ace\n"));
420 DEBUG(10,("get_pai_owner_type: unknown type %u\n",
421 (unsigned int)paie->owner_type ));
427 /************************************************************************
429 ************************************************************************/
431 static const char *create_pai_v1_entries(struct pai_val *paiv,
432 const char *entry_offset,
437 for (i = 0; i < paiv->num_entries; i++) {
438 struct pai_entry *paie = SMB_MALLOC_P(struct pai_entry);
443 paie->ace_flags = SEC_ACE_FLAG_INHERITED_ACE;
444 if (!get_pai_owner_type(paie, entry_offset)) {
449 DLIST_ADD(paiv->entry_list, paie);
451 DLIST_ADD(paiv->def_entry_list, paie);
453 entry_offset += PAI_V1_ENTRY_LENGTH;
458 /************************************************************************
459 Convert to in-memory format from version 1.
460 ************************************************************************/
462 static struct pai_val *create_pai_val_v1(const char *buf, size_t size)
464 const char *entry_offset;
465 struct pai_val *paiv = NULL;
467 if (!check_pai_ok_v1(buf, size)) {
471 paiv = SMB_MALLOC_P(struct pai_val);
476 memset(paiv, '\0', sizeof(struct pai_val));
478 paiv->sd_type = (CVAL(buf,PAI_V1_FLAG_OFFSET) == PAI_V1_ACL_FLAG_PROTECTED) ?
479 SE_DESC_DACL_PROTECTED : 0;
481 paiv->num_entries = SVAL(buf,PAI_V1_NUM_ENTRIES_OFFSET);
482 paiv->num_def_entries = SVAL(buf,PAI_V1_NUM_DEFAULT_ENTRIES_OFFSET);
484 entry_offset = buf + PAI_V1_ENTRIES_BASE;
486 DEBUG(10,("create_pai_val: num_entries = %u, num_def_entries = %u\n",
487 paiv->num_entries, paiv->num_def_entries ));
489 entry_offset = create_pai_v1_entries(paiv, entry_offset, false);
490 if (entry_offset == NULL) {
491 free_inherited_info(paiv);
494 entry_offset = create_pai_v1_entries(paiv, entry_offset, true);
495 if (entry_offset == NULL) {
496 free_inherited_info(paiv);
503 /************************************************************************
505 ************************************************************************/
507 static const char *create_pai_v2_entries(struct pai_val *paiv,
508 unsigned int num_entries,
509 const char *entry_offset,
514 for (i = 0; i < num_entries; i++) {
515 struct pai_entry *paie = SMB_MALLOC_P(struct pai_entry);
520 paie->ace_flags = CVAL(entry_offset,0);
522 if (!get_pai_owner_type(paie, entry_offset+1)) {
526 DLIST_ADD(paiv->entry_list, paie);
528 DLIST_ADD(paiv->def_entry_list, paie);
530 entry_offset += PAI_V2_ENTRY_LENGTH;
535 /************************************************************************
536 Convert to in-memory format from version 2.
537 ************************************************************************/
539 static struct pai_val *create_pai_val_v2(const char *buf, size_t size)
541 const char *entry_offset;
542 struct pai_val *paiv = NULL;
544 if (!check_pai_ok_v2(buf, size)) {
548 paiv = SMB_MALLOC_P(struct pai_val);
553 memset(paiv, '\0', sizeof(struct pai_val));
555 paiv->sd_type = SVAL(buf,PAI_V2_TYPE_OFFSET);
557 paiv->num_entries = SVAL(buf,PAI_V2_NUM_ENTRIES_OFFSET);
558 paiv->num_def_entries = SVAL(buf,PAI_V2_NUM_DEFAULT_ENTRIES_OFFSET);
560 entry_offset = buf + PAI_V2_ENTRIES_BASE;
562 DEBUG(10,("create_pai_val_v2: sd_type = 0x%x num_entries = %u, num_def_entries = %u\n",
563 (unsigned int)paiv->sd_type,
564 paiv->num_entries, paiv->num_def_entries ));
566 entry_offset = create_pai_v2_entries(paiv, paiv->num_entries,
567 entry_offset, false);
568 if (entry_offset == NULL) {
569 free_inherited_info(paiv);
572 entry_offset = create_pai_v2_entries(paiv, paiv->num_def_entries,
574 if (entry_offset == NULL) {
575 free_inherited_info(paiv);
582 /************************************************************************
583 Convert to in-memory format - from either version 1 or 2.
584 ************************************************************************/
586 static struct pai_val *create_pai_val(const char *buf, size_t size)
591 if (CVAL(buf,PAI_VERSION_OFFSET) == PAI_V1_VERSION) {
592 return create_pai_val_v1(buf, size);
593 } else if (CVAL(buf,PAI_VERSION_OFFSET) == PAI_V2_VERSION) {
594 return create_pai_val_v2(buf, size);
600 /************************************************************************
601 Load the user.SAMBA_PAI attribute.
602 ************************************************************************/
604 static struct pai_val *fload_inherited_info(files_struct *fsp)
607 size_t pai_buf_size = 1024;
608 struct pai_val *paiv = NULL;
611 if (!lp_map_acl_inherit(SNUM(fsp->conn))) {
615 if ((pai_buf = (char *)SMB_MALLOC(pai_buf_size)) == NULL) {
620 if (fsp->fh->fd != -1) {
621 ret = SMB_VFS_FGETXATTR(fsp, SAMBA_POSIX_INHERITANCE_EA_NAME,
622 pai_buf, pai_buf_size);
624 ret = SMB_VFS_GETXATTR(fsp->conn,
625 fsp->fsp_name->base_name,
626 SAMBA_POSIX_INHERITANCE_EA_NAME,
627 pai_buf, pai_buf_size);
631 if (errno != ERANGE) {
634 /* Buffer too small - enlarge it. */
637 if (pai_buf_size > 1024*1024) {
638 return NULL; /* Limit malloc to 1mb. */
640 if ((pai_buf = (char *)SMB_MALLOC(pai_buf_size)) == NULL)
645 DEBUG(10,("load_inherited_info: ret = %lu for file %s\n",
646 (unsigned long)ret, fsp_str_dbg(fsp)));
649 /* No attribute or not supported. */
651 if (errno != ENOATTR)
652 DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
655 DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
661 paiv = create_pai_val(pai_buf, ret);
664 DEBUG(10,("load_inherited_info: ACL type is 0x%x for file %s\n",
665 (unsigned int)paiv->sd_type, fsp_str_dbg(fsp)));
672 /************************************************************************
673 Load the user.SAMBA_PAI attribute.
674 ************************************************************************/
676 static struct pai_val *load_inherited_info(const struct connection_struct *conn,
680 size_t pai_buf_size = 1024;
681 struct pai_val *paiv = NULL;
684 if (!lp_map_acl_inherit(SNUM(conn))) {
688 if ((pai_buf = (char *)SMB_MALLOC(pai_buf_size)) == NULL) {
693 ret = SMB_VFS_GETXATTR(conn, fname,
694 SAMBA_POSIX_INHERITANCE_EA_NAME,
695 pai_buf, pai_buf_size);
698 if (errno != ERANGE) {
701 /* Buffer too small - enlarge it. */
704 if (pai_buf_size > 1024*1024) {
705 return NULL; /* Limit malloc to 1mb. */
707 if ((pai_buf = (char *)SMB_MALLOC(pai_buf_size)) == NULL)
712 DEBUG(10,("load_inherited_info: ret = %lu for file %s\n", (unsigned long)ret, fname));
715 /* No attribute or not supported. */
717 if (errno != ENOATTR)
718 DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
721 DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
727 paiv = create_pai_val(pai_buf, ret);
730 DEBUG(10,("load_inherited_info: ACL type 0x%x for file %s\n",
731 (unsigned int)paiv->sd_type,
739 /****************************************************************************
740 Functions to manipulate the internal ACE format.
741 ****************************************************************************/
743 /****************************************************************************
744 Count a linked list of canonical ACE entries.
745 ****************************************************************************/
747 static size_t count_canon_ace_list( canon_ace *l_head )
752 for (ace = l_head; ace; ace = ace->next)
758 /****************************************************************************
759 Free a linked list of canonical ACE entries.
760 ****************************************************************************/
762 static void free_canon_ace_list( canon_ace *l_head )
764 canon_ace *list, *next;
766 for (list = l_head; list; list = next) {
768 DLIST_REMOVE(l_head, list);
773 /****************************************************************************
774 Function to duplicate a canon_ace entry.
775 ****************************************************************************/
777 static canon_ace *dup_canon_ace( canon_ace *src_ace)
779 canon_ace *dst_ace = SMB_MALLOC_P(canon_ace);
785 dst_ace->prev = dst_ace->next = NULL;
789 /****************************************************************************
790 Print out a canon ace.
791 ****************************************************************************/
793 static void print_canon_ace(canon_ace *pace, int num)
795 dbgtext( "canon_ace index %d. Type = %s ", num, pace->attr == ALLOW_ACE ? "allow" : "deny" );
796 dbgtext( "SID = %s ", sid_string_dbg(&pace->trustee));
797 if (pace->owner_type == UID_ACE) {
798 const char *u_name = uidtoname(pace->unix_ug.uid);
799 dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.uid, u_name );
800 } else if (pace->owner_type == GID_ACE) {
801 char *g_name = gidtoname(pace->unix_ug.gid);
802 dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.gid, g_name );
805 switch (pace->type) {
807 dbgtext( "SMB_ACL_USER ");
809 case SMB_ACL_USER_OBJ:
810 dbgtext( "SMB_ACL_USER_OBJ ");
813 dbgtext( "SMB_ACL_GROUP ");
815 case SMB_ACL_GROUP_OBJ:
816 dbgtext( "SMB_ACL_GROUP_OBJ ");
819 dbgtext( "SMB_ACL_OTHER ");
826 dbgtext( "ace_flags = 0x%x ", (unsigned int)pace->ace_flags);
828 dbgtext( "%c", pace->perms & S_IRUSR ? 'r' : '-');
829 dbgtext( "%c", pace->perms & S_IWUSR ? 'w' : '-');
830 dbgtext( "%c\n", pace->perms & S_IXUSR ? 'x' : '-');
833 /****************************************************************************
834 Print out a canon ace list.
835 ****************************************************************************/
837 static void print_canon_ace_list(const char *name, canon_ace *ace_list)
841 if( DEBUGLVL( 10 )) {
842 dbgtext( "print_canon_ace_list: %s\n", name );
843 for (;ace_list; ace_list = ace_list->next, count++)
844 print_canon_ace(ace_list, count );
848 /****************************************************************************
849 Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
850 ****************************************************************************/
852 static mode_t convert_permset_to_mode_t(connection_struct *conn, SMB_ACL_PERMSET_T permset)
856 ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRUSR : 0);
857 ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
858 ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
863 /****************************************************************************
864 Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
865 ****************************************************************************/
867 static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
881 /****************************************************************************
882 Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to
883 an SMB_ACL_PERMSET_T.
884 ****************************************************************************/
886 static int map_acl_perms_to_permset(connection_struct *conn, mode_t mode, SMB_ACL_PERMSET_T *p_permset)
888 if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) == -1)
890 if (mode & S_IRUSR) {
891 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1)
894 if (mode & S_IWUSR) {
895 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1)
898 if (mode & S_IXUSR) {
899 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1)
905 /****************************************************************************
906 Function to create owner and group SIDs from a SMB_STRUCT_STAT.
907 ****************************************************************************/
909 void create_file_sids(const SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
911 uid_to_sid( powner_sid, psbuf->st_ex_uid );
912 gid_to_sid( pgroup_sid, psbuf->st_ex_gid );
915 /****************************************************************************
916 Merge aces with a common sid - if both are allow or deny, OR the permissions together and
917 delete the second one. If the first is deny, mask the permissions off and delete the allow
918 if the permissions become zero, delete the deny if the permissions are non zero.
919 ****************************************************************************/
921 static void merge_aces( canon_ace **pp_list_head, bool dir_acl)
923 canon_ace *l_head = *pp_list_head;
924 canon_ace *curr_ace_outer;
925 canon_ace *curr_ace_outer_next;
928 * First, merge allow entries with identical SIDs, and deny entries
929 * with identical SIDs.
932 for (curr_ace_outer = l_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
934 canon_ace *curr_ace_next;
936 curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
938 for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
939 bool can_merge = false;
941 curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
943 /* For file ACLs we can merge if the SIDs and ALLOW/DENY
944 * types are the same. For directory acls we must also
945 * ensure the POSIX ACL types are the same. */
948 can_merge = (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
949 (curr_ace->attr == curr_ace_outer->attr));
951 can_merge = (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
952 (curr_ace->type == curr_ace_outer->type) &&
953 (curr_ace->attr == curr_ace_outer->attr));
957 if( DEBUGLVL( 10 )) {
958 dbgtext("merge_aces: Merging ACE's\n");
959 print_canon_ace( curr_ace_outer, 0);
960 print_canon_ace( curr_ace, 0);
963 /* Merge two allow or two deny ACE's. */
965 /* Theoretically we shouldn't merge a dir ACE if
966 * one ACE has the CI flag set, and the other
967 * ACE has the OI flag set, but this is rare
968 * enough we can ignore it. */
970 curr_ace_outer->perms |= curr_ace->perms;
971 curr_ace_outer->ace_flags |= curr_ace->ace_flags;
972 DLIST_REMOVE(l_head, curr_ace);
974 curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
980 * Now go through and mask off allow permissions with deny permissions.
981 * We can delete either the allow or deny here as we know that each SID
982 * appears only once in the list.
985 for (curr_ace_outer = l_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
987 canon_ace *curr_ace_next;
989 curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
991 for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
993 curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
996 * Subtract ACE's with different entries. Due to the ordering constraints
997 * we've put on the ACL, we know the deny must be the first one.
1000 if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
1001 (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
1003 if( DEBUGLVL( 10 )) {
1004 dbgtext("merge_aces: Masking ACE's\n");
1005 print_canon_ace( curr_ace_outer, 0);
1006 print_canon_ace( curr_ace, 0);
1009 curr_ace->perms &= ~curr_ace_outer->perms;
1011 if (curr_ace->perms == 0) {
1014 * The deny overrides the allow. Remove the allow.
1017 DLIST_REMOVE(l_head, curr_ace);
1018 SAFE_FREE(curr_ace);
1019 curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
1024 * Even after removing permissions, there
1025 * are still allow permissions - delete the deny.
1026 * It is safe to delete the deny here,
1027 * as we are guarenteed by the deny first
1028 * ordering that all the deny entries for
1029 * this SID have already been merged into one
1030 * before we can get to an allow ace.
1033 DLIST_REMOVE(l_head, curr_ace_outer);
1034 SAFE_FREE(curr_ace_outer);
1039 } /* end for curr_ace */
1040 } /* end for curr_ace_outer */
1042 /* We may have modified the list. */
1044 *pp_list_head = l_head;
1047 /****************************************************************************
1048 Check if we need to return NT4.x compatible ACL entries.
1049 ****************************************************************************/
1051 bool nt4_compatible_acls(void)
1053 int compat = lp_acl_compatibility();
1055 if (compat == ACL_COMPAT_AUTO) {
1056 enum remote_arch_types ra_type = get_remote_arch();
1058 /* Automatically adapt to client */
1059 return (ra_type <= RA_WINNT);
1061 return (compat == ACL_COMPAT_WINNT);
1065 /****************************************************************************
1066 Map canon_ace perms to permission bits NT.
1067 The attr element is not used here - we only process deny entries on set,
1068 not get. Deny entries are implicit on get with ace->perms = 0.
1069 ****************************************************************************/
1071 uint32_t map_canon_ace_perms(int snum,
1072 enum security_ace_type *pacl_type,
1076 uint32_t nt_mask = 0;
1078 *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
1080 if (lp_acl_map_full_control(snum) && ((perms & ALL_ACE_PERMS) == ALL_ACE_PERMS)) {
1081 if (directory_ace) {
1082 nt_mask = UNIX_DIRECTORY_ACCESS_RWX;
1084 nt_mask = (UNIX_ACCESS_RWX & ~DELETE_ACCESS);
1086 } else if ((perms & ALL_ACE_PERMS) == (mode_t)0) {
1088 * Windows NT refuses to display ACEs with no permissions in them (but
1089 * they are perfectly legal with Windows 2000). If the ACE has empty
1090 * permissions we cannot use 0, so we use the otherwise unused
1091 * WRITE_OWNER permission, which we ignore when we set an ACL.
1092 * We abstract this into a #define of UNIX_ACCESS_NONE to allow this
1093 * to be changed in the future.
1096 if (nt4_compatible_acls())
1097 nt_mask = UNIX_ACCESS_NONE;
1101 if (directory_ace) {
1102 nt_mask |= ((perms & S_IRUSR) ? UNIX_DIRECTORY_ACCESS_R : 0 );
1103 nt_mask |= ((perms & S_IWUSR) ? UNIX_DIRECTORY_ACCESS_W : 0 );
1104 nt_mask |= ((perms & S_IXUSR) ? UNIX_DIRECTORY_ACCESS_X : 0 );
1106 nt_mask |= ((perms & S_IRUSR) ? UNIX_ACCESS_R : 0 );
1107 nt_mask |= ((perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
1108 nt_mask |= ((perms & S_IXUSR) ? UNIX_ACCESS_X : 0 );
1112 if ((perms & S_IWUSR) && lp_dos_filemode(snum)) {
1113 nt_mask |= (SEC_STD_WRITE_DAC|SEC_STD_WRITE_OWNER|DELETE_ACCESS);
1116 DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
1117 (unsigned int)perms, (unsigned int)nt_mask ));
1122 /****************************************************************************
1123 Map NT perms to a UNIX mode_t.
1124 ****************************************************************************/
1126 #define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
1127 #define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
1128 #define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
1130 static mode_t map_nt_perms( uint32 *mask, int type)
1136 if((*mask) & GENERIC_ALL_ACCESS)
1137 mode = S_IRUSR|S_IWUSR|S_IXUSR;
1139 mode |= ((*mask) & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
1140 mode |= ((*mask) & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
1141 mode |= ((*mask) & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
1145 if((*mask) & GENERIC_ALL_ACCESS)
1146 mode = S_IRGRP|S_IWGRP|S_IXGRP;
1148 mode |= ((*mask) & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
1149 mode |= ((*mask) & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
1150 mode |= ((*mask) & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
1154 if((*mask) & GENERIC_ALL_ACCESS)
1155 mode = S_IROTH|S_IWOTH|S_IXOTH;
1157 mode |= ((*mask) & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
1158 mode |= ((*mask) & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
1159 mode |= ((*mask) & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
1167 /****************************************************************************
1168 Unpack a SEC_DESC into a UNIX owner and group.
1169 ****************************************************************************/
1171 NTSTATUS unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, const SEC_DESC *psd)
1179 if(security_info_sent == 0) {
1180 DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
1181 return NT_STATUS_OK;
1185 * Validate the owner and group SID's.
1188 memset(&owner_sid, '\0', sizeof(owner_sid));
1189 memset(&grp_sid, '\0', sizeof(grp_sid));
1191 DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
1194 * Don't immediately fail if the owner sid cannot be validated.
1195 * This may be a group chown only set.
1198 if (security_info_sent & OWNER_SECURITY_INFORMATION) {
1199 sid_copy(&owner_sid, psd->owner_sid);
1200 if (!sid_to_uid(&owner_sid, puser)) {
1201 if (lp_force_unknown_acl_user(snum)) {
1202 /* this allows take ownership to work
1204 *puser = current_user.ut.uid;
1206 DEBUG(3,("unpack_nt_owners: unable to validate"
1207 " owner sid for %s\n",
1208 sid_string_dbg(&owner_sid)));
1209 return NT_STATUS_INVALID_OWNER;
1212 DEBUG(3,("unpack_nt_owners: owner sid mapped to uid %u\n",
1213 (unsigned int)*puser ));
1217 * Don't immediately fail if the group sid cannot be validated.
1218 * This may be an owner chown only set.
1221 if (security_info_sent & GROUP_SECURITY_INFORMATION) {
1222 sid_copy(&grp_sid, psd->group_sid);
1223 if (!sid_to_gid( &grp_sid, pgrp)) {
1224 if (lp_force_unknown_acl_user(snum)) {
1225 /* this allows take group ownership to work
1227 *pgrp = current_user.ut.gid;
1229 DEBUG(3,("unpack_nt_owners: unable to validate"
1231 return NT_STATUS_INVALID_OWNER;
1234 DEBUG(3,("unpack_nt_owners: group sid mapped to gid %u\n",
1235 (unsigned int)*pgrp));
1238 DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
1240 return NT_STATUS_OK;
1243 /****************************************************************************
1244 Ensure the enforced permissions for this share apply.
1245 ****************************************************************************/
1247 static void apply_default_perms(const struct share_params *params,
1248 const bool is_directory, canon_ace *pace,
1251 mode_t and_bits = (mode_t)0;
1252 mode_t or_bits = (mode_t)0;
1254 /* Get the initial bits to apply. */
1257 and_bits = lp_dir_security_mask(params->service);
1258 or_bits = lp_force_dir_security_mode(params->service);
1260 and_bits = lp_security_mask(params->service);
1261 or_bits = lp_force_security_mode(params->service);
1264 /* Now bounce them into the S_USR space. */
1267 /* Ensure owner has read access. */
1268 pace->perms |= S_IRUSR;
1270 pace->perms |= (S_IWUSR|S_IXUSR);
1271 and_bits = unix_perms_to_acl_perms(and_bits, S_IRUSR, S_IWUSR, S_IXUSR);
1272 or_bits = unix_perms_to_acl_perms(or_bits, S_IRUSR, S_IWUSR, S_IXUSR);
1275 and_bits = unix_perms_to_acl_perms(and_bits, S_IRGRP, S_IWGRP, S_IXGRP);
1276 or_bits = unix_perms_to_acl_perms(or_bits, S_IRGRP, S_IWGRP, S_IXGRP);
1279 and_bits = unix_perms_to_acl_perms(and_bits, S_IROTH, S_IWOTH, S_IXOTH);
1280 or_bits = unix_perms_to_acl_perms(or_bits, S_IROTH, S_IWOTH, S_IXOTH);
1284 pace->perms = ((pace->perms & and_bits)|or_bits);
1287 /****************************************************************************
1288 Check if a given uid/SID is in a group gid/SID. This is probably very
1289 expensive and will need optimisation. A *lot* of optimisation :-). JRA.
1290 ****************************************************************************/
1292 static bool uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
1294 const char *u_name = NULL;
1296 /* "Everyone" always matches every uid. */
1298 if (sid_equal(&group_ace->trustee, &global_sid_World))
1302 * if it's the current user, we already have the unix token
1303 * and don't need to do the complex user_in_group_sid() call
1305 if (uid_ace->unix_ug.uid == current_user.ut.uid) {
1308 if (group_ace->unix_ug.gid == current_user.ut.gid) {
1312 for (i=0; i < current_user.ut.ngroups; i++) {
1313 if (group_ace->unix_ug.gid == current_user.ut.groups[i]) {
1319 /* u_name talloc'ed off tos. */
1320 u_name = uidtoname(uid_ace->unix_ug.uid);
1326 * user_in_group_sid() uses create_token_from_username()
1327 * which creates an artificial NT token given just a username,
1328 * so this is not reliable for users from foreign domains
1329 * exported by winbindd!
1331 return user_in_group_sid(u_name, &group_ace->trustee);
1334 /****************************************************************************
1335 A well formed POSIX file or default ACL has at least 3 entries, a
1336 SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
1337 In addition, the owner must always have at least read access.
1338 When using this call on get_acl, the pst struct is valid and contains
1339 the mode of the file. When using this call on set_acl, the pst struct has
1340 been modified to have a mode containing the default for this file or directory
1342 ****************************************************************************/
1344 static bool ensure_canon_entry_valid(canon_ace **pp_ace,
1345 const struct share_params *params,
1346 const bool is_directory,
1347 const DOM_SID *pfile_owner_sid,
1348 const DOM_SID *pfile_grp_sid,
1349 const SMB_STRUCT_STAT *pst,
1353 bool got_user = False;
1354 bool got_grp = False;
1355 bool got_other = False;
1356 canon_ace *pace_other = NULL;
1358 for (pace = *pp_ace; pace; pace = pace->next) {
1359 if (pace->type == SMB_ACL_USER_OBJ) {
1362 apply_default_perms(params, is_directory, pace, S_IRUSR);
1365 } else if (pace->type == SMB_ACL_GROUP_OBJ) {
1368 * Ensure create mask/force create mode is respected on set.
1372 apply_default_perms(params, is_directory, pace, S_IRGRP);
1375 } else if (pace->type == SMB_ACL_OTHER) {
1378 * Ensure create mask/force create mode is respected on set.
1382 apply_default_perms(params, is_directory, pace, S_IROTH);
1389 if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
1390 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1395 pace->type = SMB_ACL_USER_OBJ;
1396 pace->owner_type = UID_ACE;
1397 pace->unix_ug.uid = pst->st_ex_uid;
1398 pace->trustee = *pfile_owner_sid;
1399 pace->attr = ALLOW_ACE;
1402 /* See if the owning user is in any of the other groups in
1403 the ACE. If so, OR in the permissions from that group. */
1405 bool group_matched = False;
1406 canon_ace *pace_iter;
1408 for (pace_iter = *pp_ace; pace_iter; pace_iter = pace_iter->next) {
1409 if (pace_iter->type == SMB_ACL_GROUP_OBJ || pace_iter->type == SMB_ACL_GROUP) {
1410 if (uid_entry_in_group(pace, pace_iter)) {
1411 pace->perms |= pace_iter->perms;
1412 group_matched = True;
1417 /* If we only got an "everyone" perm, just use that. */
1418 if (!group_matched) {
1420 pace->perms = pace_other->perms;
1425 apply_default_perms(params, is_directory, pace, S_IRUSR);
1427 pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRUSR, S_IWUSR, S_IXUSR);
1430 DLIST_ADD(*pp_ace, pace);
1434 if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
1435 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1440 pace->type = SMB_ACL_GROUP_OBJ;
1441 pace->owner_type = GID_ACE;
1442 pace->unix_ug.uid = pst->st_ex_gid;
1443 pace->trustee = *pfile_grp_sid;
1444 pace->attr = ALLOW_ACE;
1446 /* If we only got an "everyone" perm, just use that. */
1448 pace->perms = pace_other->perms;
1451 apply_default_perms(params, is_directory, pace, S_IRGRP);
1453 pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IRGRP, S_IWGRP, S_IXGRP);
1456 DLIST_ADD(*pp_ace, pace);
1460 if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
1461 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1466 pace->type = SMB_ACL_OTHER;
1467 pace->owner_type = WORLD_ACE;
1468 pace->unix_ug.world = -1;
1469 pace->trustee = global_sid_World;
1470 pace->attr = ALLOW_ACE;
1473 apply_default_perms(params, is_directory, pace, S_IROTH);
1475 pace->perms = unix_perms_to_acl_perms(pst->st_ex_mode, S_IROTH, S_IWOTH, S_IXOTH);
1477 DLIST_ADD(*pp_ace, pace);
1483 /****************************************************************************
1484 Check if a POSIX ACL has the required SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries.
1485 If it does not have them, check if there are any entries where the trustee is the
1486 file owner or the owning group, and map these to SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ.
1487 ****************************************************************************/
1489 static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid)
1491 bool got_user_obj, got_group_obj;
1492 canon_ace *current_ace;
1495 entries = count_canon_ace_list(ace);
1496 got_user_obj = False;
1497 got_group_obj = False;
1499 for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1500 if (current_ace->type == SMB_ACL_USER_OBJ)
1501 got_user_obj = True;
1502 else if (current_ace->type == SMB_ACL_GROUP_OBJ)
1503 got_group_obj = True;
1505 if (got_user_obj && got_group_obj) {
1506 DEBUG(10,("check_owning_objs: ACL had owning user/group entries.\n"));
1510 for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1511 if (!got_user_obj && current_ace->owner_type == UID_ACE &&
1512 sid_equal(¤t_ace->trustee, pfile_owner_sid)) {
1513 current_ace->type = SMB_ACL_USER_OBJ;
1514 got_user_obj = True;
1516 if (!got_group_obj && current_ace->owner_type == GID_ACE &&
1517 sid_equal(¤t_ace->trustee, pfile_grp_sid)) {
1518 current_ace->type = SMB_ACL_GROUP_OBJ;
1519 got_group_obj = True;
1523 DEBUG(10,("check_owning_objs: ACL is missing an owner entry.\n"));
1525 DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n"));
1528 /****************************************************************************
1529 Unpack a SEC_DESC into two canonical ace lists.
1530 ****************************************************************************/
1532 static bool create_canon_ace_lists(files_struct *fsp,
1533 const SMB_STRUCT_STAT *pst,
1534 DOM_SID *pfile_owner_sid,
1535 DOM_SID *pfile_grp_sid,
1536 canon_ace **ppfile_ace,
1537 canon_ace **ppdir_ace,
1538 const SEC_ACL *dacl)
1540 bool all_aces_are_inherit_only = (fsp->is_directory ? True : False);
1541 canon_ace *file_ace = NULL;
1542 canon_ace *dir_ace = NULL;
1543 canon_ace *current_ace = NULL;
1544 bool got_dir_allow = False;
1545 bool got_file_allow = False;
1552 * Convert the incoming ACL into a more regular form.
1555 for(i = 0; i < dacl->num_aces; i++) {
1556 SEC_ACE *psa = &dacl->aces[i];
1558 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
1559 DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
1563 if (nt4_compatible_acls()) {
1565 * The security mask may be UNIX_ACCESS_NONE which should map into
1566 * no permissions (we overload the WRITE_OWNER bit for this) or it
1567 * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
1568 * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
1572 * Convert GENERIC bits to specific bits.
1575 se_map_generic(&psa->access_mask, &file_generic_mapping);
1577 psa->access_mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS);
1579 if(psa->access_mask != UNIX_ACCESS_NONE)
1580 psa->access_mask &= ~UNIX_ACCESS_NONE;
1585 * Deal with the fact that NT 4.x re-writes the canonical format
1586 * that we return for default ACLs. If a directory ACE is identical
1587 * to a inherited directory ACE then NT changes the bits so that the
1588 * first ACE is set to OI|IO and the second ACE for this SID is set
1589 * to CI. We need to repair this. JRA.
1592 for(i = 0; i < dacl->num_aces; i++) {
1593 SEC_ACE *psa1 = &dacl->aces[i];
1595 for (j = i + 1; j < dacl->num_aces; j++) {
1596 SEC_ACE *psa2 = &dacl->aces[j];
1598 if (psa1->access_mask != psa2->access_mask)
1601 if (!sid_equal(&psa1->trustee, &psa2->trustee))
1605 * Ok - permission bits and SIDs are equal.
1606 * Check if flags were re-written.
1609 if (psa1->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1611 psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1612 psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1614 } else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1616 psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1617 psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1623 for(i = 0; i < dacl->num_aces; i++) {
1624 SEC_ACE *psa = &dacl->aces[i];
1627 * Create a cannon_ace entry representing this NT DACL ACE.
1630 if ((current_ace = SMB_MALLOC_P(canon_ace)) == NULL) {
1631 free_canon_ace_list(file_ace);
1632 free_canon_ace_list(dir_ace);
1633 DEBUG(0,("create_canon_ace_lists: malloc fail.\n"));
1637 ZERO_STRUCTP(current_ace);
1639 sid_copy(¤t_ace->trustee, &psa->trustee);
1642 * Try and work out if the SID is a user or group
1643 * as we need to flag these differently for POSIX.
1644 * Note what kind of a POSIX ACL this should map to.
1647 if( sid_equal(¤t_ace->trustee, &global_sid_World)) {
1648 current_ace->owner_type = WORLD_ACE;
1649 current_ace->unix_ug.world = -1;
1650 current_ace->type = SMB_ACL_OTHER;
1651 } else if (sid_equal(¤t_ace->trustee, &global_sid_Creator_Owner)) {
1652 current_ace->owner_type = UID_ACE;
1653 current_ace->unix_ug.uid = pst->st_ex_uid;
1654 current_ace->type = SMB_ACL_USER_OBJ;
1657 * The Creator Owner entry only specifies inheritable permissions,
1658 * never access permissions. WinNT doesn't always set the ACE to
1659 * INHERIT_ONLY, though.
1662 psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1664 } else if (sid_equal(¤t_ace->trustee, &global_sid_Creator_Group)) {
1665 current_ace->owner_type = GID_ACE;
1666 current_ace->unix_ug.gid = pst->st_ex_gid;
1667 current_ace->type = SMB_ACL_GROUP_OBJ;
1670 * The Creator Group entry only specifies inheritable permissions,
1671 * never access permissions. WinNT doesn't always set the ACE to
1672 * INHERIT_ONLY, though.
1674 psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1676 } else if (sid_to_uid( ¤t_ace->trustee, ¤t_ace->unix_ug.uid)) {
1677 current_ace->owner_type = UID_ACE;
1678 /* If it's the owning user, this is a user_obj, not
1680 if (current_ace->unix_ug.uid == pst->st_ex_uid) {
1681 current_ace->type = SMB_ACL_USER_OBJ;
1683 current_ace->type = SMB_ACL_USER;
1685 } else if (sid_to_gid( ¤t_ace->trustee, ¤t_ace->unix_ug.gid)) {
1686 current_ace->owner_type = GID_ACE;
1687 /* If it's the primary group, this is a group_obj, not
1689 if (current_ace->unix_ug.gid == pst->st_ex_gid) {
1690 current_ace->type = SMB_ACL_GROUP_OBJ;
1692 current_ace->type = SMB_ACL_GROUP;
1696 * Silently ignore map failures in non-mappable SIDs (NT Authority, BUILTIN etc).
1699 if (non_mappable_sid(&psa->trustee)) {
1700 DEBUG(10, ("create_canon_ace_lists: ignoring "
1701 "non-mappable SID %s\n",
1702 sid_string_dbg(&psa->trustee)));
1703 SAFE_FREE(current_ace);
1707 if (lp_force_unknown_acl_user(SNUM(fsp->conn))) {
1708 DEBUG(10, ("create_canon_ace_lists: ignoring "
1709 "unknown or foreign SID %s\n",
1710 sid_string_dbg(&psa->trustee)));
1711 SAFE_FREE(current_ace);
1715 free_canon_ace_list(file_ace);
1716 free_canon_ace_list(dir_ace);
1717 DEBUG(0, ("create_canon_ace_lists: unable to map SID "
1718 "%s to uid or gid.\n",
1719 sid_string_dbg(¤t_ace->trustee)));
1720 SAFE_FREE(current_ace);
1725 * Map the given NT permissions into a UNIX mode_t containing only
1726 * S_I(R|W|X)USR bits.
1729 current_ace->perms |= map_nt_perms( &psa->access_mask, S_IRUSR);
1730 current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
1732 /* Store the ace_flag. */
1733 current_ace->ace_flags = psa->flags;
1736 * Now add the created ace to either the file list, the directory
1737 * list, or both. We *MUST* preserve the order here (hence we use
1738 * DLIST_ADD_END) as NT ACLs are order dependent.
1741 if (fsp->is_directory) {
1744 * We can only add to the default POSIX ACE list if the ACE is
1745 * designed to be inherited by both files and directories.
1748 if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
1749 (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
1751 canon_ace *current_dir_ace = current_ace;
1752 DLIST_ADD_END(dir_ace, current_ace, canon_ace *);
1755 * Note if this was an allow ace. We can't process
1756 * any further deny ace's after this.
1759 if (current_ace->attr == ALLOW_ACE)
1760 got_dir_allow = True;
1762 if ((current_ace->attr == DENY_ACE) && got_dir_allow) {
1763 DEBUG(0,("create_canon_ace_lists: "
1765 "inheritable ACL! Deny entry "
1766 "after Allow entry. Failing "
1767 "to set on file %s.\n",
1769 free_canon_ace_list(file_ace);
1770 free_canon_ace_list(dir_ace);
1774 if( DEBUGLVL( 10 )) {
1775 dbgtext("create_canon_ace_lists: adding dir ACL:\n");
1776 print_canon_ace( current_ace, 0);
1780 * If this is not an inherit only ACE we need to add a duplicate
1784 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1785 canon_ace *dup_ace = dup_canon_ace(current_ace);
1788 DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
1789 free_canon_ace_list(file_ace);
1790 free_canon_ace_list(dir_ace);
1795 * We must not free current_ace here as its
1796 * pointer is now owned by the dir_ace list.
1798 current_ace = dup_ace;
1799 /* We've essentially split this ace into two,
1800 * and added the ace with inheritance request
1801 * bits to the directory ACL. Drop those bits for
1802 * the ACE we're adding to the file list. */
1803 current_ace->ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
1804 SEC_ACE_FLAG_CONTAINER_INHERIT|
1805 SEC_ACE_FLAG_INHERIT_ONLY);
1808 * We must not free current_ace here as its
1809 * pointer is now owned by the dir_ace list.
1815 * current_ace is now either owned by file_ace
1816 * or is NULL. We can safely operate on current_dir_ace
1817 * to treat mapping for default acl entries differently
1818 * than access acl entries.
1821 if (current_dir_ace->owner_type == UID_ACE) {
1823 * We already decided above this is a uid,
1824 * for default acls ace's only CREATOR_OWNER
1825 * maps to ACL_USER_OBJ. All other uid
1826 * ace's are ACL_USER.
1828 if (sid_equal(¤t_dir_ace->trustee,
1829 &global_sid_Creator_Owner)) {
1830 current_dir_ace->type = SMB_ACL_USER_OBJ;
1832 current_dir_ace->type = SMB_ACL_USER;
1836 if (current_dir_ace->owner_type == GID_ACE) {
1838 * We already decided above this is a gid,
1839 * for default acls ace's only CREATOR_GROUP
1840 * maps to ACL_GROUP_OBJ. All other uid
1841 * ace's are ACL_GROUP.
1843 if (sid_equal(¤t_dir_ace->trustee,
1844 &global_sid_Creator_Group)) {
1845 current_dir_ace->type = SMB_ACL_GROUP_OBJ;
1847 current_dir_ace->type = SMB_ACL_GROUP;
1854 * Only add to the file ACL if not inherit only.
1857 if (current_ace && !(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1858 DLIST_ADD_END(file_ace, current_ace, canon_ace *);
1861 * Note if this was an allow ace. We can't process
1862 * any further deny ace's after this.
1865 if (current_ace->attr == ALLOW_ACE)
1866 got_file_allow = True;
1868 if ((current_ace->attr == DENY_ACE) && got_file_allow) {
1869 DEBUG(0,("create_canon_ace_lists: malformed "
1870 "ACL in file ACL ! Deny entry after "
1871 "Allow entry. Failing to set on file "
1872 "%s.\n", fsp_str_dbg(fsp)));
1873 free_canon_ace_list(file_ace);
1874 free_canon_ace_list(dir_ace);
1878 if( DEBUGLVL( 10 )) {
1879 dbgtext("create_canon_ace_lists: adding file ACL:\n");
1880 print_canon_ace( current_ace, 0);
1882 all_aces_are_inherit_only = False;
1884 * We must not free current_ace here as its
1885 * pointer is now owned by the file_ace list.
1891 * Free if ACE was not added.
1894 SAFE_FREE(current_ace);
1897 if (fsp->is_directory && all_aces_are_inherit_only) {
1899 * Windows 2000 is doing one of these weird 'inherit acl'
1900 * traverses to conserve NTFS ACL resources. Just pretend
1901 * there was no DACL sent. JRA.
1904 DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n"));
1905 free_canon_ace_list(file_ace);
1906 free_canon_ace_list(dir_ace);
1911 * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in each
1912 * ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP
1913 * entries can be converted to *_OBJ. Usually we will already have these
1914 * entries in the Default ACL, and the Access ACL will not have them.
1917 check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);
1920 check_owning_objs(dir_ace, pfile_owner_sid, pfile_grp_sid);
1924 *ppfile_ace = file_ace;
1925 *ppdir_ace = dir_ace;
1930 /****************************************************************************
1931 ASCII art time again... JRA :-).
1933 We have 4 cases to process when moving from an NT ACL to a POSIX ACL. Firstly,
1934 we insist the ACL is in canonical form (ie. all DENY entries preceede ALLOW
1935 entries). Secondly, the merge code has ensured that all duplicate SID entries for
1936 allow or deny have been merged, so the same SID can only appear once in the deny
1937 list or once in the allow list.
1939 We then process as follows :
1941 ---------------------------------------------------------------------------
1942 First pass - look for a Everyone DENY entry.
1944 If it is deny all (rwx) trunate the list at this point.
1945 Else, walk the list from this point and use the deny permissions of this
1946 entry as a mask on all following allow entries. Finally, delete
1947 the Everyone DENY entry (we have applied it to everything possible).
1949 In addition, in this pass we remove any DENY entries that have
1950 no permissions (ie. they are a DENY nothing).
1951 ---------------------------------------------------------------------------
1952 Second pass - only deal with deny user entries.
1954 DENY user1 (perms XXX)
1957 for all following allow group entries where user1 is in group
1958 new_perms |= group_perms;
1960 user1 entry perms = new_perms & ~ XXX;
1962 Convert the deny entry to an allow entry with the new perms and
1963 push to the end of the list. Note if the user was in no groups
1964 this maps to a specific allow nothing entry for this user.
1966 The common case from the NT ACL choser (userX deny all) is
1967 optimised so we don't do the group lookup - we just map to
1968 an allow nothing entry.
1970 What we're doing here is inferring the allow permissions the
1971 person setting the ACE on user1 wanted by looking at the allow
1972 permissions on the groups the user is currently in. This will
1973 be a snapshot, depending on group membership but is the best
1974 we can do and has the advantage of failing closed rather than
1976 ---------------------------------------------------------------------------
1977 Third pass - only deal with deny group entries.
1979 DENY group1 (perms XXX)
1981 for all following allow user entries where user is in group1
1982 user entry perms = user entry perms & ~ XXX;
1984 If there is a group Everyone allow entry with permissions YYY,
1985 convert the group1 entry to an allow entry and modify its
1988 new_perms = YYY & ~ XXX
1990 and push to the end of the list.
1992 If there is no group Everyone allow entry then convert the
1993 group1 entry to a allow nothing entry and push to the end of the list.
1995 Note that the common case from the NT ACL choser (groupX deny all)
1996 cannot be optimised here as we need to modify user entries who are
1997 in the group to change them to a deny all also.
1999 What we're doing here is modifying the allow permissions of
2000 user entries (which are more specific in POSIX ACLs) to mask
2001 out the explicit deny set on the group they are in. This will
2002 be a snapshot depending on current group membership but is the
2003 best we can do and has the advantage of failing closed rather
2005 ---------------------------------------------------------------------------
2006 Fourth pass - cope with cumulative permissions.
2008 for all allow user entries, if there exists an allow group entry with
2009 more permissive permissions, and the user is in that group, rewrite the
2010 allow user permissions to contain both sets of permissions.
2012 Currently the code for this is #ifdef'ed out as these semantics make
2013 no sense to me. JRA.
2014 ---------------------------------------------------------------------------
2016 Note we *MUST* do the deny user pass first as this will convert deny user
2017 entries into allow user entries which can then be processed by the deny
2020 The above algorithm took a *lot* of thinking about - hence this
2021 explaination :-). JRA.
2022 ****************************************************************************/
2024 /****************************************************************************
2025 Process a canon_ace list entries. This is very complex code. We need
2026 to go through and remove the "deny" permissions from any allow entry that matches
2027 the id of this entry. We have already refused any NT ACL that wasn't in correct
2028 order (DENY followed by ALLOW). If any allow entry ends up with zero permissions,
2029 we just remove it (to fail safe). We have already removed any duplicate ace
2030 entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all
2032 ****************************************************************************/
2034 static void process_deny_list( canon_ace **pp_ace_list )
2036 canon_ace *ace_list = *pp_ace_list;
2037 canon_ace *curr_ace = NULL;
2038 canon_ace *curr_ace_next = NULL;
2040 /* Pass 1 above - look for an Everyone, deny entry. */
2042 for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
2043 canon_ace *allow_ace_p;
2045 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
2047 if (curr_ace->attr != DENY_ACE)
2050 if (curr_ace->perms == (mode_t)0) {
2052 /* Deny nothing entry - delete. */
2054 DLIST_REMOVE(ace_list, curr_ace);
2058 if (!sid_equal(&curr_ace->trustee, &global_sid_World))
2061 /* JRATEST - assert. */
2062 SMB_ASSERT(curr_ace->owner_type == WORLD_ACE);
2064 if (curr_ace->perms == ALL_ACE_PERMS) {
2067 * Optimisation. This is a DENY_ALL to Everyone. Truncate the
2068 * list at this point including this entry.
2071 canon_ace *prev_entry = curr_ace->prev;
2073 free_canon_ace_list( curr_ace );
2075 prev_entry->next = NULL;
2077 /* We deleted the entire list. */
2083 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
2086 * Only mask off allow entries.
2089 if (allow_ace_p->attr != ALLOW_ACE)
2092 allow_ace_p->perms &= ~curr_ace->perms;
2096 * Now it's been applied, remove it.
2099 DLIST_REMOVE(ace_list, curr_ace);
2102 /* Pass 2 above - deal with deny user entries. */
2104 for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
2105 mode_t new_perms = (mode_t)0;
2106 canon_ace *allow_ace_p;
2108 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
2110 if (curr_ace->attr != DENY_ACE)
2113 if (curr_ace->owner_type != UID_ACE)
2116 if (curr_ace->perms == ALL_ACE_PERMS) {
2119 * Optimisation - this is a deny everything to this user.
2120 * Convert to an allow nothing and push to the end of the list.
2123 curr_ace->attr = ALLOW_ACE;
2124 curr_ace->perms = (mode_t)0;
2125 DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
2129 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
2131 if (allow_ace_p->attr != ALLOW_ACE)
2134 /* We process GID_ACE and WORLD_ACE entries only. */
2136 if (allow_ace_p->owner_type == UID_ACE)
2139 if (uid_entry_in_group( curr_ace, allow_ace_p))
2140 new_perms |= allow_ace_p->perms;
2144 * Convert to a allow entry, modify the perms and push to the end
2148 curr_ace->attr = ALLOW_ACE;
2149 curr_ace->perms = (new_perms & ~curr_ace->perms);
2150 DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
2153 /* Pass 3 above - deal with deny group entries. */
2155 for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
2156 canon_ace *allow_ace_p;
2157 canon_ace *allow_everyone_p = NULL;
2159 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
2161 if (curr_ace->attr != DENY_ACE)
2164 if (curr_ace->owner_type != GID_ACE)
2167 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
2169 if (allow_ace_p->attr != ALLOW_ACE)
2172 /* Store a pointer to the Everyone allow, if it exists. */
2173 if (allow_ace_p->owner_type == WORLD_ACE)
2174 allow_everyone_p = allow_ace_p;
2176 /* We process UID_ACE entries only. */
2178 if (allow_ace_p->owner_type != UID_ACE)
2181 /* Mask off the deny group perms. */
2183 if (uid_entry_in_group( allow_ace_p, curr_ace))
2184 allow_ace_p->perms &= ~curr_ace->perms;
2188 * Convert the deny to an allow with the correct perms and
2189 * push to the end of the list.
2192 curr_ace->attr = ALLOW_ACE;
2193 if (allow_everyone_p)
2194 curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms;
2196 curr_ace->perms = (mode_t)0;
2197 DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
2200 /* Doing this fourth pass allows Windows semantics to be layered
2201 * on top of POSIX semantics. I'm not sure if this is desirable.
2202 * For example, in W2K ACLs there is no way to say, "Group X no
2203 * access, user Y full access" if user Y is a member of group X.
2204 * This seems completely broken semantics to me.... JRA.
2208 /* Pass 4 above - deal with allow entries. */
2210 for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
2211 canon_ace *allow_ace_p;
2213 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
2215 if (curr_ace->attr != ALLOW_ACE)
2218 if (curr_ace->owner_type != UID_ACE)
2221 for (allow_ace_p = ace_list; allow_ace_p; allow_ace_p = allow_ace_p->next) {
2223 if (allow_ace_p->attr != ALLOW_ACE)
2226 /* We process GID_ACE entries only. */
2228 if (allow_ace_p->owner_type != GID_ACE)
2231 /* OR in the group perms. */
2233 if (uid_entry_in_group( curr_ace, allow_ace_p))
2234 curr_ace->perms |= allow_ace_p->perms;
2239 *pp_ace_list = ace_list;
2242 /****************************************************************************
2243 Create a default mode that will be used if a security descriptor entry has
2244 no user/group/world entries.
2245 ****************************************************************************/
2247 static mode_t create_default_mode(files_struct *fsp, bool interitable_mode)
2249 int snum = SNUM(fsp->conn);
2250 mode_t and_bits = (mode_t)0;
2251 mode_t or_bits = (mode_t)0;
2254 if (interitable_mode) {
2255 mode = unix_mode(fsp->conn, FILE_ATTRIBUTE_ARCHIVE,
2256 fsp->fsp_name, NULL);
2261 if (fsp->is_directory)
2262 mode |= (S_IWUSR|S_IXUSR);
2265 * Now AND with the create mode/directory mode bits then OR with the
2266 * force create mode/force directory mode bits.
2269 if (fsp->is_directory) {
2270 and_bits = lp_dir_security_mask(snum);
2271 or_bits = lp_force_dir_security_mode(snum);
2273 and_bits = lp_security_mask(snum);
2274 or_bits = lp_force_security_mode(snum);
2277 return ((mode & and_bits)|or_bits);
2280 /****************************************************************************
2281 Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
2283 ****************************************************************************/
2285 static bool unpack_canon_ace(files_struct *fsp,
2286 const SMB_STRUCT_STAT *pst,
2287 DOM_SID *pfile_owner_sid,
2288 DOM_SID *pfile_grp_sid,
2289 canon_ace **ppfile_ace,
2290 canon_ace **ppdir_ace,
2291 uint32 security_info_sent,
2292 const SEC_DESC *psd)
2295 canon_ace *file_ace = NULL;
2296 canon_ace *dir_ace = NULL;
2301 if(security_info_sent == 0) {
2302 DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
2307 * If no DACL then this is a chown only security descriptor.
2310 if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !psd->dacl)
2314 * Now go through the DACL and create the canon_ace lists.
2317 if (!create_canon_ace_lists( fsp, pst, pfile_owner_sid, pfile_grp_sid,
2318 &file_ace, &dir_ace, psd->dacl))
2321 if ((file_ace == NULL) && (dir_ace == NULL)) {
2322 /* W2K traverse DACL set - ignore. */
2327 * Go through the canon_ace list and merge entries
2328 * belonging to identical users of identical allow or deny type.
2329 * We can do this as all deny entries come first, followed by
2330 * all allow entries (we have mandated this before accepting this acl).
2333 print_canon_ace_list( "file ace - before merge", file_ace);
2334 merge_aces( &file_ace, false);
2336 print_canon_ace_list( "dir ace - before merge", dir_ace);
2337 merge_aces( &dir_ace, true);
2340 * NT ACLs are order dependent. Go through the acl lists and
2341 * process DENY entries by masking the allow entries.
2344 print_canon_ace_list( "file ace - before deny", file_ace);
2345 process_deny_list( &file_ace);
2347 print_canon_ace_list( "dir ace - before deny", dir_ace);
2348 process_deny_list( &dir_ace);
2351 * A well formed POSIX file or default ACL has at least 3 entries, a
2352 * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
2353 * and optionally a mask entry. Ensure this is the case.
2356 print_canon_ace_list( "file ace - before valid", file_ace);
2361 * A default 3 element mode entry for a file should be r-- --- ---.
2362 * A default 3 element mode entry for a directory should be rwx --- ---.
2365 st.st_ex_mode = create_default_mode(fsp, False);
2367 if (!ensure_canon_entry_valid(&file_ace, fsp->conn->params,
2368 fsp->is_directory, pfile_owner_sid, pfile_grp_sid, &st, True)) {
2369 free_canon_ace_list(file_ace);
2370 free_canon_ace_list(dir_ace);
2374 print_canon_ace_list( "dir ace - before valid", dir_ace);
2377 * A default inheritable 3 element mode entry for a directory should be the
2378 * mode Samba will use to create a file within. Ensure user rwx bits are set if
2382 st.st_ex_mode = create_default_mode(fsp, True);
2384 if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp->conn->params,
2385 fsp->is_directory, pfile_owner_sid, pfile_grp_sid, &st, True)) {
2386 free_canon_ace_list(file_ace);
2387 free_canon_ace_list(dir_ace);
2391 print_canon_ace_list( "file ace - return", file_ace);
2392 print_canon_ace_list( "dir ace - return", dir_ace);
2394 *ppfile_ace = file_ace;
2395 *ppdir_ace = dir_ace;
2400 /******************************************************************************
2401 When returning permissions, try and fit NT display
2402 semantics if possible. Note the the canon_entries here must have been malloced.
2403 The list format should be - first entry = owner, followed by group and other user
2404 entries, last entry = other.
2406 Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries
2407 are not ordered, and match on the most specific entry rather than walking a list,
2408 then a simple POSIX permission of rw-r--r-- should really map to 5 entries,
2410 Entry 0: owner : deny all except read and write.
2411 Entry 1: owner : allow read and write.
2412 Entry 2: group : deny all except read.
2413 Entry 3: group : allow read.
2414 Entry 4: Everyone : allow read.
2416 But NT cannot display this in their ACL editor !
2417 ********************************************************************************/
2419 static void arrange_posix_perms(const char *filename, canon_ace **pp_list_head)
2421 canon_ace *l_head = *pp_list_head;
2422 canon_ace *owner_ace = NULL;
2423 canon_ace *other_ace = NULL;
2424 canon_ace *ace = NULL;
2426 for (ace = l_head; ace; ace = ace->next) {
2427 if (ace->type == SMB_ACL_USER_OBJ)
2429 else if (ace->type == SMB_ACL_OTHER) {
2430 /* Last ace - this is "other" */
2435 if (!owner_ace || !other_ace) {
2436 DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n",
2442 * The POSIX algorithm applies to owner first, and other last,
2443 * so ensure they are arranged in this order.
2447 DLIST_PROMOTE(l_head, owner_ace);
2451 DLIST_DEMOTE(l_head, other_ace, canon_ace *);
2454 /* We have probably changed the head of the list. */
2456 *pp_list_head = l_head;
2459 /****************************************************************************
2460 Create a linked list of canonical ACE entries.
2461 ****************************************************************************/
2463 static canon_ace *canonicalise_acl(struct connection_struct *conn,
2464 const char *fname, SMB_ACL_T posix_acl,
2465 const SMB_STRUCT_STAT *psbuf,
2466 const DOM_SID *powner, const DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type)
2468 mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
2469 canon_ace *l_head = NULL;
2470 canon_ace *ace = NULL;
2471 canon_ace *next_ace = NULL;
2472 int entry_id = SMB_ACL_FIRST_ENTRY;
2473 SMB_ACL_ENTRY_T entry;
2476 while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
2477 SMB_ACL_TAG_T tagtype;
2478 SMB_ACL_PERMSET_T permset;
2481 enum ace_owner owner_type;
2483 entry_id = SMB_ACL_NEXT_ENTRY;
2485 /* Is this a MASK entry ? */
2486 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
2489 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
2492 /* Decide which SID to use based on the ACL type. */
2494 case SMB_ACL_USER_OBJ:
2495 /* Get the SID from the owner. */
2496 sid_copy(&sid, powner);
2497 unix_ug.uid = psbuf->st_ex_uid;
2498 owner_type = UID_ACE;
2502 uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
2504 DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
2507 uid_to_sid( &sid, *puid);
2508 unix_ug.uid = *puid;
2509 owner_type = UID_ACE;
2510 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
2513 case SMB_ACL_GROUP_OBJ:
2514 /* Get the SID from the owning group. */
2515 sid_copy(&sid, pgroup);
2516 unix_ug.gid = psbuf->st_ex_gid;
2517 owner_type = GID_ACE;
2521 gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
2523 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
2526 gid_to_sid( &sid, *pgid);
2527 unix_ug.gid = *pgid;
2528 owner_type = GID_ACE;
2529 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
2533 acl_mask = convert_permset_to_mode_t(conn, permset);
2534 continue; /* Don't count the mask as an entry. */
2536 /* Use the Everyone SID */
2537 sid = global_sid_World;
2539 owner_type = WORLD_ACE;
2542 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
2547 * Add this entry to the list.
2550 if ((ace = SMB_MALLOC_P(canon_ace)) == NULL)
2554 ace->type = tagtype;
2555 ace->perms = convert_permset_to_mode_t(conn, permset);
2556 ace->attr = ALLOW_ACE;
2558 ace->unix_ug = unix_ug;
2559 ace->owner_type = owner_type;
2560 ace->ace_flags = get_pai_flags(pal, ace, (the_acl_type == SMB_ACL_TYPE_DEFAULT));
2562 DLIST_ADD(l_head, ace);
2566 * This next call will ensure we have at least a user/group/world set.
2569 if (!ensure_canon_entry_valid(&l_head, conn->params,
2570 S_ISDIR(psbuf->st_ex_mode), powner, pgroup,
2575 * Now go through the list, masking the permissions with the
2576 * acl_mask. Ensure all DENY Entries are at the start of the list.
2579 DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", the_acl_type == SMB_ACL_TYPE_ACCESS ? "Access" : "Default" ));
2581 for ( ace_count = 0, ace = l_head; ace; ace = next_ace, ace_count++) {
2582 next_ace = ace->next;
2584 /* Masks are only applied to entries other than USER_OBJ and OTHER. */
2585 if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
2586 ace->perms &= acl_mask;
2588 if (ace->perms == 0) {
2589 DLIST_PROMOTE(l_head, ace);
2592 if( DEBUGLVL( 10 ) ) {
2593 print_canon_ace(ace, ace_count);
2597 arrange_posix_perms(fname,&l_head );
2599 print_canon_ace_list( "canonicalise_acl: ace entries after arrange", l_head );
2605 free_canon_ace_list(l_head);
2609 /****************************************************************************
2610 Check if the current user group list contains a given group.
2611 ****************************************************************************/
2613 bool current_user_in_group(gid_t gid)
2617 for (i = 0; i < current_user.ut.ngroups; i++) {
2618 if (current_user.ut.groups[i] == gid) {
2626 /****************************************************************************
2627 Should we override a deny ? Check 'acl group control' and 'dos filemode'.
2628 ****************************************************************************/
2630 static bool acl_group_override(connection_struct *conn,
2631 const struct smb_filename *smb_fname)
2633 if ((errno != EPERM) && (errno != EACCES)) {
2637 /* file primary group == user primary or supplementary group */
2638 if (lp_acl_group_control(SNUM(conn)) &&
2639 current_user_in_group(smb_fname->st.st_ex_gid)) {
2643 /* user has writeable permission */
2644 if (lp_dos_filemode(SNUM(conn)) &&
2645 can_write_to_file(conn, smb_fname)) {
2652 /****************************************************************************
2653 Attempt to apply an ACL to a file or directory.
2654 ****************************************************************************/
2656 static bool set_canon_ace_list(files_struct *fsp,
2659 const SMB_STRUCT_STAT *psbuf,
2660 bool *pacl_set_support)
2662 connection_struct *conn = fsp->conn;
2664 SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, (int)count_canon_ace_list(the_ace) + 1);
2667 SMB_ACL_ENTRY_T mask_entry;
2668 bool got_mask_entry = False;
2669 SMB_ACL_PERMSET_T mask_permset;
2670 SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
2671 bool needs_mask = False;
2672 mode_t mask_perms = 0;
2674 /* Use the psbuf that was passed in. */
2675 if (psbuf != &fsp->fsp_name->st) {
2676 fsp->fsp_name->st = *psbuf;
2679 #if defined(POSIX_ACL_NEEDS_MASK)
2680 /* HP-UX always wants to have a mask (called "class" there). */
2684 if (the_acl == NULL) {
2686 if (!no_acl_syscall_error(errno)) {
2688 * Only print this error message if we have some kind of ACL
2689 * support that's not working. Otherwise we would always get this.
2691 DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
2692 default_ace ? "default" : "file", strerror(errno) ));
2694 *pacl_set_support = False;
2698 if( DEBUGLVL( 10 )) {
2699 dbgtext("set_canon_ace_list: setting ACL:\n");
2700 for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2701 print_canon_ace( p_ace, i);
2705 for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2706 SMB_ACL_ENTRY_T the_entry;
2707 SMB_ACL_PERMSET_T the_permset;
2710 * ACLs only "need" an ACL_MASK entry if there are any named user or
2711 * named group entries. But if there is an ACL_MASK entry, it applies
2712 * to ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. Set the mask
2713 * so that it doesn't deny (i.e., mask off) any permissions.
2716 if (p_ace->type == SMB_ACL_USER || p_ace->type == SMB_ACL_GROUP) {
2718 mask_perms |= p_ace->perms;
2719 } else if (p_ace->type == SMB_ACL_GROUP_OBJ) {
2720 mask_perms |= p_ace->perms;
2724 * Get the entry for this ACE.
2727 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
2728 DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
2729 i, strerror(errno) ));
2733 if (p_ace->type == SMB_ACL_MASK) {
2734 mask_entry = the_entry;
2735 got_mask_entry = True;
2739 * Ok - we now know the ACL calls should be working, don't
2740 * allow fallback to chmod.
2743 *pacl_set_support = True;
2746 * Initialise the entry from the canon_ace.
2750 * First tell the entry what type of ACE this is.
2753 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, p_ace->type) == -1) {
2754 DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
2755 i, strerror(errno) ));
2760 * Only set the qualifier (user or group id) if the entry is a user
2764 if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
2765 if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
2766 DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
2767 i, strerror(errno) ));
2773 * Convert the mode_t perms in the canon_ace to a POSIX permset.
2776 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
2777 DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
2778 i, strerror(errno) ));
2782 if (map_acl_perms_to_permset(conn, p_ace->perms, &the_permset) == -1) {
2783 DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
2784 (unsigned int)p_ace->perms, i, strerror(errno) ));
2789 * ..and apply them to the entry.
2792 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
2793 DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
2794 i, strerror(errno) ));
2799 print_canon_ace( p_ace, i);
2803 if (needs_mask && !got_mask_entry) {
2804 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &mask_entry) == -1) {
2805 DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
2809 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, mask_entry, SMB_ACL_MASK) == -1) {
2810 DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
2814 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, mask_entry, &mask_permset) == -1) {
2815 DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
2819 if (map_acl_perms_to_permset(conn, S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
2820 DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
2824 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, mask_entry, mask_permset) == -1) {
2825 DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
2831 * Finally apply it to the file or directory.
2834 if(default_ace || fsp->is_directory || fsp->fh->fd == -1) {
2835 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name->base_name,
2836 the_acl_type, the_acl) == -1) {
2838 * Some systems allow all the above calls and only fail with no ACL support
2839 * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2841 if (no_acl_syscall_error(errno)) {
2842 *pacl_set_support = False;
2845 if (acl_group_override(conn, fsp->fsp_name)) {
2848 DEBUG(5,("set_canon_ace_list: acl group "
2849 "control on and current user in file "
2850 "%s primary group.\n",
2854 sret = SMB_VFS_SYS_ACL_SET_FILE(conn,
2855 fsp->fsp_name->base_name, the_acl_type,
2864 DEBUG(2,("set_canon_ace_list: "
2865 "sys_acl_set_file type %s failed for "
2867 the_acl_type == SMB_ACL_TYPE_DEFAULT ?
2868 "directory default" : "file",
2869 fsp_str_dbg(fsp), strerror(errno)));
2874 if (SMB_VFS_SYS_ACL_SET_FD(fsp, the_acl) == -1) {
2876 * Some systems allow all the above calls and only fail with no ACL support
2877 * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2879 if (no_acl_syscall_error(errno)) {
2880 *pacl_set_support = False;
2883 if (acl_group_override(conn, fsp->fsp_name)) {
2886 DEBUG(5,("set_canon_ace_list: acl group "
2887 "control on and current user in file "
2888 "%s primary group.\n",
2892 sret = SMB_VFS_SYS_ACL_SET_FD(fsp, the_acl);
2900 DEBUG(2,("set_canon_ace_list: "
2901 "sys_acl_set_file failed for file %s "
2903 fsp_str_dbg(fsp), strerror(errno)));
2913 if (the_acl != NULL) {
2914 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2920 /****************************************************************************
2921 Find a particular canon_ace entry.
2922 ****************************************************************************/
2924 static struct canon_ace *canon_ace_entry_for(struct canon_ace *list, SMB_ACL_TAG_T type, posix_id *id)
2927 if (list->type == type && ((type != SMB_ACL_USER && type != SMB_ACL_GROUP) ||
2928 (type == SMB_ACL_USER && id && id->uid == list->unix_ug.uid) ||
2929 (type == SMB_ACL_GROUP && id && id->gid == list->unix_ug.gid)))
2936 /****************************************************************************
2938 ****************************************************************************/
2940 SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl)
2942 SMB_ACL_ENTRY_T entry;
2946 if (SMB_VFS_SYS_ACL_GET_ENTRY(conn, the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
2947 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2953 /****************************************************************************
2954 Convert a canon_ace to a generic 3 element permission - if possible.
2955 ****************************************************************************/
2957 #define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
2959 static bool convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
2961 int snum = SNUM(fsp->conn);
2962 size_t ace_count = count_canon_ace_list(file_ace_list);
2964 canon_ace *owner_ace = NULL;
2965 canon_ace *group_ace = NULL;
2966 canon_ace *other_ace = NULL;
2970 if (ace_count != 3) {
2971 DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE "
2972 "entries for file %s to convert to posix perms.\n",
2977 for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
2978 if (ace_p->owner_type == UID_ACE)
2980 else if (ace_p->owner_type == GID_ACE)
2982 else if (ace_p->owner_type == WORLD_ACE)
2986 if (!owner_ace || !group_ace || !other_ace) {
2987 DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get "
2988 "standard entries for file %s.\n", fsp_str_dbg(fsp)));
2992 *posix_perms = (mode_t)0;
2994 *posix_perms |= owner_ace->perms;
2995 *posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP);
2996 *posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP);
2997 *posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP);
2998 *posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH);
2999 *posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH);
3000 *posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH);
3002 /* The owner must have at least read access. */
3004 *posix_perms |= S_IRUSR;
3005 if (fsp->is_directory)
3006 *posix_perms |= (S_IWUSR|S_IXUSR);
3008 /* If requested apply the masks. */
3010 /* Get the initial bits to apply. */
3012 if (fsp->is_directory) {
3013 and_bits = lp_dir_security_mask(snum);
3014 or_bits = lp_force_dir_security_mode(snum);
3016 and_bits = lp_security_mask(snum);
3017 or_bits = lp_force_security_mode(snum);
3020 *posix_perms = (((*posix_perms) & and_bits)|or_bits);
3022 DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o "
3023 "to perm=0%o for file %s.\n", (int)owner_ace->perms,
3024 (int)group_ace->perms, (int)other_ace->perms,
3025 (int)*posix_perms, fsp_str_dbg(fsp)));
3030 /****************************************************************************
3031 Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and
3032 a normal POSIX acl. Win2k needs these split acls re-merging into one ACL
3033 with CI|OI set so it is inherited and also applies to the directory.
3034 Based on code from "Jim McDonough" <jmcd@us.ibm.com>.
3035 ****************************************************************************/
3037 static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
3041 for (i = 0; i < num_aces; i++) {
3042 for (j = i+1; j < num_aces; j++) {
3043 uint32 i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
3044 uint32 j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
3045 bool i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
3046 bool j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
3048 /* We know the lower number ACE's are file entries. */
3049 if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
3050 (nt_ace_list[i].size == nt_ace_list[j].size) &&
3051 (nt_ace_list[i].access_mask == nt_ace_list[j].access_mask) &&
3052 sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
3054 (i_flags_ni == 0) &&
3055 (j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT|
3056 SEC_ACE_FLAG_CONTAINER_INHERIT|
3057 SEC_ACE_FLAG_INHERIT_ONLY))) {
3059 * W2K wants to have access allowed zero access ACE's
3060 * at the end of the list. If the mask is zero, merge
3061 * the non-inherited ACE onto the inherited ACE.
3064 if (nt_ace_list[i].access_mask == 0) {
3065 nt_ace_list[j].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
3066 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
3067 if (num_aces - i - 1 > 0)
3068 memmove(&nt_ace_list[i], &nt_ace_list[i+1], (num_aces-i-1) *
3071 DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n",
3072 (unsigned int)i, (unsigned int)j ));
3075 * These are identical except for the flags.
3076 * Merge the inherited ACE onto the non-inherited ACE.
3079 nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
3080 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
3081 if (num_aces - j - 1 > 0)
3082 memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) *
3085 DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n",
3086 (unsigned int)j, (unsigned int)i ));
3098 * Add or Replace ACE entry.
3099 * In some cases we need to add a specific ACE for compatibility reasons.
3100 * When doing that we must make sure we are not actually creating a duplicate
3101 * entry. So we need to search whether an ACE entry already exist and eventually
3102 * replacce the access mask, or add a completely new entry if none was found.
3104 * This function assumes the array has enough space to add a new entry without
3105 * any reallocation of memory.
3108 static void add_or_replace_ace(SEC_ACE *nt_ace_list, size_t *num_aces,
3109 const DOM_SID *sid, enum security_ace_type type,
3110 uint32_t mask, uint8_t flags)
3114 /* first search for a duplicate */
3115 for (i = 0; i < *num_aces; i++) {
3116 if (sid_equal(&nt_ace_list[i].trustee, sid) &&
3117 (nt_ace_list[i].flags == flags)) break;
3120 if (i < *num_aces) { /* found */
3121 nt_ace_list[i].type = type;
3122 nt_ace_list[i].access_mask = mask;
3123 DEBUG(10, ("Replacing ACE %d with SID %s and flags %02x\n",
3124 i, sid_string_dbg(sid), flags));
3128 /* not found, append it */
3129 init_sec_ace(&nt_ace_list[(*num_aces)++], sid, type, mask, flags);
3133 /****************************************************************************
3134 Reply to query a security descriptor from an fsp. If it succeeds it allocates
3135 the space for the return elements and returns the size needed to return the
3136 security descriptor. This should be the only external function needed for
3137 the UNIX style get ACL.
3138 ****************************************************************************/
3140 static NTSTATUS posix_get_nt_acl_common(struct connection_struct *conn,
3142 const SMB_STRUCT_STAT *sbuf,
3143 struct pai_val *pal,
3144 SMB_ACL_T posix_acl,
3146 uint32_t security_info,
3152 SEC_ACL *psa = NULL;
3153 size_t num_acls = 0;
3154 size_t num_def_acls = 0;
3155 size_t num_aces = 0;
3156 canon_ace *file_ace = NULL;
3157 canon_ace *dir_ace = NULL;
3158 SEC_ACE *nt_ace_list = NULL;
3159 size_t num_profile_acls = 0;
3160 DOM_SID orig_owner_sid;
3161 SEC_DESC *psd = NULL;
3165 * Get the owner, group and world SIDs.
3168 create_file_sids(sbuf, &owner_sid, &group_sid);
3170 if (lp_profile_acls(SNUM(conn))) {
3171 /* For WXP SP1 the owner must be administrators. */
3172 sid_copy(&orig_owner_sid, &owner_sid);
3173 sid_copy(&owner_sid, &global_sid_Builtin_Administrators);
3174 sid_copy(&group_sid, &global_sid_Builtin_Users);
3175 num_profile_acls = 3;
3178 if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) {
3181 * In the optimum case Creator Owner and Creator Group would be used for
3182 * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this
3183 * would lead to usability problems under Windows: The Creator entries
3184 * are only available in browse lists of directories and not for files;
3185 * additionally the identity of the owning group couldn't be determined.
3186 * We therefore use those identities only for Default ACLs.
3189 /* Create the canon_ace lists. */
3190 file_ace = canonicalise_acl(conn, name, posix_acl, sbuf,
3191 &owner_sid, &group_sid, pal,
3192 SMB_ACL_TYPE_ACCESS);
3194 /* We must have *some* ACLS. */
3196 if (count_canon_ace_list(file_ace) == 0) {
3197 DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", name));
3201 if (S_ISDIR(sbuf->st_ex_mode) && def_acl) {
3202 dir_ace = canonicalise_acl(conn, name, def_acl,
3204 &global_sid_Creator_Owner,
3205 &global_sid_Creator_Group,
3206 pal, SMB_ACL_TYPE_DEFAULT);
3210 * Create the NT ACE list from the canonical ace lists.
3215 enum security_ace_type nt_acl_type;
3217 if (nt4_compatible_acls() && dir_ace) {
3219 * NT 4 chokes if an ACL contains an INHERIT_ONLY entry
3220 * but no non-INHERIT_ONLY entry for one SID. So we only
3221 * remove entries from the Access ACL if the
3222 * corresponding Default ACL entries have also been
3223 * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP
3224 * are exceptions. We can do nothing
3225 * intelligent if the Default ACL contains entries that
3226 * are not also contained in the Access ACL, so this
3227 * case will still fail under NT 4.
3230 ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL);
3231 if (ace && !ace->perms) {
3232 DLIST_REMOVE(dir_ace, ace);
3235 ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL);
3236 if (ace && !ace->perms) {
3237 DLIST_REMOVE(file_ace, ace);
3243 * WinNT doesn't usually have Creator Group
3244 * in browse lists, so we send this entry to
3245 * WinNT even if it contains no relevant
3246 * permissions. Once we can add
3247 * Creator Group to browse lists we can
3252 ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL);
3253 if (ace && !ace->perms) {
3254 DLIST_REMOVE(dir_ace, ace);
3259 ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL);
3260 if (ace && !ace->perms) {
3261 DLIST_REMOVE(file_ace, ace);
3266 num_acls = count_canon_ace_list(file_ace);
3267 num_def_acls = count_canon_ace_list(dir_ace);
3269 /* Allocate the ace list. */
3270 if ((nt_ace_list = SMB_MALLOC_ARRAY(SEC_ACE,num_acls + num_profile_acls + num_def_acls)) == NULL) {
3271 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
3275 memset(nt_ace_list, '\0', (num_acls + num_def_acls) * sizeof(SEC_ACE) );
3278 * Create the NT ACE list from the canonical ace lists.
3281 for (ace = file_ace; ace != NULL; ace = ace->next) {
3282 uint32_t acc = map_canon_ace_perms(SNUM(conn),
3285 S_ISDIR(sbuf->st_ex_mode));
3286 init_sec_ace(&nt_ace_list[num_aces++],
3293 /* The User must have access to a profile share - even
3294 * if we can't map the SID. */
3295 if (lp_profile_acls(SNUM(conn))) {
3296 add_or_replace_ace(nt_ace_list, &num_aces,
3297 &global_sid_Builtin_Users,
3298 SEC_ACE_TYPE_ACCESS_ALLOWED,
3299 FILE_GENERIC_ALL, 0);
3302 for (ace = dir_ace; ace != NULL; ace = ace->next) {
3303 uint32_t acc = map_canon_ace_perms(SNUM(conn),
3306 S_ISDIR(sbuf->st_ex_mode));
3307 init_sec_ace(&nt_ace_list[num_aces++],
3312 SEC_ACE_FLAG_OBJECT_INHERIT|
3313 SEC_ACE_FLAG_CONTAINER_INHERIT|
3314 SEC_ACE_FLAG_INHERIT_ONLY);
3317 /* The User must have access to a profile share - even
3318 * if we can't map the SID. */
3319 if (lp_profile_acls(SNUM(conn))) {
3320 add_or_replace_ace(nt_ace_list, &num_aces,
3321 &global_sid_Builtin_Users,
3322 SEC_ACE_TYPE_ACCESS_ALLOWED,
3324 SEC_ACE_FLAG_OBJECT_INHERIT |
3325 SEC_ACE_FLAG_CONTAINER_INHERIT |
3326 SEC_ACE_FLAG_INHERIT_ONLY);
3330 * Merge POSIX default ACLs and normal ACLs into one NT ACE.
3331 * Win2K needs this to get the inheritance correct when replacing ACLs
3332 * on a directory tree. Based on work by Jim @ IBM.
3335 num_aces = merge_default_aces(nt_ace_list, num_aces);
3337 if (lp_profile_acls(SNUM(conn))) {
3338 for (i = 0; i < num_aces; i++) {
3339 if (sid_equal(&nt_ace_list[i].trustee, &owner_sid)) {
3340 add_or_replace_ace(nt_ace_list, &num_aces,
3342 nt_ace_list[i].type,
3343 nt_ace_list[i].access_mask,
3344 nt_ace_list[i].flags);
3352 if((psa = make_sec_acl( talloc_tos(), NT4_ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
3353 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
3357 } /* security_info & DACL_SECURITY_INFORMATION */
3359 psd = make_standard_sec_desc( talloc_tos(),
3360 (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL,
3361 (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL,
3366 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
3372 * Windows 2000: The DACL_PROTECTED flag in the security
3373 * descriptor marks the ACL as non-inheriting, i.e., no
3374 * ACEs from higher level directories propagate to this
3375 * ACL. In the POSIX ACL model permissions are only
3376 * inherited at file create time, so ACLs never contain
3377 * any ACEs that are inherited dynamically. The DACL_PROTECTED
3378 * flag doesn't seem to bother Windows NT.
3379 * Always set this if map acl inherit is turned off.
3381 if (pal == NULL || !lp_map_acl_inherit(SNUM(conn))) {
3382 psd->type |= SEC_DESC_DACL_PROTECTED;
3384 psd->type |= pal->sd_type;
3388 dacl_sort_into_canonical_order(psd->dacl->aces, (unsigned int)psd->dacl->num_aces);
3396 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3399 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
3401 free_canon_ace_list(file_ace);
3402 free_canon_ace_list(dir_ace);
3403 free_inherited_info(pal);
3404 SAFE_FREE(nt_ace_list);
3406 return NT_STATUS_OK;
3409 NTSTATUS posix_fget_nt_acl(struct files_struct *fsp, uint32_t security_info,
3412 SMB_STRUCT_STAT sbuf;
3413 SMB_ACL_T posix_acl = NULL;
3414 struct pai_val *pal;
3418 DEBUG(10,("posix_fget_nt_acl: called for file %s\n",
3421 /* can it happen that fsp_name == NULL ? */
3422 if (fsp->is_directory || fsp->fh->fd == -1) {
3423 return posix_get_nt_acl(fsp->conn, fsp->fsp_name->base_name,
3424 security_info, ppdesc);
3427 /* Get the stat struct for the owner info. */
3428 if(SMB_VFS_FSTAT(fsp, &sbuf) != 0) {
3429 return map_nt_error_from_unix(errno);
3432 /* Get the ACL from the fd. */
3433 posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp);
3435 pal = fload_inherited_info(fsp);
3437 return posix_get_nt_acl_common(fsp->conn, fsp->fsp_name->base_name,
3438 &sbuf, pal, posix_acl, NULL,
3439 security_info, ppdesc);
3442 NTSTATUS posix_get_nt_acl(struct connection_struct *conn, const char *name,
3443 uint32_t security_info, SEC_DESC **ppdesc)
3445 SMB_ACL_T posix_acl = NULL;
3446 SMB_ACL_T def_acl = NULL;
3447 struct pai_val *pal;
3448 struct smb_filename smb_fname;
3453 DEBUG(10,("posix_get_nt_acl: called for file %s\n", name ));
3455 ZERO_STRUCT(smb_fname);
3456 smb_fname.base_name = discard_const_p(char, name);
3458 /* Get the stat struct for the owner info. */
3459 if (lp_posix_pathnames()) {
3460 ret = SMB_VFS_LSTAT(conn, &smb_fname);
3462 ret = SMB_VFS_STAT(conn, &smb_fname);
3466 return map_nt_error_from_unix(errno);
3469 /* Get the ACL from the path. */
3470 posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, name, SMB_ACL_TYPE_ACCESS);
3472 /* If it's a directory get the default POSIX ACL. */
3473 if(S_ISDIR(smb_fname.st.st_ex_mode)) {
3474 def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, name, SMB_ACL_TYPE_DEFAULT);
3475 def_acl = free_empty_sys_acl(conn, def_acl);
3478 pal = load_inherited_info(conn, name);
3480 return posix_get_nt_acl_common(conn, name, &smb_fname.st, pal,
3481 posix_acl, def_acl, security_info,
3485 /****************************************************************************
3486 Try to chown a file. We will be able to chown it under the following conditions.
3488 1) If we have root privileges, then it will just work.
3489 2) If we have SeTakeOwnershipPrivilege we can change the user to the current user.
3490 3) If we have SeRestorePrivilege we can change the user to any other user.
3491 4) If we have write permission to the file and dos_filemodes is set
3492 then allow chown to the currently authenticated user.
3493 ****************************************************************************/
3495 int try_chown(connection_struct *conn, struct smb_filename *smb_fname,
3496 uid_t uid, gid_t gid)
3501 if(!CAN_WRITE(conn)) {
3506 /* try the direct way first */
3507 if (lp_posix_pathnames()) {
3508 ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, uid, gid);
3510 ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid, gid);
3516 /* Case (2) / (3) */
3517 if (lp_enable_privileges()) {
3519 bool has_take_ownership_priv = user_has_privileges(current_user.nt_user_token,
3520 &se_take_ownership);
3521 bool has_restore_priv = user_has_privileges(current_user.nt_user_token,
3525 if ( ( has_take_ownership_priv && ( uid == current_user.ut.uid ) ) ||
3527 ( has_restore_priv ) ) {
3530 /* Keep the current file gid the same - take ownership doesn't imply group change. */
3531 if (lp_posix_pathnames()) {
3532 ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, uid,
3535 ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid,
3544 if (!lp_dos_filemode(SNUM(conn))) {
3549 /* only allow chown to the current user. This is more secure,
3550 and also copes with the case where the SID in a take ownership ACL is
3551 a local SID on the users workstation
3553 if (uid != current_user.ut.uid) {
3558 if (lp_posix_pathnames()) {
3559 ret = SMB_VFS_LSTAT(conn, smb_fname);
3561 ret = SMB_VFS_STAT(conn, smb_fname);
3568 if (!NT_STATUS_IS_OK(open_file_fchmod(conn, smb_fname, &fsp))) {
3573 /* Keep the current file gid the same. */
3574 if (fsp->fh->fd == -1) {
3575 if (lp_posix_pathnames()) {
3576 ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, uid,
3579 ret = SMB_VFS_CHOWN(conn, smb_fname->base_name, uid,
3583 ret = SMB_VFS_FCHOWN(fsp, uid, (gid_t)-1);
3587 close_file(NULL, fsp, NORMAL_CLOSE);
3593 /* Disable this - prevents ACL inheritance from the ACL editor. JRA. */
3595 /****************************************************************************
3596 Take care of parent ACL inheritance.
3597 ****************************************************************************/
3599 NTSTATUS append_parent_acl(files_struct *fsp,
3600 const SEC_DESC *pcsd,
3601 SEC_DESC **pp_new_sd)
3603 struct smb_filename *smb_dname = NULL;
3604 SEC_DESC *parent_sd = NULL;
3605 files_struct *parent_fsp = NULL;
3606 TALLOC_CTX *mem_ctx = talloc_tos();
3607 char *parent_name = NULL;
3608 SEC_ACE *new_ace = NULL;
3609 unsigned int num_aces = pcsd->dacl->num_aces;
3613 SEC_DESC *psd = dup_sec_desc(talloc_tos(), pcsd);
3614 bool is_dacl_protected = (pcsd->type & SEC_DESC_DACL_PROTECTED);
3617 return NT_STATUS_NO_MEMORY;
3620 if (!parent_dirname(mem_ctx, fsp->fsp_name->base_name, &parent_name,
3622 return NT_STATUS_NO_MEMORY;
3625 status = create_synthetic_smb_fname(mem_ctx, parent_name, NULL, NULL,
3627 if (!NT_STATUS_IS_OK(status)) {
3631 status = SMB_VFS_CREATE_FILE(
3632 fsp->conn, /* conn */
3634 0, /* root_dir_fid */
3635 smb_dname, /* fname */
3636 FILE_READ_ATTRIBUTES, /* access_mask */
3637 FILE_SHARE_NONE, /* share_access */
3638 FILE_OPEN, /* create_disposition*/
3639 FILE_DIRECTORY_FILE, /* create_options */
3640 0, /* file_attributes */
3641 INTERNAL_OPEN_ONLY, /* oplock_request */
3642 0, /* allocation_size */
3645 &parent_fsp, /* result */
3648 if (!NT_STATUS_IS_OK(status)) {
3649 TALLOC_FREE(smb_dname);
3653 status = SMB_VFS_GET_NT_ACL(parent_fsp->conn, smb_dname->base_name,
3654 DACL_SECURITY_INFORMATION, &parent_sd );
3656 close_file(NULL, parent_fsp, NORMAL_CLOSE);
3657 TALLOC_FREE(smb_dname);
3659 if (!NT_STATUS_IS_OK(status)) {
3664 * Make room for potentially all the ACLs from
3665 * the parent. We used to add the ugw triple here,
3666 * as we knew we were dealing with POSIX ACLs.
3667 * We no longer need to do so as we can guarentee
3668 * that a default ACL from the parent directory will
3669 * be well formed for POSIX ACLs if it came from a
3670 * POSIX ACL source, and if we're not writing to a
3671 * POSIX ACL sink then we don't care if it's not well
3675 num_aces += parent_sd->dacl->num_aces;
3677 if((new_ace = TALLOC_ZERO_ARRAY(mem_ctx, SEC_ACE,
3678 num_aces)) == NULL) {
3679 return NT_STATUS_NO_MEMORY;
3682 /* Start by copying in all the given ACE entries. */
3683 for (i = 0; i < psd->dacl->num_aces; i++) {
3684 sec_ace_copy(&new_ace[i], &psd->dacl->aces[i]);
3688 * Note that we're ignoring "inherit permissions" here
3689 * as that really only applies to newly created files. JRA.
3692 /* Finally append any inherited ACEs. */
3693 for (j = 0; j < parent_sd->dacl->num_aces; j++) {
3694 SEC_ACE *se = &parent_sd->dacl->aces[j];
3696 if (fsp->is_directory) {
3697 if (!(se->flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
3698 /* Doesn't apply to a directory - ignore. */
3699 DEBUG(10,("append_parent_acl: directory %s "
3700 "ignoring non container "
3701 "inherit flags %u on ACE with sid %s "
3704 (unsigned int)se->flags,
3705 sid_string_dbg(&se->trustee),
3710 if (!(se->flags & SEC_ACE_FLAG_OBJECT_INHERIT)) {
3711 /* Doesn't apply to a file - ignore. */
3712 DEBUG(10,("append_parent_acl: file %s "
3713 "ignoring non object "
3714 "inherit flags %u on ACE with sid %s "
3717 (unsigned int)se->flags,
3718 sid_string_dbg(&se->trustee),
3724 if (is_dacl_protected) {
3725 /* If the DACL is protected it means we must
3726 * not overwrite an existing ACE entry with the
3727 * same SID. This is order N^2. Ouch :-(. JRA. */
3729 for (k = 0; k < psd->dacl->num_aces; k++) {
3730 if (sid_equal(&psd->dacl->aces[k].trustee,
3735 if (k < psd->dacl->num_aces) {
3736 /* SID matched. Ignore. */
3737 DEBUG(10,("append_parent_acl: path %s "
3738 "ignoring ACE with protected sid %s "
3741 sid_string_dbg(&se->trustee),
3747 sec_ace_copy(&new_ace[i], se);
3748 if (se->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
3749 new_ace[i].flags &= ~(SEC_ACE_FLAG_VALID_INHERIT);
3751 new_ace[i].flags |= SEC_ACE_FLAG_INHERITED_ACE;
3753 if (fsp->is_directory) {
3755 * Strip off any inherit only. It's applied.
3757 new_ace[i].flags &= ~(SEC_ACE_FLAG_INHERIT_ONLY);
3758 if (se->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
3759 /* No further inheritance. */
3761 ~(SEC_ACE_FLAG_CONTAINER_INHERIT|
3762 SEC_ACE_FLAG_OBJECT_INHERIT);
3766 * Strip off any container or inherit
3767 * flags, they can't apply to objects.
3769 new_ace[i].flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|
3770 SEC_ACE_FLAG_INHERIT_ONLY|
3771 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT);
3775 DEBUG(10,("append_parent_acl: path %s "
3776 "inheriting ACE with sid %s "
3779 sid_string_dbg(&se->trustee),
3783 psd->dacl->aces = new_ace;
3784 psd->dacl->num_aces = i;
3785 psd->type &= ~(SE_DESC_DACL_AUTO_INHERITED|
3786 SE_DESC_DACL_AUTO_INHERIT_REQ);
3793 /****************************************************************************
3794 Reply to set a security descriptor on an fsp. security_info_sent is the
3795 description of the following NT ACL.
3796 This should be the only external function needed for the UNIX style set ACL.
3797 ****************************************************************************/
3799 NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC *psd_orig)
3801 connection_struct *conn = fsp->conn;
3802 uid_t user = (uid_t)-1;
3803 gid_t grp = (gid_t)-1;
3804 DOM_SID file_owner_sid;
3805 DOM_SID file_grp_sid;
3806 canon_ace *file_ace_list = NULL;
3807 canon_ace *dir_ace_list = NULL;
3808 bool acl_perms = False;
3809 mode_t orig_mode = (mode_t)0;
3811 bool set_acl_as_root = false;
3812 bool acl_set_support = false;
3814 SEC_DESC *psd = NULL;
3816 DEBUG(10,("set_nt_acl: called for file %s\n",
3819 if (!CAN_WRITE(conn)) {
3820 DEBUG(10,("set acl rejected on read-only share\n"));
3821 return NT_STATUS_MEDIA_WRITE_PROTECTED;
3825 return NT_STATUS_INVALID_PARAMETER;
3828 psd = dup_sec_desc(talloc_tos(), psd_orig);
3830 return NT_STATUS_NO_MEMORY;
3834 * Get the current state of the file.
3837 status = vfs_stat_fsp(fsp);
3838 if (!NT_STATUS_IS_OK(status)) {
3842 /* Save the original element we check against. */
3843 orig_mode = fsp->fsp_name->st.st_ex_mode;
3846 * Unpack the user/group/world id's.
3849 /* POSIX can't cope with missing owner/group. */
3850 if ((security_info_sent & SECINFO_OWNER) && (psd->owner_sid == NULL)) {
3851 security_info_sent &= ~SECINFO_OWNER;
3853 if ((security_info_sent & SECINFO_GROUP) && (psd->group_sid == NULL)) {
3854 security_info_sent &= ~SECINFO_GROUP;
3857 status = unpack_nt_owners( SNUM(conn), &user, &grp, security_info_sent, psd);
3858 if (!NT_STATUS_IS_OK(status)) {
3863 * Do we need to chown ? If so this must be done first as the incoming
3864 * CREATOR_OWNER acl will be relative to the *new* owner, not the old.
3868 if (((user != (uid_t)-1) && (fsp->fsp_name->st.st_ex_uid != user)) ||
3869 (( grp != (gid_t)-1) && (fsp->fsp_name->st.st_ex_gid != grp))) {
3871 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3872 fsp_str_dbg(fsp), (unsigned int)user,
3873 (unsigned int)grp));
3875 if(try_chown(fsp->conn, fsp->fsp_name, user, grp) == -1) {
3876 DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error "
3877 "= %s.\n", fsp_str_dbg(fsp),
3878 (unsigned int)user, (unsigned int)grp,
3880 if (errno == EPERM) {
3881 return NT_STATUS_INVALID_OWNER;
3883 return map_nt_error_from_unix(errno);
3887 * Recheck the current state of the file, which may have changed.
3888 * (suid/sgid bits, for instance)
3891 status = vfs_stat_fsp(fsp);
3892 if (!NT_STATUS_IS_OK(status)) {
3896 /* Save the original element we check against. */
3897 orig_mode = fsp->fsp_name->st.st_ex_mode;
3899 /* If we successfully chowned, we know we must
3900 * be able to set the acl, so do it as root.
3902 set_acl_as_root = true;
3905 create_file_sids(&fsp->fsp_name->st, &file_owner_sid, &file_grp_sid);
3907 if((security_info_sent & SECINFO_DACL) &&
3908 (psd->type & SEC_DESC_DACL_PRESENT) &&
3909 (psd->dacl == NULL)) {
3912 /* We can't have NULL DACL in POSIX.
3913 Use owner/group/Everyone -> full access. */
3915 init_sec_ace(&ace[0],
3917 SEC_ACE_TYPE_ACCESS_ALLOWED,
3920 init_sec_ace(&ace[1],
3922 SEC_ACE_TYPE_ACCESS_ALLOWED,
3925 init_sec_ace(&ace[2],
3927 SEC_ACE_TYPE_ACCESS_ALLOWED,
3930 psd->dacl = make_sec_acl(talloc_tos(),
3934 if (psd->dacl == NULL) {
3935 return NT_STATUS_NO_MEMORY;
3937 security_acl_map_generic(psd->dacl, &file_generic_mapping);
3940 acl_perms = unpack_canon_ace(fsp, &fsp->fsp_name->st, &file_owner_sid,
3941 &file_grp_sid, &file_ace_list,
3942 &dir_ace_list, security_info_sent, psd);
3944 /* Ignore W2K traverse DACL set. */
3945 if (!file_ace_list && !dir_ace_list) {
3946 return NT_STATUS_OK;
3950 DEBUG(3,("set_nt_acl: cannot set permissions\n"));
3951 free_canon_ace_list(file_ace_list);
3952 free_canon_ace_list(dir_ace_list);
3953 return NT_STATUS_ACCESS_DENIED;
3957 * Only change security if we got a DACL.
3960 if(!(security_info_sent & DACL_SECURITY_INFORMATION) || (psd->dacl == NULL)) {
3961 free_canon_ace_list(file_ace_list);
3962 free_canon_ace_list(dir_ace_list);
3963 return NT_STATUS_OK;
3967 * Try using the POSIX ACL set first. Fall back to chmod if
3968 * we have no ACL support on this filesystem.
3971 if (acl_perms && file_ace_list) {
3972 if (set_acl_as_root) {
3975 ret = set_canon_ace_list(fsp, file_ace_list, false,
3976 &fsp->fsp_name->st, &acl_set_support);
3977 if (set_acl_as_root) {
3980 if (acl_set_support && ret == false) {
3981 DEBUG(3,("set_nt_acl: failed to set file acl on file "
3982 "%s (%s).\n", fsp_str_dbg(fsp),
3984 free_canon_ace_list(file_ace_list);
3985 free_canon_ace_list(dir_ace_list);
3986 return map_nt_error_from_unix(errno);
3990 if (acl_perms && acl_set_support && fsp->is_directory) {
3992 if (set_acl_as_root) {
3995 ret = set_canon_ace_list(fsp, dir_ace_list, true,
3998 if (set_acl_as_root) {
4002 DEBUG(3,("set_nt_acl: failed to set default "
4003 "acl on directory %s (%s).\n",
4004 fsp_str_dbg(fsp), strerror(errno)));
4005 free_canon_ace_list(file_ace_list);
4006 free_canon_ace_list(dir_ace_list);
4007 return map_nt_error_from_unix(errno);
4013 * No default ACL - delete one if it exists.
4016 if (set_acl_as_root) {
4019 sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn,
4020 fsp->fsp_name->base_name);
4021 if (set_acl_as_root) {
4025 if (acl_group_override(conn, fsp->fsp_name)) {
4026 DEBUG(5,("set_nt_acl: acl group "
4027 "control on and current user "
4028 "in file %s primary group. "
4029 "Override delete_def_acl\n",
4034 SMB_VFS_SYS_ACL_DELETE_DEF_FILE(
4036 fsp->fsp_name->base_name);
4041 DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
4042 free_canon_ace_list(file_ace_list);
4043 free_canon_ace_list(dir_ace_list);
4044 return map_nt_error_from_unix(errno);
4050 if (acl_set_support) {
4051 if (set_acl_as_root) {
4054 store_inheritance_attributes(fsp,
4058 if (set_acl_as_root) {
4064 * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
4067 if(!acl_set_support && acl_perms) {
4070 if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
4071 free_canon_ace_list(file_ace_list);
4072 free_canon_ace_list(dir_ace_list);
4073 DEBUG(3,("set_nt_acl: failed to convert file acl to "
4074 "posix permissions for file %s.\n",
4076 return NT_STATUS_ACCESS_DENIED;
4079 if (orig_mode != posix_perms) {
4082 DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
4083 fsp_str_dbg(fsp), (unsigned int)posix_perms));
4085 if (set_acl_as_root) {
4088 sret = SMB_VFS_CHMOD(conn, fsp->fsp_name->base_name,
4090 if (set_acl_as_root) {
4094 if (acl_group_override(conn, fsp->fsp_name)) {
4095 DEBUG(5,("set_nt_acl: acl group "
4096 "control on and current user "
4097 "in file %s primary group. "
4102 sret = SMB_VFS_CHMOD(conn,
4103 fsp->fsp_name->base_name,
4109 DEBUG(3,("set_nt_acl: chmod %s, 0%o "
4110 "failed. Error = %s.\n",
4112 (unsigned int)posix_perms,
4114 free_canon_ace_list(file_ace_list);
4115 free_canon_ace_list(dir_ace_list);
4116 return map_nt_error_from_unix(errno);
4122 free_canon_ace_list(file_ace_list);
4123 free_canon_ace_list(dir_ace_list);
4125 /* Ensure the stat struct in the fsp is correct. */
4126 status = vfs_stat_fsp(fsp);
4128 return NT_STATUS_OK;
4131 /****************************************************************************
4132 Get the actual group bits stored on a file with an ACL. Has no effect if
4133 the file has no ACL. Needed in dosmode code where the stat() will return
4134 the mask bits, not the real group bits, for a file with an ACL.
4135 ****************************************************************************/
4137 int get_acl_group_bits( connection_struct *conn, const char *fname, mode_t *mode )
4139 int entry_id = SMB_ACL_FIRST_ENTRY;
4140 SMB_ACL_ENTRY_T entry;
4141 SMB_ACL_T posix_acl;
4144 posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS);
4145 if (posix_acl == (SMB_ACL_T)NULL)
4148 while (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
4149 SMB_ACL_TAG_T tagtype;
4150 SMB_ACL_PERMSET_T permset;
4152 entry_id = SMB_ACL_NEXT_ENTRY;
4154 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) ==-1)
4157 if (tagtype == SMB_ACL_GROUP_OBJ) {
4158 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
4161 *mode &= ~(S_IRGRP|S_IWGRP|S_IXGRP);
4162 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRGRP : 0);
4163 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWGRP : 0);
4164 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXGRP : 0);
4170 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
4174 /****************************************************************************
4175 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
4176 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
4177 ****************************************************************************/
4179 static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mode_t mode)
4181 int entry_id = SMB_ACL_FIRST_ENTRY;
4182 SMB_ACL_ENTRY_T entry;
4183 int num_entries = 0;
4185 while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
4186 SMB_ACL_TAG_T tagtype;
4187 SMB_ACL_PERMSET_T permset;
4190 entry_id = SMB_ACL_NEXT_ENTRY;
4192 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
4195 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
4201 case SMB_ACL_USER_OBJ:
4202 perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
4204 case SMB_ACL_GROUP_OBJ:
4205 perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
4209 * FIXME: The ACL_MASK entry permissions should really be set to
4210 * the union of the permissions of all ACL_USER,
4211 * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what
4212 * acl_calc_mask() does, but Samba ACLs doesn't provide it.
4214 perms = S_IRUSR|S_IWUSR|S_IXUSR;
4217 perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
4223 if (map_acl_perms_to_permset(conn, perms, &permset) == -1)
4226 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) == -1)
4231 * If this is a simple 3 element ACL or no elements then it's a standard
4232 * UNIX permission set. Just use chmod...
4235 if ((num_entries == 3) || (num_entries == 0))
4241 /****************************************************************************
4242 Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ,
4243 GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the
4244 resulting ACL on TO. Note that name is in UNIX character set.
4245 ****************************************************************************/
4247 static int copy_access_posix_acl(connection_struct *conn, const char *from, const char *to, mode_t mode)
4249 SMB_ACL_T posix_acl = NULL;
4252 if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL)
4255 if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
4258 ret = SMB_VFS_SYS_ACL_SET_FILE(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl);
4262 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
4266 /****************************************************************************
4267 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
4268 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
4269 Note that name is in UNIX character set.
4270 ****************************************************************************/
4272 int chmod_acl(connection_struct *conn, const char *name, mode_t mode)
4274 return copy_access_posix_acl(conn, name, name, mode);
4277 /****************************************************************************
4278 Check for an existing default POSIX ACL on a directory.
4279 ****************************************************************************/
4281 static bool directory_has_default_posix_acl(connection_struct *conn, const char *fname)
4283 SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT);
4284 bool has_acl = False;
4285 SMB_ACL_ENTRY_T entry;
4287 if (def_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, def_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) {
4292 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4297 /****************************************************************************
4298 If the parent directory has no default ACL but it does have an Access ACL,
4299 inherit this Access ACL to file name.
4300 ****************************************************************************/
4302 int inherit_access_posix_acl(connection_struct *conn, const char *inherit_from_dir,
4303 const char *name, mode_t mode)
4305 if (directory_has_default_posix_acl(conn, inherit_from_dir))
4308 return copy_access_posix_acl(conn, inherit_from_dir, name, mode);
4311 /****************************************************************************
4312 Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
4313 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
4314 ****************************************************************************/
4316 int fchmod_acl(files_struct *fsp, mode_t mode)
4318 connection_struct *conn = fsp->conn;
4319 SMB_ACL_T posix_acl = NULL;
4322 if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp)) == NULL)
4325 if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
4328 ret = SMB_VFS_SYS_ACL_SET_FD(fsp, posix_acl);
4332 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
4336 /****************************************************************************
4337 Map from wire type to permset.
4338 ****************************************************************************/
4340 static bool unix_ex_wire_to_permset(connection_struct *conn, unsigned char wire_perm, SMB_ACL_PERMSET_T *p_permset)
4342 if (wire_perm & ~(SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE)) {
4346 if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) == -1) {
4350 if (wire_perm & SMB_POSIX_ACL_READ) {
4351 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1) {
4355 if (wire_perm & SMB_POSIX_ACL_WRITE) {
4356 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1) {
4360 if (wire_perm & SMB_POSIX_ACL_EXECUTE) {
4361 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1) {
4368 /****************************************************************************
4369 Map from wire type to tagtype.
4370 ****************************************************************************/
4372 static bool unix_ex_wire_to_tagtype(unsigned char wire_tt, SMB_ACL_TAG_T *p_tt)
4375 case SMB_POSIX_ACL_USER_OBJ:
4376 *p_tt = SMB_ACL_USER_OBJ;
4378 case SMB_POSIX_ACL_USER:
4379 *p_tt = SMB_ACL_USER;
4381 case SMB_POSIX_ACL_GROUP_OBJ:
4382 *p_tt = SMB_ACL_GROUP_OBJ;
4384 case SMB_POSIX_ACL_GROUP:
4385 *p_tt = SMB_ACL_GROUP;
4387 case SMB_POSIX_ACL_MASK:
4388 *p_tt = SMB_ACL_MASK;
4390 case SMB_POSIX_ACL_OTHER:
4391 *p_tt = SMB_ACL_OTHER;
4399 /****************************************************************************
4400 Create a new POSIX acl from wire permissions.
4401 FIXME ! How does the share mask/mode fit into this.... ?
4402 ****************************************************************************/
4404 static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_acls, const char *pdata)
4407 SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, num_acls);
4409 if (the_acl == NULL) {
4413 for (i = 0; i < num_acls; i++) {
4414 SMB_ACL_ENTRY_T the_entry;
4415 SMB_ACL_PERMSET_T the_permset;
4416 SMB_ACL_TAG_T tag_type;
4418 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
4419 DEBUG(0,("create_posix_acl_from_wire: Failed to create entry %u. (%s)\n",
4420 i, strerror(errno) ));
4424 if (!unix_ex_wire_to_tagtype(CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), &tag_type)) {
4425 DEBUG(0,("create_posix_acl_from_wire: invalid wire tagtype %u on entry %u.\n",
4426 CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), i ));
4430 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, tag_type) == -1) {
4431 DEBUG(0,("create_posix_acl_from_wire: Failed to set tagtype on entry %u. (%s)\n",
4432 i, strerror(errno) ));
4436 /* Get the permset pointer from the new ACL entry. */
4437 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
4438 DEBUG(0,("create_posix_acl_from_wire: Failed to get permset on entry %u. (%s)\n",
4439 i, strerror(errno) ));
4443 /* Map from wire to permissions. */
4444 if (!unix_ex_wire_to_permset(conn, CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+1), &the_permset)) {
4445 DEBUG(0,("create_posix_acl_from_wire: invalid permset %u on entry %u.\n",
4446 CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE) + 1), i ));
4450 /* Now apply to the new ACL entry. */
4451 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
4452 DEBUG(0,("create_posix_acl_from_wire: Failed to add permset on entry %u. (%s)\n",
4453 i, strerror(errno) ));
4457 if (tag_type == SMB_ACL_USER) {
4458 uint32 uidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
4459 uid_t uid = (uid_t)uidval;
4460 if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&uid) == -1) {
4461 DEBUG(0,("create_posix_acl_from_wire: Failed to set uid %u on entry %u. (%s)\n",
4462 (unsigned int)uid, i, strerror(errno) ));
4467 if (tag_type == SMB_ACL_GROUP) {
4468 uint32 gidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
4469 gid_t gid = (uid_t)gidval;
4470 if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&gid) == -1) {
4471 DEBUG(0,("create_posix_acl_from_wire: Failed to set gid %u on entry %u. (%s)\n",
4472 (unsigned int)gid, i, strerror(errno) ));
4482 if (the_acl != NULL) {
4483 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
4488 /****************************************************************************
4489 Calls from UNIX extensions - Default POSIX ACL set.
4490 If num_def_acls == 0 and not a directory just return. If it is a directory
4491 and num_def_acls == 0 then remove the default acl. Else set the default acl
4493 ****************************************************************************/
4495 bool set_unix_posix_default_acl(connection_struct *conn, const char *fname, const SMB_STRUCT_STAT *psbuf,
4496 uint16 num_def_acls, const char *pdata)
4498 SMB_ACL_T def_acl = NULL;
4500 if (!S_ISDIR(psbuf->st_ex_mode)) {
4502 DEBUG(5,("set_unix_posix_default_acl: Can't set default ACL on non-directory file %s\n", fname ));
4510 if (!num_def_acls) {
4511 /* Remove the default ACL. */
4512 if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fname) == -1) {
4513 DEBUG(5,("set_unix_posix_default_acl: acl_delete_def_file failed on directory %s (%s)\n",
4514 fname, strerror(errno) ));
4520 if ((def_acl = create_posix_acl_from_wire(conn, num_def_acls, pdata)) == NULL) {
4524 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT, def_acl) == -1) {
4525 DEBUG(5,("set_unix_posix_default_acl: acl_set_file failed on directory %s (%s)\n",
4526 fname, strerror(errno) ));
4527 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4531 DEBUG(10,("set_unix_posix_default_acl: set default acl for file %s\n", fname ));
4532 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
4536 /****************************************************************************
4537 Remove an ACL from a file. As we don't have acl_delete_entry() available
4538 we must read the current acl and copy all entries except MASK, USER and GROUP
4539 to a new acl, then set that. This (at least on Linux) causes any ACL to be
4541 FIXME ! How does the share mask/mode fit into this.... ?
4542 ****************************************************************************/
4544 static bool remove_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname)
4546 SMB_ACL_T file_acl = NULL;
4547 int entry_id = SMB_ACL_FIRST_ENTRY;
4548 SMB_ACL_ENTRY_T entry;
4550 /* Create a new ACL with only 3 entries, u/g/w. */
4551 SMB_ACL_T new_file_acl = SMB_VFS_SYS_ACL_INIT(conn, 3);
4552 SMB_ACL_ENTRY_T user_ent = NULL;
4553 SMB_ACL_ENTRY_T group_ent = NULL;
4554 SMB_ACL_ENTRY_T other_ent = NULL;
4556 if (new_file_acl == NULL) {
4557 DEBUG(5,("remove_posix_acl: failed to init new ACL with 3 entries for file %s.\n", fname));
4561 /* Now create the u/g/w entries. */
4562 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &user_ent) == -1) {
4563 DEBUG(5,("remove_posix_acl: Failed to create user entry for file %s. (%s)\n",
4564 fname, strerror(errno) ));
4567 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, user_ent, SMB_ACL_USER_OBJ) == -1) {
4568 DEBUG(5,("remove_posix_acl: Failed to set user entry for file %s. (%s)\n",
4569 fname, strerror(errno) ));
4573 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &group_ent) == -1) {
4574 DEBUG(5,("remove_posix_acl: Failed to create group entry for file %s. (%s)\n",
4575 fname, strerror(errno) ));
4578 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, group_ent, SMB_ACL_GROUP_OBJ) == -1) {
4579 DEBUG(5,("remove_posix_acl: Failed to set group entry for file %s. (%s)\n",
4580 fname, strerror(errno) ));
4584 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &other_ent) == -1) {
4585 DEBUG(5,("remove_posix_acl: Failed to create other entry for file %s. (%s)\n",
4586 fname, strerror(errno) ));
4589 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, other_ent, SMB_ACL_OTHER) == -1) {
4590 DEBUG(5,("remove_posix_acl: Failed to set other entry for file %s. (%s)\n",
4591 fname, strerror(errno) ));
4595 /* Get the current file ACL. */
4596 if (fsp && fsp->fh->fd != -1) {
4597 file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp);
4599 file_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_ACCESS);
4602 if (file_acl == NULL) {
4603 /* This is only returned if an error occurred. Even for a file with
4604 no acl a u/g/w acl should be returned. */
4605 DEBUG(5,("remove_posix_acl: failed to get ACL from file %s (%s).\n",
4606 fname, strerror(errno) ));
4610 while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, file_acl, entry_id, &entry) == 1) {
4611 SMB_ACL_TAG_T tagtype;
4612 SMB_ACL_PERMSET_T permset;
4614 entry_id = SMB_ACL_NEXT_ENTRY;
4616 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
4617 DEBUG(5,("remove_posix_acl: failed to get tagtype from ACL on file %s (%s).\n",
4618 fname, strerror(errno) ));
4622 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
4623 DEBUG(5,("remove_posix_acl: failed to get permset from ACL on file %s (%s).\n",
4624 fname, strerror(errno) ));
4628 if (tagtype == SMB_ACL_USER_OBJ) {
4629 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, user_ent, permset) == -1) {
4630 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
4631 fname, strerror(errno) ));
4633 } else if (tagtype == SMB_ACL_GROUP_OBJ) {
4634 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, group_ent, permset) == -1) {
4635 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
4636 fname, strerror(errno) ));
4638 } else if (tagtype == SMB_ACL_OTHER) {
4639 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, other_ent, permset) == -1) {
4640 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
4641 fname, strerror(errno) ));
4646 /* Set the new empty file ACL. */
4647 if (fsp && fsp->fh->fd != -1) {
4648 if (SMB_VFS_SYS_ACL_SET_FD(fsp, new_file_acl) == -1) {
4649 DEBUG(5,("remove_posix_acl: acl_set_file failed on %s (%s)\n",
4650 fname, strerror(errno) ));
4654 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, new_file_acl) == -1) {
4655 DEBUG(5,("remove_posix_acl: acl_set_file failed on %s (%s)\n",
4656 fname, strerror(errno) ));
4666 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4669 SMB_VFS_SYS_ACL_FREE_ACL(conn, new_file_acl);
4674 /****************************************************************************
4675 Calls from UNIX extensions - POSIX ACL set.
4676 If num_def_acls == 0 then read/modify/write acl after removing all entries
4677 except SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER.
4678 ****************************************************************************/
4680 bool set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname, uint16 num_acls, const char *pdata)
4682 SMB_ACL_T file_acl = NULL;
4685 /* Remove the ACL from the file. */
4686 return remove_posix_acl(conn, fsp, fname);
4689 if ((file_acl = create_posix_acl_from_wire(conn, num_acls, pdata)) == NULL) {
4693 if (fsp && fsp->fh->fd != -1) {
4694 /* The preferred way - use an open fd. */
4695 if (SMB_VFS_SYS_ACL_SET_FD(fsp, file_acl) == -1) {
4696 DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
4697 fname, strerror(errno) ));
4698 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4702 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, file_acl) == -1) {
4703 DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
4704 fname, strerror(errno) ));
4705 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4710 DEBUG(10,("set_unix_posix_acl: set acl for file %s\n", fname ));
4711 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
4715 /********************************************************************
4716 Pull the NT ACL from a file on disk or the OpenEventlog() access
4717 check. Caller is responsible for freeing the returned security
4718 descriptor via TALLOC_FREE(). This is designed for dealing with
4719 user space access checks in smbd outside of the VFS. For example,
4720 checking access rights in OpenEventlog().
4722 Assume we are dealing with files (for now)
4723 ********************************************************************/
4725 SEC_DESC *get_nt_acl_no_snum( TALLOC_CTX *ctx, const char *fname)
4727 SEC_DESC *psd, *ret_sd;
4728 connection_struct *conn;
4730 struct fd_handle fh;
4733 conn = TALLOC_ZERO_P(ctx, connection_struct);
4735 DEBUG(0, ("talloc failed\n"));
4739 if (!(conn->params = TALLOC_P(conn, struct share_params))) {
4740 DEBUG(0,("get_nt_acl_no_snum: talloc() failed!\n"));
4745 conn->params->service = -1;
4747 set_conn_connectpath(conn, "/");
4749 if (!smbd_vfs_init(conn)) {
4750 DEBUG(0,("get_nt_acl_no_snum: Unable to create a fake connection struct!\n"));
4755 ZERO_STRUCT( finfo );
4763 status = create_synthetic_smb_fname(talloc_tos(), fname, NULL, NULL,
4765 if (!NT_STATUS_IS_OK(status)) {
4770 if (!NT_STATUS_IS_OK(SMB_VFS_FGET_NT_ACL( &finfo, DACL_SECURITY_INFORMATION, &psd))) {
4771 DEBUG(0,("get_nt_acl_no_snum: get_nt_acl returned zero.\n"));
4772 TALLOC_FREE(finfo.fsp_name);
4777 ret_sd = dup_sec_desc( ctx, psd );
4779 TALLOC_FREE(finfo.fsp_name);
4785 /* Stolen shamelessly from pvfs_default_acl() in source4 :-). */
4787 NTSTATUS make_default_filesystem_acl(TALLOC_CTX *ctx,
4789 SMB_STRUCT_STAT *psbuf,
4792 struct dom_sid owner_sid, group_sid;
4795 uint32_t access_mask = 0;
4796 mode_t mode = psbuf->st_ex_mode;
4797 SEC_ACL *new_dacl = NULL;
4800 DEBUG(10,("make_default_filesystem_acl: file %s mode = 0%o\n",
4803 uid_to_sid(&owner_sid, psbuf->st_ex_uid);
4804 gid_to_sid(&group_sid, psbuf->st_ex_gid);
4807 We provide up to 4 ACEs
4814 if (mode & S_IRUSR) {
4815 if (mode & S_IWUSR) {
4816 access_mask |= SEC_RIGHTS_FILE_ALL;
4818 access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
4821 if (mode & S_IWUSR) {
4822 access_mask |= SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE;
4825 init_sec_ace(&aces[idx],
4827 SEC_ACE_TYPE_ACCESS_ALLOWED,
4833 if (mode & S_IRGRP) {
4834 access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
4836 if (mode & S_IWGRP) {
4837 /* note that delete is not granted - this matches posix behaviour */
4838 access_mask |= SEC_RIGHTS_FILE_WRITE;
4841 init_sec_ace(&aces[idx],
4843 SEC_ACE_TYPE_ACCESS_ALLOWED,
4850 if (mode & S_IROTH) {
4851 access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
4853 if (mode & S_IWOTH) {
4854 access_mask |= SEC_RIGHTS_FILE_WRITE;
4857 init_sec_ace(&aces[idx],
4859 SEC_ACE_TYPE_ACCESS_ALLOWED,
4865 init_sec_ace(&aces[idx],
4867 SEC_ACE_TYPE_ACCESS_ALLOWED,
4868 SEC_RIGHTS_FILE_ALL,
4872 new_dacl = make_sec_acl(ctx,
4878 return NT_STATUS_NO_MEMORY;
4881 *ppdesc = make_sec_desc(ctx,
4882 SECURITY_DESCRIPTOR_REVISION_1,
4883 SEC_DESC_SELF_RELATIVE|SEC_DESC_DACL_PRESENT,
4890 return NT_STATUS_NO_MEMORY;
4892 return NT_STATUS_OK;