2 Unix SMB/CIFS implementation.
3 SMB NT Security Descriptor / Unix permission conversion.
4 Copyright (C) Jeremy Allison 1994-2000
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 /****************************************************************************
24 Data structures representing the internal ACE format.
25 ****************************************************************************/
27 enum ace_owner
{UID_ACE
, GID_ACE
, WORLD_ACE
};
28 enum ace_attribute
{ALLOW_ACE
, DENY_ACE
}; /* Used for incoming NT ACLS. */
30 typedef union posix_id
{
36 typedef struct canon_ace
{
37 struct canon_ace
*next
, *prev
;
39 mode_t perms
; /* Only use S_I(R|W|X)USR mode bits here. */
41 enum ace_owner owner_type
;
42 enum ace_attribute attr
;
46 #define ALL_ACE_PERMS (S_IRUSR|S_IWUSR|S_IXUSR)
48 /****************************************************************************
49 Functions to manipulate the internal ACE format.
50 ****************************************************************************/
52 /****************************************************************************
53 Count a linked list of canonical ACE entries.
54 ****************************************************************************/
56 static size_t count_canon_ace_list( canon_ace
*list_head
)
61 for (ace
= list_head
; ace
; ace
= ace
->next
)
67 /****************************************************************************
68 Free a linked list of canonical ACE entries.
69 ****************************************************************************/
71 static void free_canon_ace_list( canon_ace
*list_head
)
74 canon_ace
*old_head
= list_head
;
75 DLIST_REMOVE(list_head
, list_head
);
80 /****************************************************************************
81 Function to duplicate a canon_ace entry.
82 ****************************************************************************/
84 static canon_ace
*dup_canon_ace( canon_ace
*src_ace
)
86 canon_ace
*dst_ace
= (canon_ace
*)malloc(sizeof(canon_ace
));
92 dst_ace
->prev
= dst_ace
->next
= NULL
;
96 /****************************************************************************
97 Print out a canon ace.
98 ****************************************************************************/
100 static void print_canon_ace(canon_ace
*pace
, int num
)
104 dbgtext( "canon_ace index %d. Type = %s ", num
, pace
->attr
== ALLOW_ACE
? "allow" : "deny" );
105 dbgtext( "SID = %s ", sid_to_string( str
, &pace
->trustee
));
106 if (pace
->owner_type
== UID_ACE
) {
107 const char *u_name
= uidtoname(pace
->unix_ug
.uid
);
108 dbgtext( "uid %u (%s) ", (unsigned int)pace
->unix_ug
.uid
, u_name
);
109 } else if (pace
->owner_type
== GID_ACE
) {
110 char *g_name
= gidtoname(pace
->unix_ug
.gid
);
111 dbgtext( "gid %u (%s) ", (unsigned int)pace
->unix_ug
.gid
, g_name
);
114 switch (pace
->type
) {
116 dbgtext( "SMB_ACL_USER ");
118 case SMB_ACL_USER_OBJ
:
119 dbgtext( "SMB_ACL_USER_OBJ ");
122 dbgtext( "SMB_ACL_GROUP ");
124 case SMB_ACL_GROUP_OBJ
:
125 dbgtext( "SMB_ACL_GROUP_OBJ ");
128 dbgtext( "SMB_ACL_OTHER ");
132 dbgtext( "%c", pace
->perms
& S_IRUSR
? 'r' : '-');
133 dbgtext( "%c", pace
->perms
& S_IWUSR
? 'w' : '-');
134 dbgtext( "%c\n", pace
->perms
& S_IXUSR
? 'x' : '-');
137 /****************************************************************************
138 Print out a canon ace list.
139 ****************************************************************************/
141 static void print_canon_ace_list(const char *name
, canon_ace
*ace_list
)
145 if( DEBUGLVL( 10 )) {
146 dbgtext( "print_canon_ace_list: %s\n", name
);
147 for (;ace_list
; ace_list
= ace_list
->next
, count
++)
148 print_canon_ace(ace_list
, count
);
152 /****************************************************************************
153 Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
154 ****************************************************************************/
156 static mode_t
convert_permset_to_mode_t(connection_struct
*conn
, SMB_ACL_PERMSET_T permset
)
160 ret
|= (conn
->vfs_ops
.sys_acl_get_perm(conn
, permset
, SMB_ACL_READ
) ? S_IRUSR
: 0);
161 ret
|= (conn
->vfs_ops
.sys_acl_get_perm(conn
, permset
, SMB_ACL_WRITE
) ? S_IWUSR
: 0);
162 ret
|= (conn
->vfs_ops
.sys_acl_get_perm(conn
, permset
, SMB_ACL_EXECUTE
) ? S_IXUSR
: 0);
167 /****************************************************************************
168 Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
169 ****************************************************************************/
171 static mode_t
unix_perms_to_acl_perms(mode_t mode
, int r_mask
, int w_mask
, int x_mask
)
185 /****************************************************************************
186 Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to
187 an SMB_ACL_PERMSET_T.
188 ****************************************************************************/
190 static int map_acl_perms_to_permset(connection_struct
*conn
, mode_t mode
, SMB_ACL_PERMSET_T
*p_permset
)
192 if (conn
->vfs_ops
.sys_acl_clear_perms(conn
, *p_permset
) == -1)
194 if (mode
& S_IRUSR
) {
195 if (conn
->vfs_ops
.sys_acl_add_perm(conn
, *p_permset
, SMB_ACL_READ
) == -1)
198 if (mode
& S_IWUSR
) {
199 if (conn
->vfs_ops
.sys_acl_add_perm(conn
, *p_permset
, SMB_ACL_WRITE
) == -1)
202 if (mode
& S_IXUSR
) {
203 if (conn
->vfs_ops
.sys_acl_add_perm(conn
, *p_permset
, SMB_ACL_EXECUTE
) == -1)
208 /****************************************************************************
209 Function to create owner and group SIDs from a SMB_STRUCT_STAT.
210 ****************************************************************************/
212 static void create_file_sids(SMB_STRUCT_STAT
*psbuf
, DOM_SID
*powner_sid
, DOM_SID
*pgroup_sid
)
214 uid_to_sid( powner_sid
, psbuf
->st_uid
);
215 gid_to_sid( pgroup_sid
, psbuf
->st_gid
);
218 /****************************************************************************
219 Merge aces with a common sid - if both are allow or deny, OR the permissions together and
220 delete the second one. If the first is deny, mask the permissions off and delete the allow
221 if the permissions become zero, delete the deny if the permissions are non zero.
222 ****************************************************************************/
224 static void merge_aces( canon_ace
**pp_list_head
)
226 canon_ace
*list_head
= *pp_list_head
;
227 canon_ace
*curr_ace_outer
;
228 canon_ace
*curr_ace_outer_next
;
231 * First, merge allow entries with identical SIDs, and deny entries
232 * with identical SIDs.
235 for (curr_ace_outer
= list_head
; curr_ace_outer
; curr_ace_outer
= curr_ace_outer_next
) {
237 canon_ace
*curr_ace_next
;
239 curr_ace_outer_next
= curr_ace_outer
->next
; /* Save the link in case we delete. */
241 for (curr_ace
= curr_ace_outer
->next
; curr_ace
; curr_ace
= curr_ace_next
) {
243 curr_ace_next
= curr_ace
->next
; /* Save the link in case of delete. */
245 if (sid_equal(&curr_ace
->trustee
, &curr_ace_outer
->trustee
) &&
246 (curr_ace
->attr
== curr_ace_outer
->attr
)) {
248 if( DEBUGLVL( 10 )) {
249 dbgtext("merge_aces: Merging ACE's\n");
250 print_canon_ace( curr_ace_outer
, 0);
251 print_canon_ace( curr_ace
, 0);
254 /* Merge two allow or two deny ACE's. */
256 curr_ace_outer
->perms
|= curr_ace
->perms
;
257 DLIST_REMOVE(list_head
, curr_ace
);
259 curr_ace_outer_next
= curr_ace_outer
->next
; /* We may have deleted the link. */
265 * Now go through and mask off allow permissions with deny permissions.
266 * We can delete either the allow or deny here as we know that each SID
267 * appears only once in the list.
270 for (curr_ace_outer
= list_head
; curr_ace_outer
; curr_ace_outer
= curr_ace_outer_next
) {
272 canon_ace
*curr_ace_next
;
274 curr_ace_outer_next
= curr_ace_outer
->next
; /* Save the link in case we delete. */
276 for (curr_ace
= curr_ace_outer
->next
; curr_ace
; curr_ace
= curr_ace_next
) {
278 curr_ace_next
= curr_ace
->next
; /* Save the link in case of delete. */
281 * Subtract ACE's with different entries. Due to the ordering constraints
282 * we've put on the ACL, we know the deny must be the first one.
285 if (sid_equal(&curr_ace
->trustee
, &curr_ace_outer
->trustee
) &&
286 (curr_ace_outer
->attr
== DENY_ACE
) && (curr_ace
->attr
== ALLOW_ACE
)) {
288 if( DEBUGLVL( 10 )) {
289 dbgtext("merge_aces: Masking ACE's\n");
290 print_canon_ace( curr_ace_outer
, 0);
291 print_canon_ace( curr_ace
, 0);
294 curr_ace
->perms
&= ~curr_ace_outer
->perms
;
296 if (curr_ace
->perms
== 0) {
299 * The deny overrides the allow. Remove the allow.
302 DLIST_REMOVE(list_head
, curr_ace
);
304 curr_ace_outer_next
= curr_ace_outer
->next
; /* We may have deleted the link. */
309 * Even after removing permissions, there
310 * are still allow permissions - delete the deny.
311 * It is safe to delete the deny here,
312 * as we are guarenteed by the deny first
313 * ordering that all the deny entries for
314 * this SID have already been merged into one
315 * before we can get to an allow ace.
318 DLIST_REMOVE(list_head
, curr_ace_outer
);
319 SAFE_FREE(curr_ace_outer
);
324 } /* end for curr_ace */
325 } /* end for curr_ace_outer */
327 /* We may have modified the list. */
329 *pp_list_head
= list_head
;
332 /****************************************************************************
333 Map canon_ace perms to permission bits NT.
334 The attr element is not used here - we only process deny entries on set,
335 not get. Deny entries are implicit on get with ace->perms = 0.
336 ****************************************************************************/
338 static SEC_ACCESS
map_canon_ace_perms(int *pacl_type
, DOM_SID
*powner_sid
, canon_ace
*ace
)
343 *pacl_type
= SEC_ACE_TYPE_ACCESS_ALLOWED
;
345 if ((ace
->perms
& ALL_ACE_PERMS
) == ALL_ACE_PERMS
) {
346 nt_mask
= UNIX_ACCESS_RWX
;
347 } else if ((ace
->perms
& ALL_ACE_PERMS
) == (mode_t
)0) {
348 nt_mask
= UNIX_ACCESS_NONE
;
350 nt_mask
|= ((ace
->perms
& S_IRUSR
) ? UNIX_ACCESS_R
: 0 );
351 nt_mask
|= ((ace
->perms
& S_IWUSR
) ? UNIX_ACCESS_W
: 0 );
352 nt_mask
|= ((ace
->perms
& S_IXUSR
) ? UNIX_ACCESS_X
: 0 );
355 DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
356 (unsigned int)ace
->perms
, (unsigned int)nt_mask
));
358 init_sec_access(&sa
,nt_mask
);
362 /****************************************************************************
363 Map NT perms to a UNIX mode_t.
364 ****************************************************************************/
366 #define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
367 #define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
368 #define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
370 static mode_t
map_nt_perms( SEC_ACCESS sec_access
, int type
)
376 if(sec_access
.mask
& GENERIC_ALL_ACCESS
)
377 mode
= S_IRUSR
|S_IWUSR
|S_IXUSR
;
379 mode
|= (sec_access
.mask
& (GENERIC_READ_ACCESS
|FILE_SPECIFIC_READ_BITS
)) ? S_IRUSR
: 0;
380 mode
|= (sec_access
.mask
& (GENERIC_WRITE_ACCESS
|FILE_SPECIFIC_WRITE_BITS
)) ? S_IWUSR
: 0;
381 mode
|= (sec_access
.mask
& (GENERIC_EXECUTE_ACCESS
|FILE_SPECIFIC_EXECUTE_BITS
)) ? S_IXUSR
: 0;
385 if(sec_access
.mask
& GENERIC_ALL_ACCESS
)
386 mode
= S_IRGRP
|S_IWGRP
|S_IXGRP
;
388 mode
|= (sec_access
.mask
& (GENERIC_READ_ACCESS
|FILE_SPECIFIC_READ_BITS
)) ? S_IRGRP
: 0;
389 mode
|= (sec_access
.mask
& (GENERIC_WRITE_ACCESS
|FILE_SPECIFIC_WRITE_BITS
)) ? S_IWGRP
: 0;
390 mode
|= (sec_access
.mask
& (GENERIC_EXECUTE_ACCESS
|FILE_SPECIFIC_EXECUTE_BITS
)) ? S_IXGRP
: 0;
394 if(sec_access
.mask
& GENERIC_ALL_ACCESS
)
395 mode
= S_IROTH
|S_IWOTH
|S_IXOTH
;
397 mode
|= (sec_access
.mask
& (GENERIC_READ_ACCESS
|FILE_SPECIFIC_READ_BITS
)) ? S_IROTH
: 0;
398 mode
|= (sec_access
.mask
& (GENERIC_WRITE_ACCESS
|FILE_SPECIFIC_WRITE_BITS
)) ? S_IWOTH
: 0;
399 mode
|= (sec_access
.mask
& (GENERIC_EXECUTE_ACCESS
|FILE_SPECIFIC_EXECUTE_BITS
)) ? S_IXOTH
: 0;
407 /****************************************************************************
408 Unpack a SEC_DESC into a UNIX owner and group.
409 ****************************************************************************/
411 static BOOL
unpack_nt_owners(SMB_STRUCT_STAT
*psbuf
, uid_t
*puser
, gid_t
*pgrp
, uint32 security_info_sent
, SEC_DESC
*psd
)
415 enum SID_NAME_USE sid_type
;
420 if(security_info_sent
== 0) {
421 DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
426 * Validate the owner and group SID's.
429 memset(&owner_sid
, '\0', sizeof(owner_sid
));
430 memset(&grp_sid
, '\0', sizeof(grp_sid
));
432 DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
435 * Don't immediately fail if the owner sid cannot be validated.
436 * This may be a group chown only set.
439 if (security_info_sent
& OWNER_SECURITY_INFORMATION
) {
440 sid_copy(&owner_sid
, psd
->owner_sid
);
441 if (!sid_to_uid( &owner_sid
, puser
, &sid_type
)) {
442 #if ACL_FORCE_UNMAPPABLE
443 /* this allows take ownership to work reasonably */
444 extern struct current_user current_user
;
445 *puser
= current_user
.uid
;
447 DEBUG(3,("unpack_nt_owners: unable to validate owner sid for %s\n",
448 sid_string_static(&owner_sid
)));
455 * Don't immediately fail if the group sid cannot be validated.
456 * This may be an owner chown only set.
459 if (security_info_sent
& GROUP_SECURITY_INFORMATION
) {
460 sid_copy(&grp_sid
, psd
->grp_sid
);
461 if (!sid_to_gid( &grp_sid
, pgrp
, &sid_type
)) {
462 #if ACL_FORCE_UNMAPPABLE
463 /* this allows take group ownership to work reasonably */
464 extern struct current_user current_user
;
465 *pgrp
= current_user
.gid
;
467 DEBUG(3,("unpack_nt_owners: unable to validate group sid.\n"));
473 DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
478 /****************************************************************************
479 Ensure the enforced permissions for this share apply.
480 ****************************************************************************/
482 static void apply_default_perms(files_struct
*fsp
, canon_ace
*pace
, mode_t type
)
484 int snum
= SNUM(fsp
->conn
);
485 mode_t and_bits
= (mode_t
)0;
486 mode_t or_bits
= (mode_t
)0;
488 /* Get the initial bits to apply. */
490 if (fsp
->is_directory
) {
491 and_bits
= lp_dir_security_mask(snum
);
492 or_bits
= lp_force_dir_security_mode(snum
);
494 and_bits
= lp_security_mask(snum
);
495 or_bits
= lp_force_security_mode(snum
);
498 /* Now bounce them into the S_USR space. */
501 /* Ensure owner has read access. */
502 pace
->perms
|= S_IRUSR
;
503 if (fsp
->is_directory
)
504 pace
->perms
|= (S_IWUSR
|S_IXUSR
);
505 and_bits
= unix_perms_to_acl_perms(and_bits
, S_IRUSR
, S_IWUSR
, S_IXUSR
);
506 or_bits
= unix_perms_to_acl_perms(or_bits
, S_IRUSR
, S_IWUSR
, S_IXUSR
);
509 and_bits
= unix_perms_to_acl_perms(and_bits
, S_IRGRP
, S_IWGRP
, S_IXGRP
);
510 or_bits
= unix_perms_to_acl_perms(or_bits
, S_IRGRP
, S_IWGRP
, S_IXGRP
);
513 and_bits
= unix_perms_to_acl_perms(and_bits
, S_IROTH
, S_IWOTH
, S_IXOTH
);
514 or_bits
= unix_perms_to_acl_perms(or_bits
, S_IROTH
, S_IWOTH
, S_IXOTH
);
518 pace
->perms
= ((pace
->perms
& and_bits
)|or_bits
);
521 /****************************************************************************
522 Check if a given uid/SID is in a group gid/SID. This is probably very
523 expensive and will need optimisation. A *lot* of optimisation :-). JRA.
524 ****************************************************************************/
526 static BOOL
uid_entry_in_group( canon_ace
*uid_ace
, canon_ace
*group_ace
)
528 extern DOM_SID global_sid_World
;
532 /* "Everyone" always matches every uid. */
534 if (sid_equal(&group_ace
->trustee
, &global_sid_World
))
537 fstrcpy(u_name
, uidtoname(uid_ace
->unix_ug
.uid
));
538 fstrcpy(g_name
, gidtoname(group_ace
->unix_ug
.gid
));
541 * Due to the winbind interfaces we need to do this via names,
545 return user_in_group_list(u_name
, g_name
);
548 /****************************************************************************
549 A well formed POSIX file or default ACL has at least 3 entries, a
550 SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
551 In addition, the owner must always have at least read access.
552 When using this call on get_acl, the pst struct is valid and contains
553 the mode of the file. When using this call on set_acl, the pst struct has
554 been modified to have a mode containing the default for this file or directory
556 ****************************************************************************/
558 static BOOL
ensure_canon_entry_valid(canon_ace
**pp_ace
,
560 DOM_SID
*pfile_owner_sid
,
561 DOM_SID
*pfile_grp_sid
,
562 SMB_STRUCT_STAT
*pst
,
565 extern DOM_SID global_sid_World
;
567 BOOL got_user
= False
;
568 BOOL got_grp
= False
;
569 BOOL got_other
= False
;
570 canon_ace
*pace_other
= NULL
;
571 canon_ace
*pace_group
= NULL
;
573 for (pace
= *pp_ace
; pace
; pace
= pace
->next
) {
574 if (pace
->type
== SMB_ACL_USER_OBJ
) {
577 apply_default_perms(fsp
, pace
, S_IRUSR
);
580 } else if (pace
->type
== SMB_ACL_GROUP_OBJ
) {
583 * Ensure create mask/force create mode is respected on set.
587 apply_default_perms(fsp
, pace
, S_IRGRP
);
591 } else if (pace
->type
== SMB_ACL_OTHER
) {
594 * Ensure create mask/force create mode is respected on set.
598 apply_default_perms(fsp
, pace
, S_IROTH
);
605 if ((pace
= (canon_ace
*)malloc(sizeof(canon_ace
))) == NULL
) {
606 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
611 pace
->type
= SMB_ACL_USER_OBJ
;
612 pace
->owner_type
= UID_ACE
;
613 pace
->unix_ug
.uid
= pst
->st_uid
;
614 pace
->trustee
= *pfile_owner_sid
;
615 pace
->attr
= ALLOW_ACE
;
618 /* If we only got an "everyone" perm, just use that. */
619 if (!got_grp
&& got_other
)
620 pace
->perms
= pace_other
->perms
;
621 else if (got_grp
&& uid_entry_in_group(pace
, pace_group
))
622 pace
->perms
= pace_group
->perms
;
624 pace
->perms
= unix_perms_to_acl_perms(pst
->st_mode
, S_IRUSR
, S_IWUSR
, S_IXUSR
);
625 apply_default_perms(fsp
, pace
, S_IRUSR
);
627 pace
->perms
= unix_perms_to_acl_perms(pst
->st_mode
, S_IRUSR
, S_IWUSR
, S_IXUSR
);
630 DLIST_ADD(*pp_ace
, pace
);
634 if ((pace
= (canon_ace
*)malloc(sizeof(canon_ace
))) == NULL
) {
635 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
640 pace
->type
= SMB_ACL_GROUP_OBJ
;
641 pace
->owner_type
= GID_ACE
;
642 pace
->unix_ug
.uid
= pst
->st_gid
;
643 pace
->trustee
= *pfile_grp_sid
;
644 pace
->attr
= ALLOW_ACE
;
646 /* If we only got an "everyone" perm, just use that. */
648 pace
->perms
= pace_other
->perms
;
650 pace
->perms
= unix_perms_to_acl_perms(pst
->st_mode
, S_IRGRP
, S_IWGRP
, S_IXGRP
);
651 apply_default_perms(fsp
, pace
, S_IRGRP
);
653 pace
->perms
= unix_perms_to_acl_perms(pst
->st_mode
, S_IRGRP
, S_IWGRP
, S_IXGRP
);
656 DLIST_ADD(*pp_ace
, pace
);
660 if ((pace
= (canon_ace
*)malloc(sizeof(canon_ace
))) == NULL
) {
661 DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
666 pace
->type
= SMB_ACL_OTHER
;
667 pace
->owner_type
= WORLD_ACE
;
668 pace
->unix_ug
.world
= -1;
669 pace
->trustee
= global_sid_World
;
670 pace
->attr
= ALLOW_ACE
;
671 pace
->perms
= unix_perms_to_acl_perms(pst
->st_mode
, S_IROTH
, S_IWOTH
, S_IXOTH
);
672 apply_default_perms(fsp
, pace
, S_IROTH
);
674 DLIST_ADD(*pp_ace
, pace
);
680 /****************************************************************************
681 Unpack a SEC_DESC into two canonical ace lists.
682 ****************************************************************************/
684 static BOOL
create_canon_ace_lists(files_struct
*fsp
,
685 DOM_SID
*pfile_owner_sid
,
686 DOM_SID
*pfile_grp_sid
,
687 canon_ace
**ppfile_ace
, canon_ace
**ppdir_ace
,
690 extern DOM_SID global_sid_World
;
691 extern struct generic_mapping file_generic_mapping
;
692 BOOL all_aces_are_inherit_only
= (fsp
->is_directory
? True
: False
);
693 canon_ace
*file_ace
= NULL
;
694 canon_ace
*dir_ace
= NULL
;
695 canon_ace
*tmp_ace
= NULL
;
696 canon_ace
*current_ace
= NULL
;
697 BOOL got_dir_allow
= False
;
698 BOOL got_file_allow
= False
;
705 * Convert the incoming ACL into a more regular form.
708 for(i
= 0; i
< dacl
->num_aces
; i
++) {
709 SEC_ACE
*psa
= &dacl
->ace
[i
];
711 if((psa
->type
!= SEC_ACE_TYPE_ACCESS_ALLOWED
) && (psa
->type
!= SEC_ACE_TYPE_ACCESS_DENIED
)) {
712 DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
717 * The security mask may be UNIX_ACCESS_NONE which should map into
718 * no permissions (we overload the WRITE_OWNER bit for this) or it
719 * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
720 * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
724 * Convert GENERIC bits to specific bits.
727 se_map_generic(&psa
->info
.mask
, &file_generic_mapping
);
729 psa
->info
.mask
&= (UNIX_ACCESS_NONE
|FILE_ALL_ACCESS
);
731 if(psa
->info
.mask
!= UNIX_ACCESS_NONE
)
732 psa
->info
.mask
&= ~UNIX_ACCESS_NONE
;
736 * Deal with the fact that NT 4.x re-writes the canonical format
737 * that we return for default ACLs. If a directory ACE is identical
738 * to a inherited directory ACE then NT changes the bits so that the
739 * first ACE is set to OI|IO and the second ACE for this SID is set
740 * to CI. We need to repair this. JRA.
743 for(i
= 0; i
< dacl
->num_aces
; i
++) {
744 SEC_ACE
*psa1
= &dacl
->ace
[i
];
746 for (j
= i
+ 1; j
< dacl
->num_aces
; j
++) {
747 SEC_ACE
*psa2
= &dacl
->ace
[j
];
749 if (psa1
->info
.mask
!= psa2
->info
.mask
)
752 if (!sid_equal(&psa1
->trustee
, &psa2
->trustee
))
756 * Ok - permission bits and SIDs are equal.
757 * Check if flags were re-written.
760 if (psa1
->flags
& SEC_ACE_FLAG_INHERIT_ONLY
) {
762 psa1
->flags
|= (psa2
->flags
& (SEC_ACE_FLAG_CONTAINER_INHERIT
|SEC_ACE_FLAG_OBJECT_INHERIT
));
763 psa2
->flags
&= ~(SEC_ACE_FLAG_CONTAINER_INHERIT
|SEC_ACE_FLAG_OBJECT_INHERIT
);
765 } else if (psa2
->flags
& SEC_ACE_FLAG_INHERIT_ONLY
) {
767 psa2
->flags
|= (psa1
->flags
& (SEC_ACE_FLAG_CONTAINER_INHERIT
|SEC_ACE_FLAG_OBJECT_INHERIT
));
768 psa1
->flags
&= ~(SEC_ACE_FLAG_CONTAINER_INHERIT
|SEC_ACE_FLAG_OBJECT_INHERIT
);
774 for(i
= 0; i
< dacl
->num_aces
; i
++) {
775 enum SID_NAME_USE sid_type
;
776 SEC_ACE
*psa
= &dacl
->ace
[i
];
779 * Ignore non-mappable SIDs (NT Authority, BUILTIN etc).
782 if (non_mappable_sid(&psa
->trustee
)) {
784 DEBUG(10,("create_canon_ace_lists: ignoring non-mappable SID %s\n",
785 sid_to_string(str
, &psa
->trustee
) ));
790 * Create a cannon_ace entry representing this NT DACL ACE.
793 if ((current_ace
= (canon_ace
*)malloc(sizeof(canon_ace
))) == NULL
) {
794 free_canon_ace_list(file_ace
);
795 free_canon_ace_list(dir_ace
);
796 DEBUG(0,("create_canon_ace_lists: malloc fail.\n"));
800 ZERO_STRUCTP(current_ace
);
802 sid_copy(¤t_ace
->trustee
, &psa
->trustee
);
805 * Try and work out if the SID is a user or group
806 * as we need to flag these differently for POSIX.
809 if( sid_equal(¤t_ace
->trustee
, &global_sid_World
)) {
810 current_ace
->owner_type
= WORLD_ACE
;
811 current_ace
->unix_ug
.world
= -1;
812 } else if (sid_to_uid( ¤t_ace
->trustee
, ¤t_ace
->unix_ug
.uid
, &sid_type
)) {
813 current_ace
->owner_type
= UID_ACE
;
814 } else if (sid_to_gid( ¤t_ace
->trustee
, ¤t_ace
->unix_ug
.gid
, &sid_type
)) {
815 current_ace
->owner_type
= GID_ACE
;
819 free_canon_ace_list(file_ace
);
820 free_canon_ace_list(dir_ace
);
821 DEBUG(0,("create_canon_ace_lists: unable to map SID %s to uid or gid.\n",
822 sid_to_string(str
, ¤t_ace
->trustee
) ));
823 SAFE_FREE(current_ace
);
828 * Map the given NT permissions into a UNIX mode_t containing only
829 * S_I(R|W|X)USR bits.
832 current_ace
->perms
|= map_nt_perms( psa
->info
, S_IRUSR
);
833 current_ace
->attr
= (psa
->type
== SEC_ACE_TYPE_ACCESS_ALLOWED
) ? ALLOW_ACE
: DENY_ACE
;
836 * Now note what kind of a POSIX ACL this should map to.
839 if(sid_equal(¤t_ace
->trustee
, pfile_owner_sid
)) {
841 current_ace
->type
= SMB_ACL_USER_OBJ
;
843 } else if( sid_equal(¤t_ace
->trustee
, pfile_grp_sid
)) {
845 current_ace
->type
= SMB_ACL_GROUP_OBJ
;
847 } else if( sid_equal(¤t_ace
->trustee
, &global_sid_World
)) {
849 current_ace
->type
= SMB_ACL_OTHER
;
853 * Could be a SMB_ACL_USER or SMB_ACL_GROUP. Check by
854 * looking at owner_type.
857 current_ace
->type
= (current_ace
->owner_type
== UID_ACE
) ? SMB_ACL_USER
: SMB_ACL_GROUP
;
861 * Now add the created ace to either the file list, the directory
862 * list, or both. We *MUST* preserve the order here (hence we use
863 * DLIST_ADD_END) as NT ACLs are order dependent.
866 if (fsp
->is_directory
) {
869 * We can only add to the default POSIX ACE list if the ACE is
870 * designed to be inherited by both files and directories.
873 if ((psa
->flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|SEC_ACE_FLAG_CONTAINER_INHERIT
)) ==
874 (SEC_ACE_FLAG_OBJECT_INHERIT
|SEC_ACE_FLAG_CONTAINER_INHERIT
)) {
876 DLIST_ADD_END(dir_ace
, current_ace
, tmp_ace
);
879 * Note if this was an allow ace. We can't process
880 * any further deny ace's after this.
883 if (current_ace
->attr
== ALLOW_ACE
)
884 got_dir_allow
= True
;
886 if ((current_ace
->attr
== DENY_ACE
) && got_dir_allow
) {
887 DEBUG(0,("create_canon_ace_lists: malformed ACL in inheritable ACL ! \
888 Deny entry after Allow entry. Failing to set on file %s.\n", fsp
->fsp_name
));
889 free_canon_ace_list(file_ace
);
890 free_canon_ace_list(dir_ace
);
891 SAFE_FREE(current_ace
);
895 if( DEBUGLVL( 10 )) {
896 dbgtext("create_canon_ace_lists: adding dir ACL:\n");
897 print_canon_ace( current_ace
, 0);
901 * If this is not an inherit only ACE we need to add a duplicate
905 if (!(psa
->flags
& SEC_ACE_FLAG_INHERIT_ONLY
)) {
906 canon_ace
*dup_ace
= dup_canon_ace(current_ace
);
909 DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
910 free_canon_ace_list(file_ace
);
911 free_canon_ace_list(dir_ace
);
915 current_ace
= dup_ace
;
923 * Only add to the file ACL if not inherit only.
926 if (!(psa
->flags
& SEC_ACE_FLAG_INHERIT_ONLY
)) {
927 DLIST_ADD_END(file_ace
, current_ace
, tmp_ace
);
930 * Note if this was an allow ace. We can't process
931 * any further deny ace's after this.
934 if (current_ace
->attr
== ALLOW_ACE
)
935 got_file_allow
= True
;
937 if ((current_ace
->attr
== DENY_ACE
) && got_file_allow
) {
938 DEBUG(0,("create_canon_ace_lists: malformed ACL in file ACL ! \
939 Deny entry after Allow entry. Failing to set on file %s.\n", fsp
->fsp_name
));
940 free_canon_ace_list(file_ace
);
941 free_canon_ace_list(dir_ace
);
942 SAFE_FREE(current_ace
);
946 if( DEBUGLVL( 10 )) {
947 dbgtext("create_canon_ace_lists: adding file ACL:\n");
948 print_canon_ace( current_ace
, 0);
950 all_aces_are_inherit_only
= False
;
955 * Free if ACE was not added.
958 SAFE_FREE(current_ace
);
961 if (fsp
->is_directory
&& all_aces_are_inherit_only
) {
963 * Windows 2000 is doing one of these weird 'inherit acl'
964 * traverses to conserve NTFS ACL resources. Just pretend
965 * there was no DACL sent. JRA.
968 DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n"));
969 free_canon_ace_list(file_ace
);
970 free_canon_ace_list(dir_ace
);
975 *ppfile_ace
= file_ace
;
976 *ppdir_ace
= dir_ace
;
981 /****************************************************************************
982 ASCII art time again... JRA :-).
984 We have 3 cases to process when moving from an NT ACL to a POSIX ACL. Firstly,
985 we insist the ACL is in canonical form (ie. all DENY entries preceede ALLOW
986 entries). Secondly, the merge code has ensured that all duplicate SID entries for
987 allow or deny have been merged, so the same SID can only appear once in the deny
988 list or once in the allow list.
990 We then process as follows :
992 ---------------------------------------------------------------------------
993 First pass - look for a Everyone DENY entry.
995 If it is deny all (rwx) trunate the list at this point.
996 Else, walk the list from this point and use the deny permissions of this
997 entry as a mask on all following allow entries. Finally, delete
998 the Everyone DENY entry (we have applied it to everything possible).
1000 In addition, in this pass we remove any DENY entries that have
1001 no permissions (ie. they are a DENY nothing).
1002 ---------------------------------------------------------------------------
1003 Second pass - only deal with deny user entries.
1005 DENY user1 (perms XXX)
1008 for all following allow group entries where user1 is in group
1009 new_perms |= group_perms;
1011 user1 entry perms = new_perms & ~ XXX;
1013 Convert the deny entry to an allow entry with the new perms and
1014 push to the end of the list. Note if the user was in no groups
1015 this maps to a specific allow nothing entry for this user.
1017 The common case from the NT ACL choser (userX deny all) is
1018 optimised so we don't do the group lookup - we just map to
1019 an allow nothing entry.
1021 What we're doing here is inferring the allow permissions the
1022 person setting the ACE on user1 wanted by looking at the allow
1023 permissions on the groups the user is currently in. This will
1024 be a snapshot, depending on group membership but is the best
1025 we can do and has the advantage of failing closed rather than
1027 ---------------------------------------------------------------------------
1028 Third pass - only deal with deny group entries.
1030 DENY group1 (perms XXX)
1032 for all following allow user entries where user is in group1
1033 user entry perms = user entry perms & ~ XXX;
1035 If there is a group Everyone allow entry with permissions YYY,
1036 convert the group1 entry to an allow entry and modify its
1039 new_perms = YYY & ~ XXX
1041 and push to the end of the list.
1043 If there is no group Everyone allow entry then convert the
1044 group1 entry to a allow nothing entry and push to the end of the list.
1046 Note that the common case from the NT ACL choser (groupX deny all)
1047 cannot be optimised here as we need to modify user entries who are
1048 in the group to change them to a deny all also.
1050 What we're doing here is modifying the allow permissions of
1051 user entries (which are more specific in POSIX ACLs) to mask
1052 out the explicit deny set on the group they are in. This will
1053 be a snapshot depending on current group membership but is the
1054 best we can do and has the advantage of failing closed rather
1056 ---------------------------------------------------------------------------
1058 Note we *MUST* do the deny user pass first as this will convert deny user
1059 entries into allow user entries which can then be processed by the deny
1062 The above algorithm took a *lot* of thinking about - hence this
1063 explaination :-). JRA.
1064 ****************************************************************************/
1066 /****************************************************************************
1067 Process a canon_ace list entries. This is very complex code. We need
1068 to go through and remove the "deny" permissions from any allow entry that matches
1069 the id of this entry. We have already refused any NT ACL that wasn't in correct
1070 order (DENY followed by ALLOW). If any allow entry ends up with zero permissions,
1071 we just remove it (to fail safe). We have already removed any duplicate ace
1072 entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all
1074 ****************************************************************************/
1076 static void process_deny_list( canon_ace
**pp_ace_list
)
1078 extern DOM_SID global_sid_World
;
1079 canon_ace
*ace_list
= *pp_ace_list
;
1080 canon_ace
*curr_ace
= NULL
;
1081 canon_ace
*curr_ace_next
= NULL
;
1083 /* Pass 1 above - look for an Everyone, deny entry. */
1085 for (curr_ace
= ace_list
; curr_ace
; curr_ace
= curr_ace_next
) {
1086 canon_ace
*allow_ace_p
;
1088 curr_ace_next
= curr_ace
->next
; /* So we can't lose the link. */
1090 if (curr_ace
->attr
!= DENY_ACE
)
1093 if (curr_ace
->perms
== (mode_t
)0) {
1095 /* Deny nothing entry - delete. */
1097 DLIST_REMOVE(ace_list
, curr_ace
);
1101 if (!sid_equal(&curr_ace
->trustee
, &global_sid_World
))
1104 /* JRATEST - assert. */
1105 SMB_ASSERT(curr_ace
->owner_type
== WORLD_ACE
);
1107 if (curr_ace
->perms
== ALL_ACE_PERMS
) {
1110 * Optimisation. This is a DENY_ALL to Everyone. Truncate the
1111 * list at this point including this entry.
1114 canon_ace
*prev_entry
= curr_ace
->prev
;
1116 free_canon_ace_list( curr_ace
);
1118 prev_entry
->next
= NULL
;
1120 /* We deleted the entire list. */
1126 for (allow_ace_p
= curr_ace
->next
; allow_ace_p
; allow_ace_p
= allow_ace_p
->next
) {
1129 * Only mask off allow entries.
1132 if (allow_ace_p
->attr
!= ALLOW_ACE
)
1135 allow_ace_p
->perms
&= ~curr_ace
->perms
;
1139 * Now it's been applied, remove it.
1142 DLIST_REMOVE(ace_list
, curr_ace
);
1145 /* Pass 2 above - deal with deny user entries. */
1147 for (curr_ace
= ace_list
; curr_ace
; curr_ace
= curr_ace_next
) {
1148 mode_t new_perms
= (mode_t
)0;
1149 canon_ace
*allow_ace_p
;
1152 curr_ace_next
= curr_ace
->next
; /* So we can't lose the link. */
1154 if (curr_ace
->attr
!= DENY_ACE
)
1157 if (curr_ace
->owner_type
!= UID_ACE
)
1160 if (curr_ace
->perms
== ALL_ACE_PERMS
) {
1163 * Optimisation - this is a deny everything to this user.
1164 * Convert to an allow nothing and push to the end of the list.
1167 curr_ace
->attr
= ALLOW_ACE
;
1168 curr_ace
->perms
= (mode_t
)0;
1169 DLIST_DEMOTE(ace_list
, curr_ace
, tmp_ace
);
1173 for (allow_ace_p
= curr_ace
->next
; allow_ace_p
; allow_ace_p
= allow_ace_p
->next
) {
1175 if (allow_ace_p
->attr
!= ALLOW_ACE
)
1178 /* We process GID_ACE and WORLD_ACE entries only. */
1180 if (allow_ace_p
->owner_type
== UID_ACE
)
1183 if (uid_entry_in_group( curr_ace
, allow_ace_p
))
1184 new_perms
|= allow_ace_p
->perms
;
1188 * Convert to a allow entry, modify the perms and push to the end
1192 curr_ace
->attr
= ALLOW_ACE
;
1193 curr_ace
->perms
= (new_perms
& ~curr_ace
->perms
);
1194 DLIST_DEMOTE(ace_list
, curr_ace
, tmp_ace
);
1197 /* Pass 3 above - deal with deny group entries. */
1199 for (curr_ace
= ace_list
; curr_ace
; curr_ace
= curr_ace_next
) {
1201 canon_ace
*allow_ace_p
;
1202 canon_ace
*allow_everyone_p
= NULL
;
1204 curr_ace_next
= curr_ace
->next
; /* So we can't lose the link. */
1206 if (curr_ace
->attr
!= DENY_ACE
)
1209 if (curr_ace
->owner_type
!= GID_ACE
)
1212 for (allow_ace_p
= curr_ace
->next
; allow_ace_p
; allow_ace_p
= allow_ace_p
->next
) {
1214 if (allow_ace_p
->attr
!= ALLOW_ACE
)
1217 /* Store a pointer to the Everyone allow, if it exists. */
1218 if (allow_ace_p
->owner_type
== WORLD_ACE
)
1219 allow_everyone_p
= allow_ace_p
;
1221 /* We process UID_ACE entries only. */
1223 if (allow_ace_p
->owner_type
!= UID_ACE
)
1226 /* Mask off the deny group perms. */
1228 if (uid_entry_in_group( allow_ace_p
, curr_ace
))
1229 allow_ace_p
->perms
&= ~curr_ace
->perms
;
1233 * Convert the deny to an allow with the correct perms and
1234 * push to the end of the list.
1237 curr_ace
->attr
= ALLOW_ACE
;
1238 if (allow_everyone_p
)
1239 curr_ace
->perms
= allow_everyone_p
->perms
& ~curr_ace
->perms
;
1241 curr_ace
->perms
= (mode_t
)0;
1242 DLIST_DEMOTE(ace_list
, curr_ace
, tmp_ace
);
1246 *pp_ace_list
= ace_list
;
1249 /****************************************************************************
1250 Create a default mode that will be used if a security descriptor entry has
1251 no user/group/world entries.
1252 ****************************************************************************/
1254 static mode_t
create_default_mode(files_struct
*fsp
, BOOL interitable_mode
)
1256 int snum
= SNUM(fsp
->conn
);
1257 mode_t and_bits
= (mode_t
)0;
1258 mode_t or_bits
= (mode_t
)0;
1259 mode_t mode
= interitable_mode
? unix_mode( fsp
->conn
, FILE_ATTRIBUTE_ARCHIVE
, fsp
->fsp_name
) : S_IRUSR
;
1261 if (fsp
->is_directory
)
1262 mode
|= (S_IWUSR
|S_IXUSR
);
1265 * Now AND with the create mode/directory mode bits then OR with the
1266 * force create mode/force directory mode bits.
1269 if (fsp
->is_directory
) {
1270 and_bits
= lp_dir_security_mask(snum
);
1271 or_bits
= lp_force_dir_security_mode(snum
);
1273 and_bits
= lp_security_mask(snum
);
1274 or_bits
= lp_force_security_mode(snum
);
1277 return ((mode
& and_bits
)|or_bits
);
1280 /****************************************************************************
1281 Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
1283 ****************************************************************************/
1285 static BOOL
unpack_canon_ace(files_struct
*fsp
,
1286 SMB_STRUCT_STAT
*pst
,
1287 DOM_SID
*pfile_owner_sid
,
1288 DOM_SID
*pfile_grp_sid
,
1289 canon_ace
**ppfile_ace
, canon_ace
**ppdir_ace
,
1290 uint32 security_info_sent
, SEC_DESC
*psd
)
1292 canon_ace
*file_ace
= NULL
;
1293 canon_ace
*dir_ace
= NULL
;
1298 if(security_info_sent
== 0) {
1299 DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
1304 * If no DACL then this is a chown only security descriptor.
1307 if(!(security_info_sent
& DACL_SECURITY_INFORMATION
) || !psd
->dacl
)
1311 * Now go through the DACL and create the canon_ace lists.
1314 if (!create_canon_ace_lists( fsp
, pfile_owner_sid
, pfile_grp_sid
,
1315 &file_ace
, &dir_ace
, psd
->dacl
))
1318 if ((file_ace
== NULL
) && (dir_ace
== NULL
)) {
1319 /* W2K traverse DACL set - ignore. */
1324 * Go through the canon_ace list and merge entries
1325 * belonging to identical users of identical allow or deny type.
1326 * We can do this as all deny entries come first, followed by
1327 * all allow entries (we have mandated this before accepting this acl).
1330 print_canon_ace_list( "file ace - before merge", file_ace
);
1331 merge_aces( &file_ace
);
1333 print_canon_ace_list( "dir ace - before merge", dir_ace
);
1334 merge_aces( &dir_ace
);
1337 * NT ACLs are order dependent. Go through the acl lists and
1338 * process DENY entries by masking the allow entries.
1341 print_canon_ace_list( "file ace - before deny", file_ace
);
1342 process_deny_list( &file_ace
);
1344 print_canon_ace_list( "dir ace - before deny", dir_ace
);
1345 process_deny_list( &dir_ace
);
1348 * A well formed POSIX file or default ACL has at least 3 entries, a
1349 * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
1350 * and optionally a mask entry. Ensure this is the case.
1353 print_canon_ace_list( "file ace - before valid", file_ace
);
1356 * A default 3 element mode entry for a file should be r-- --- ---.
1357 * A default 3 element mode entry for a directory should be rwx --- ---.
1360 pst
->st_mode
= create_default_mode(fsp
, False
);
1362 if (!ensure_canon_entry_valid(&file_ace
, fsp
, pfile_owner_sid
, pfile_grp_sid
, pst
, True
)) {
1363 free_canon_ace_list(file_ace
);
1364 free_canon_ace_list(dir_ace
);
1368 print_canon_ace_list( "dir ace - before valid", dir_ace
);
1371 * A default inheritable 3 element mode entry for a directory should be the
1372 * mode Samba will use to create a file within. Ensure user rwx bits are set if
1376 pst
->st_mode
= create_default_mode(fsp
, True
);
1378 if (!ensure_canon_entry_valid(&dir_ace
, fsp
, pfile_owner_sid
, pfile_grp_sid
, pst
, True
)) {
1379 free_canon_ace_list(file_ace
);
1380 free_canon_ace_list(dir_ace
);
1384 print_canon_ace_list( "file ace - return", file_ace
);
1385 print_canon_ace_list( "dir ace - return", dir_ace
);
1387 *ppfile_ace
= file_ace
;
1388 *ppdir_ace
= dir_ace
;
1393 /******************************************************************************
1394 When returning permissions, try and fit NT display
1395 semantics if possible. Note the the canon_entries here must have been malloced.
1396 The list format should be - first entry = owner, followed by group and other user
1397 entries, last entry = other.
1399 Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries
1400 are not ordered, and match on the most specific entry rather than walking a list,
1401 then a simple POSIX permission of rw-r--r-- should really map to 6 entries,
1403 Entry 0: owner : deny all except read and write.
1404 Entry 1: group : deny all except read.
1405 Entry 2: Everyone : deny all except read.
1406 Entry 3: owner : allow read and write.
1407 Entry 4: group : allow read.
1408 Entry 5: Everyone : allow read.
1410 But NT cannot display this in their ACL editor !
1411 ********************************************************************************/
1413 static void arrange_posix_perms( char *filename
, canon_ace
**pp_list_head
)
1415 canon_ace
*list_head
= *pp_list_head
;
1416 canon_ace
*owner_ace
= NULL
;
1417 canon_ace
*other_ace
= NULL
;
1418 canon_ace
*ace
= NULL
;
1420 for (ace
= list_head
; ace
; ace
= ace
->next
) {
1421 if (ace
->type
== SMB_ACL_USER_OBJ
)
1423 else if (ace
->type
== SMB_ACL_OTHER
) {
1424 /* Last ace - this is "other" */
1429 if (!owner_ace
|| !other_ace
) {
1430 DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n",
1436 * The POSIX algorithm applies to owner first, and other last,
1437 * so ensure they are arranged in this order.
1441 DLIST_PROMOTE(list_head
, owner_ace
);
1445 DLIST_DEMOTE(list_head
, other_ace
, ace
);
1448 /* We have probably changed the head of the list. */
1450 *pp_list_head
= list_head
;
1453 /****************************************************************************
1454 Create a linked list of canonical ACE entries.
1455 ****************************************************************************/
1457 static canon_ace
*canonicalise_acl( files_struct
*fsp
, SMB_ACL_T posix_acl
, SMB_STRUCT_STAT
*psbuf
,
1458 DOM_SID
*powner
, DOM_SID
*pgroup
)
1460 extern DOM_SID global_sid_World
;
1461 connection_struct
*conn
= fsp
->conn
;
1462 mode_t acl_mask
= (S_IRUSR
|S_IWUSR
|S_IXUSR
);
1463 canon_ace
*list_head
= NULL
;
1464 canon_ace
*ace
= NULL
;
1465 canon_ace
*next_ace
= NULL
;
1466 int entry_id
= SMB_ACL_FIRST_ENTRY
;
1467 SMB_ACL_ENTRY_T entry
;
1470 while ( posix_acl
&& (conn
->vfs_ops
.sys_acl_get_entry(conn
, posix_acl
, entry_id
, &entry
) == 1)) {
1471 SMB_ACL_TAG_T tagtype
;
1472 SMB_ACL_PERMSET_T permset
;
1475 enum ace_owner owner_type
;
1478 if (entry_id
== SMB_ACL_FIRST_ENTRY
)
1479 entry_id
= SMB_ACL_NEXT_ENTRY
;
1481 /* Is this a MASK entry ? */
1482 if (conn
->vfs_ops
.sys_acl_get_tag_type(conn
, entry
, &tagtype
) == -1)
1485 if (conn
->vfs_ops
.sys_acl_get_permset(conn
, entry
, &permset
) == -1)
1488 /* Decide which SID to use based on the ACL type. */
1490 case SMB_ACL_USER_OBJ
:
1491 /* Get the SID from the owner. */
1492 uid_to_sid( &sid
, psbuf
->st_uid
);
1493 unix_ug
.uid
= psbuf
->st_uid
;
1494 owner_type
= UID_ACE
;
1498 uid_t
*puid
= (uid_t
*)conn
->vfs_ops
.sys_acl_get_qualifier(conn
, entry
);
1500 DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
1503 uid_to_sid( &sid
, *puid
);
1504 unix_ug
.uid
= *puid
;
1505 owner_type
= UID_ACE
;
1506 conn
->vfs_ops
.sys_acl_free_qualifier(conn
, (void *)puid
,tagtype
);
1509 case SMB_ACL_GROUP_OBJ
:
1510 /* Get the SID from the owning group. */
1511 gid_to_sid( &sid
, psbuf
->st_gid
);
1512 unix_ug
.gid
= psbuf
->st_gid
;
1513 owner_type
= GID_ACE
;
1517 gid_t
*pgid
= (gid_t
*)conn
->vfs_ops
.sys_acl_get_qualifier(conn
, entry
);
1519 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
1522 gid_to_sid( &sid
, *pgid
);
1523 unix_ug
.gid
= *pgid
;
1524 owner_type
= GID_ACE
;
1525 conn
->vfs_ops
.sys_acl_free_qualifier(conn
, (void *)pgid
,tagtype
);
1529 acl_mask
= convert_permset_to_mode_t(conn
, permset
);
1530 continue; /* Don't count the mask as an entry. */
1532 /* Use the Everyone SID */
1533 sid
= global_sid_World
;
1535 owner_type
= WORLD_ACE
;
1538 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype
));
1543 * Add this entry to the list.
1546 if ((ace
= (canon_ace
*)malloc(sizeof(canon_ace
))) == NULL
)
1550 ace
->type
= tagtype
;
1551 ace
->perms
= convert_permset_to_mode_t(conn
, permset
);
1552 ace
->attr
= ALLOW_ACE
;
1554 ace
->unix_ug
= unix_ug
;
1555 ace
->owner_type
= owner_type
;
1557 DLIST_ADD(list_head
, ace
);
1561 * This next call will ensure we have at least a user/group/world set.
1564 if (!ensure_canon_entry_valid(&list_head
, fsp
, powner
, pgroup
, psbuf
, False
))
1567 arrange_posix_perms(fsp
->fsp_name
,&list_head
);
1570 * Now go through the list, masking the permissions with the
1571 * acl_mask. Ensure all DENY Entries are at the start of the list.
1574 DEBUG(10,("canonicalise_acl: ace entries before arrange :\n"));
1576 for ( ace_count
= 0, ace
= list_head
; ace
; ace
= next_ace
, ace_count
++) {
1577 next_ace
= ace
->next
;
1579 /* Masks are only applied to entries other than USER_OBJ and OTHER. */
1580 if (ace
->type
!= SMB_ACL_OTHER
&& ace
->type
!= SMB_ACL_USER_OBJ
)
1581 ace
->perms
&= acl_mask
;
1583 if (ace
->perms
== 0) {
1584 DLIST_PROMOTE(list_head
, ace
);
1587 if( DEBUGLVL( 10 ) ) {
1588 print_canon_ace(ace
, ace_count
);
1592 print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head
);
1598 free_canon_ace_list(list_head
);
1602 /****************************************************************************
1603 Attempt to apply an ACL to a file or directory.
1604 ****************************************************************************/
1606 static BOOL
set_canon_ace_list(files_struct
*fsp
, canon_ace
*the_ace
, BOOL default_ace
, BOOL
*pacl_set_support
)
1608 connection_struct
*conn
= fsp
->conn
;
1610 SMB_ACL_T the_acl
= conn
->vfs_ops
.sys_acl_init(conn
, (int)count_canon_ace_list(the_ace
) + 1);
1613 SMB_ACL_ENTRY_T mask_entry
;
1614 SMB_ACL_PERMSET_T mask_permset
;
1615 SMB_ACL_TYPE_T the_acl_type
= (default_ace
? SMB_ACL_TYPE_DEFAULT
: SMB_ACL_TYPE_ACCESS
);
1617 if (the_acl
== NULL
) {
1619 if (errno
!= ENOSYS
) {
1621 * Only print this error message if we have some kind of ACL
1622 * support that's not working. Otherwise we would always get this.
1624 DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
1625 default_ace
? "default" : "file", strerror(errno
) ));
1627 *pacl_set_support
= False
;
1631 for (i
= 0, p_ace
= the_ace
; p_ace
; p_ace
= p_ace
->next
, i
++ ) {
1632 SMB_ACL_ENTRY_T the_entry
;
1633 SMB_ACL_PERMSET_T the_permset
;
1636 * Get the entry for this ACE.
1639 if (conn
->vfs_ops
.sys_acl_create_entry(conn
, &the_acl
, &the_entry
) == -1) {
1640 DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
1641 i
, strerror(errno
) ));
1646 * Ok - we now know the ACL calls should be working, don't
1647 * allow fallback to chmod.
1650 *pacl_set_support
= True
;
1653 * Initialise the entry from the canon_ace.
1657 * First tell the entry what type of ACE this is.
1660 if (conn
->vfs_ops
.sys_acl_set_tag_type(conn
, the_entry
, p_ace
->type
) == -1) {
1661 DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
1662 i
, strerror(errno
) ));
1667 * Only set the qualifier (user or group id) if the entry is a user
1671 if ((p_ace
->type
== SMB_ACL_USER
) || (p_ace
->type
== SMB_ACL_GROUP
)) {
1672 if (conn
->vfs_ops
.sys_acl_set_qualifier(conn
, the_entry
,(void *)&p_ace
->unix_ug
.uid
) == -1) {
1673 DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
1674 i
, strerror(errno
) ));
1680 * Convert the mode_t perms in the canon_ace to a POSIX permset.
1683 if (conn
->vfs_ops
.sys_acl_get_permset(conn
, the_entry
, &the_permset
) == -1) {
1684 DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
1685 i
, strerror(errno
) ));
1689 if (map_acl_perms_to_permset(conn
, p_ace
->perms
, &the_permset
) == -1) {
1690 DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
1691 (unsigned int)p_ace
->perms
, i
, strerror(errno
) ));
1696 * ..and apply them to the entry.
1699 if (conn
->vfs_ops
.sys_acl_set_permset(conn
, the_entry
, the_permset
) == -1) {
1700 DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
1701 i
, strerror(errno
) ));
1706 print_canon_ace( p_ace
, i
);
1710 * Add in a mask of rwx.
1713 if (conn
->vfs_ops
.sys_acl_create_entry( conn
, &the_acl
, &mask_entry
) == -1) {
1714 DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno
) ));
1718 if (conn
->vfs_ops
.sys_acl_set_tag_type(conn
, mask_entry
, SMB_ACL_MASK
) == -1) {
1719 DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno
) ));
1723 if (conn
->vfs_ops
.sys_acl_get_permset(conn
, mask_entry
, &mask_permset
) == -1) {
1724 DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno
) ));
1728 if (map_acl_perms_to_permset(conn
, S_IRUSR
|S_IWUSR
|S_IXUSR
, &mask_permset
) == -1) {
1729 DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno
) ));
1733 if (conn
->vfs_ops
.sys_acl_set_permset(conn
, mask_entry
, mask_permset
) == -1) {
1734 DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno
) ));
1739 * Check if the ACL is valid.
1742 if (conn
->vfs_ops
.sys_acl_valid(conn
, the_acl
) == -1) {
1743 DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n",
1744 the_acl_type
== SMB_ACL_TYPE_DEFAULT
? "directory default" : "file",
1750 * Finally apply it to the file or directory.
1753 if(default_ace
|| fsp
->is_directory
|| fsp
->fd
== -1) {
1754 if (conn
->vfs_ops
.sys_acl_set_file(conn
, fsp
->fsp_name
, the_acl_type
, the_acl
) == -1) {
1756 * Some systems allow all the above calls and only fail with no ACL support
1757 * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
1759 if (errno
== ENOSYS
)
1760 *pacl_set_support
= False
;
1761 DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
1762 the_acl_type
== SMB_ACL_TYPE_DEFAULT
? "directory default" : "file",
1763 fsp
->fsp_name
, strerror(errno
) ));
1767 if (conn
->vfs_ops
.sys_acl_set_fd(fsp
, fsp
->fd
, the_acl
) == -1) {
1769 * Some systems allow all the above calls and only fail with no ACL support
1770 * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
1772 if (errno
== ENOSYS
)
1773 *pacl_set_support
= False
;
1774 DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
1775 fsp
->fsp_name
, strerror(errno
) ));
1784 if (the_acl
!= NULL
)
1785 conn
->vfs_ops
.sys_acl_free_acl(conn
, the_acl
);
1790 /****************************************************************************
1791 Convert a canon_ace to a generic 3 element permission - if possible.
1792 ****************************************************************************/
1794 #define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
1796 static BOOL
convert_canon_ace_to_posix_perms( files_struct
*fsp
, canon_ace
*file_ace_list
, mode_t
*posix_perms
)
1798 int snum
= SNUM(fsp
->conn
);
1799 size_t ace_count
= count_canon_ace_list(file_ace_list
);
1801 canon_ace
*owner_ace
= NULL
;
1802 canon_ace
*group_ace
= NULL
;
1803 canon_ace
*other_ace
= NULL
;
1807 if (ace_count
!= 3) {
1808 DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \
1809 posix perms.\n", fsp
->fsp_name
));
1813 for (ace_p
= file_ace_list
; ace_p
; ace_p
= ace_p
->next
) {
1814 if (ace_p
->owner_type
== UID_ACE
)
1816 else if (ace_p
->owner_type
== GID_ACE
)
1818 else if (ace_p
->owner_type
== WORLD_ACE
)
1822 if (!owner_ace
|| !group_ace
|| !other_ace
) {
1823 DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n",
1828 *posix_perms
= (mode_t
)0;
1830 *posix_perms
|= owner_ace
->perms
;
1831 *posix_perms
|= MAP_PERM(group_ace
->perms
, S_IRUSR
, S_IRGRP
);
1832 *posix_perms
|= MAP_PERM(group_ace
->perms
, S_IWUSR
, S_IWGRP
);
1833 *posix_perms
|= MAP_PERM(group_ace
->perms
, S_IXUSR
, S_IXGRP
);
1834 *posix_perms
|= MAP_PERM(other_ace
->perms
, S_IRUSR
, S_IROTH
);
1835 *posix_perms
|= MAP_PERM(other_ace
->perms
, S_IWUSR
, S_IWOTH
);
1836 *posix_perms
|= MAP_PERM(other_ace
->perms
, S_IXUSR
, S_IXOTH
);
1838 /* The owner must have at least read access. */
1840 *posix_perms
|= S_IRUSR
;
1841 if (fsp
->is_directory
)
1842 *posix_perms
|= (S_IWUSR
|S_IXUSR
);
1844 /* If requested apply the masks. */
1846 /* Get the initial bits to apply. */
1848 if (fsp
->is_directory
) {
1849 and_bits
= lp_dir_security_mask(snum
);
1850 or_bits
= lp_force_dir_security_mode(snum
);
1852 and_bits
= lp_security_mask(snum
);
1853 or_bits
= lp_force_security_mode(snum
);
1856 *posix_perms
= (((*posix_perms
) & and_bits
)|or_bits
);
1858 DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n",
1859 (int)owner_ace
->perms
, (int)group_ace
->perms
, (int)other_ace
->perms
, (int)*posix_perms
,
1865 static int nt_ace_comp( SEC_ACE
*a1
, SEC_ACE
*a2
)
1867 if (a1
->type
== a2
->type
)
1870 if (a1
->type
== SEC_ACE_TYPE_ACCESS_DENIED
&& a2
->type
== SEC_ACE_TYPE_ACCESS_ALLOWED
)
1875 /****************************************************************************
1876 Reply to query a security descriptor from an fsp. If it succeeds it allocates
1877 the space for the return elements and returns the size needed to return the
1878 security descriptor. This should be the only external function needed for
1879 the UNIX style get ACL.
1880 ****************************************************************************/
1882 size_t get_nt_acl(files_struct
*fsp
, SEC_DESC
**ppdesc
)
1884 extern DOM_SID global_sid_Builtin_Administrators
;
1885 extern DOM_SID global_sid_Builtin_Users
;
1886 connection_struct
*conn
= fsp
->conn
;
1887 SMB_STRUCT_STAT sbuf
;
1888 SEC_ACE
*nt_ace_list
= NULL
;
1892 SEC_ACL
*psa
= NULL
;
1893 size_t num_acls
= 0;
1894 size_t num_dir_acls
= 0;
1895 size_t num_aces
= 0;
1896 SMB_ACL_T posix_acl
= NULL
;
1897 SMB_ACL_T dir_acl
= NULL
;
1898 canon_ace
*file_ace
= NULL
;
1899 canon_ace
*dir_ace
= NULL
;
1900 size_t num_profile_acls
= 0;
1904 DEBUG(10,("get_nt_acl: called for file %s\n", fsp
->fsp_name
));
1906 if(fsp
->is_directory
|| fsp
->fd
== -1) {
1908 /* Get the stat struct for the owner info. */
1909 if(vfs_stat(fsp
->conn
,fsp
->fsp_name
, &sbuf
) != 0) {
1913 * Get the ACL from the path.
1916 posix_acl
= conn
->vfs_ops
.sys_acl_get_file(conn
, fsp
->fsp_name
, SMB_ACL_TYPE_ACCESS
);
1919 * If it's a directory get the default POSIX ACL.
1922 if(fsp
->is_directory
)
1923 dir_acl
= conn
->vfs_ops
.sys_acl_get_file(conn
, fsp
->fsp_name
, SMB_ACL_TYPE_DEFAULT
);
1927 /* Get the stat struct for the owner info. */
1928 if(vfs_fstat(fsp
,fsp
->fd
,&sbuf
) != 0) {
1932 * Get the ACL from the fd.
1934 posix_acl
= conn
->vfs_ops
.sys_acl_get_fd(fsp
, fsp
->fd
);
1937 DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
1938 posix_acl
? "present" : "absent",
1939 dir_acl
? "present" : "absent" ));
1942 * Get the owner, group and world SIDs.
1945 if (lp_profile_acls(SNUM(fsp
->conn
))) {
1946 /* For WXP SP1 the owner must be administrators. */
1947 sid_copy(&owner_sid
, &global_sid_Builtin_Administrators
);
1948 sid_copy(&group_sid
, &global_sid_Builtin_Users
);
1949 num_profile_acls
= 2;
1951 create_file_sids(&sbuf
, &owner_sid
, &group_sid
);
1954 /* Create the canon_ace lists. */
1955 file_ace
= canonicalise_acl( fsp
, posix_acl
, &sbuf
, &owner_sid
, &group_sid
);
1956 num_acls
= count_canon_ace_list(file_ace
);
1958 /* We must have *some* ACLS. */
1960 if (num_acls
== 0) {
1961 DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp
->fsp_name
));
1965 if (fsp
->is_directory
) {
1967 * If we have to fake a default ACL then this is the mode to use.
1969 sbuf
.st_mode
= unix_mode( fsp
->conn
, FILE_ATTRIBUTE_ARCHIVE
, fsp
->fsp_name
);
1971 dir_ace
= canonicalise_acl(fsp
, dir_acl
, &sbuf
, &owner_sid
, &group_sid
);
1972 num_dir_acls
= count_canon_ace_list(dir_ace
);
1975 /* Allocate the ace list. */
1976 if ((nt_ace_list
= (SEC_ACE
*)malloc((num_acls
+ num_profile_acls
+ num_dir_acls
)* sizeof(SEC_ACE
))) == NULL
) {
1977 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
1981 memset(nt_ace_list
, '\0', (num_acls
+ num_dir_acls
) * sizeof(SEC_ACE
) );
1984 * Create the NT ACE list from the canonical ace lists.
1994 for (i
= 0; i
< num_acls
; i
++, ace
= ace
->next
) {
1995 SEC_ACCESS acc
= map_canon_ace_perms(&nt_acl_type
, &owner_sid
, ace
);
1996 init_sec_ace(&nt_ace_list
[num_aces
++], &ace
->trustee
, nt_acl_type
, acc
, 0);
1999 /* The User must have access to a profile share - even if we can't map the SID. */
2000 if (lp_profile_acls(SNUM(fsp
->conn
))) {
2002 init_sec_access(&acc
,FILE_GENERIC_ALL
);
2003 init_sec_ace(&nt_ace_list
[num_aces
++], &global_sid_Builtin_Users
, SEC_ACE_TYPE_ACCESS_ALLOWED
, acc
, 0);
2008 for (i
= 0; i
< num_dir_acls
; i
++, ace
= ace
->next
) {
2009 SEC_ACCESS acc
= map_canon_ace_perms(&nt_acl_type
, &owner_sid
, ace
);
2010 init_sec_ace(&nt_ace_list
[num_aces
++], &ace
->trustee
, nt_acl_type
, acc
,
2011 SEC_ACE_FLAG_OBJECT_INHERIT
|SEC_ACE_FLAG_CONTAINER_INHERIT
|SEC_ACE_FLAG_INHERIT_ONLY
);
2014 /* The User must have access to a profile share - even if we can't map the SID. */
2015 if (lp_profile_acls(SNUM(fsp
->conn
))) {
2017 init_sec_access(&acc
,FILE_GENERIC_ALL
);
2018 init_sec_ace(&nt_ace_list
[num_aces
++], &global_sid_Builtin_Users
, SEC_ACE_TYPE_ACCESS_ALLOWED
, acc
,
2019 SEC_ACE_FLAG_OBJECT_INHERIT
|SEC_ACE_FLAG_CONTAINER_INHERIT
|
2020 SEC_ACE_FLAG_INHERIT_ONLY
);
2024 * Sort to force deny entries to the front.
2027 if (num_acls
+ num_dir_acls
)
2028 qsort( nt_ace_list
, num_acls
+ num_dir_acls
, sizeof(nt_ace_list
[0]), QSORT_CAST nt_ace_comp
);
2032 if((psa
= make_sec_acl( main_loop_talloc_get(), ACL_REVISION
, num_aces
, nt_ace_list
)) == NULL
) {
2033 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
2038 *ppdesc
= make_standard_sec_desc( main_loop_talloc_get(), &owner_sid
, &group_sid
, psa
, &sd_size
);
2041 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
2048 conn
->vfs_ops
.sys_acl_free_acl(conn
, posix_acl
);
2050 conn
->vfs_ops
.sys_acl_free_acl(conn
, dir_acl
);
2051 free_canon_ace_list(file_ace
);
2052 free_canon_ace_list(dir_ace
);
2053 SAFE_FREE(nt_ace_list
);
2059 try to chown a file. We will be able to chown it under the following conditions
2061 1) if we have root privileges, then it will just work
2062 2) if we have write permission to the file and dos_filemodes is set
2063 then allow chown to the currently authenticated user.
2066 static int try_chown(connection_struct
*conn
, const char *fname
, uid_t uid
, gid_t gid
)
2069 extern struct current_user current_user
;
2073 /* try the direct way first */
2074 ret
= vfs_chown(conn
, fname
, uid
, gid
);
2078 if(!CAN_WRITE(conn
) || !lp_dos_filemode(SNUM(conn
)))
2081 if (vfs_stat(conn
,fname
,&st
))
2084 fsp
= open_file_fchmod(conn
,fname
,&st
);
2088 /* only allow chown to the current user. This is more secure,
2089 and also copes with the case where the SID in a take ownership ACL is
2090 a local SID on the users workstation
2092 uid
= current_user
.uid
;
2095 /* Keep the current file gid the same. */
2096 ret
= vfswrap_fchown(fsp
, fsp
->fd
, uid
, (gid_t
)-1);
2099 close_file_fchmod(fsp
);
2104 /****************************************************************************
2105 Reply to set a security descriptor on an fsp. security_info_sent is the
2106 description of the following NT ACL.
2107 This should be the only external function needed for the UNIX style set ACL.
2108 ****************************************************************************/
2110 BOOL
set_nt_acl(files_struct
*fsp
, uint32 security_info_sent
, SEC_DESC
*psd
)
2112 connection_struct
*conn
= fsp
->conn
;
2113 uid_t user
= (uid_t
)-1;
2114 gid_t grp
= (gid_t
)-1;
2115 SMB_STRUCT_STAT sbuf
;
2116 DOM_SID file_owner_sid
;
2117 DOM_SID file_grp_sid
;
2118 canon_ace
*file_ace_list
= NULL
;
2119 canon_ace
*dir_ace_list
= NULL
;
2120 BOOL acl_perms
= False
;
2121 mode_t orig_mode
= (mode_t
)0;
2125 DEBUG(10,("set_nt_acl: called for file %s\n", fsp
->fsp_name
));
2128 * Get the current state of the file.
2131 if(fsp
->is_directory
|| fsp
->fd
== -1) {
2132 if(vfs_stat(fsp
->conn
,fsp
->fsp_name
, &sbuf
) != 0)
2135 if(vfs_fstat(fsp
,fsp
->fd
,&sbuf
) != 0)
2139 /* Save the original elements we check against. */
2140 orig_mode
= sbuf
.st_mode
;
2141 orig_uid
= sbuf
.st_uid
;
2142 orig_gid
= sbuf
.st_gid
;
2145 * Unpack the user/group/world id's.
2148 if (!unpack_nt_owners( &sbuf
, &user
, &grp
, security_info_sent
, psd
))
2152 * Do we need to chown ?
2155 if((user
!= (uid_t
)-1 || grp
!= (uid_t
)-1) && (orig_uid
!= user
|| orig_gid
!= grp
)) {
2157 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
2158 fsp
->fsp_name
, (unsigned int)user
, (unsigned int)grp
));
2160 if(try_chown( fsp
->conn
, fsp
->fsp_name
, user
, grp
) == -1) {
2161 DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
2162 fsp
->fsp_name
, (unsigned int)user
, (unsigned int)grp
, strerror(errno
) ));
2167 * Recheck the current state of the file, which may have changed.
2168 * (suid/sgid bits, for instance)
2171 if(fsp
->is_directory
) {
2172 if(vfs_stat(fsp
->conn
, fsp
->fsp_name
, &sbuf
) != 0) {
2180 ret
= vfs_stat(fsp
->conn
, fsp
->fsp_name
, &sbuf
);
2182 ret
= vfs_fstat(fsp
,fsp
->fd
,&sbuf
);
2188 /* Save the original elements we check against. */
2189 orig_mode
= sbuf
.st_mode
;
2190 orig_uid
= sbuf
.st_uid
;
2191 orig_gid
= sbuf
.st_gid
;
2194 create_file_sids(&sbuf
, &file_owner_sid
, &file_grp_sid
);
2196 acl_perms
= unpack_canon_ace( fsp
, &sbuf
, &file_owner_sid
, &file_grp_sid
,
2197 &file_ace_list
, &dir_ace_list
, security_info_sent
, psd
);
2199 if ((file_ace_list
== NULL
) && (dir_ace_list
== NULL
)) {
2200 /* W2K traverse DACL set - ignore. */
2205 DEBUG(3,("set_nt_acl: cannot set permissions\n"));
2206 free_canon_ace_list(file_ace_list
);
2207 free_canon_ace_list(dir_ace_list
);
2212 * Only change security if we got a DACL.
2215 if((security_info_sent
& DACL_SECURITY_INFORMATION
) && (psd
->dacl
!= NULL
)) {
2217 BOOL acl_set_support
= False
;
2221 * Try using the POSIX ACL set first. Fall back to chmod if
2222 * we have no ACL support on this filesystem.
2225 if (acl_perms
&& file_ace_list
) {
2226 ret
= set_canon_ace_list(fsp
, file_ace_list
, False
, &acl_set_support
);
2227 if (acl_set_support
&& ret
== False
) {
2228 DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp
->fsp_name
, strerror(errno
) ));
2229 free_canon_ace_list(file_ace_list
);
2230 free_canon_ace_list(dir_ace_list
);
2235 if (acl_perms
&& acl_set_support
&& fsp
->is_directory
) {
2237 if (!set_canon_ace_list(fsp
, dir_ace_list
, True
, &acl_set_support
)) {
2238 DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp
->fsp_name
, strerror(errno
) ));
2239 free_canon_ace_list(file_ace_list
);
2240 free_canon_ace_list(dir_ace_list
);
2246 * No default ACL - delete one if it exists.
2249 if (conn
->vfs_ops
.sys_acl_delete_def_file(conn
, fsp
->fsp_name
) == -1) {
2250 DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno
)));
2251 free_canon_ace_list(file_ace_list
);
2258 * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
2261 if(!acl_set_support
&& acl_perms
) {
2264 if (!convert_canon_ace_to_posix_perms( fsp
, file_ace_list
, &posix_perms
)) {
2265 free_canon_ace_list(file_ace_list
);
2266 free_canon_ace_list(dir_ace_list
);
2267 DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
2272 if (orig_mode
!= posix_perms
) {
2274 DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
2275 fsp
->fsp_name
, (unsigned int)posix_perms
));
2277 if(conn
->vfs_ops
.chmod(conn
,fsp
->fsp_name
, posix_perms
) == -1) {
2278 DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
2279 fsp
->fsp_name
, (unsigned int)posix_perms
, strerror(errno
) ));
2280 free_canon_ace_list(file_ace_list
);
2281 free_canon_ace_list(dir_ace_list
);
2288 free_canon_ace_list(file_ace_list
);
2289 free_canon_ace_list(dir_ace_list
);
2294 /****************************************************************************
2295 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
2296 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
2297 ****************************************************************************/
2299 static int chmod_acl_internals( connection_struct
*conn
, SMB_ACL_T posix_acl
, mode_t mode
)
2301 int entry_id
= SMB_ACL_FIRST_ENTRY
;
2302 SMB_ACL_ENTRY_T entry
;
2303 int num_entries
= 0;
2305 while ( conn
->vfs_ops
.sys_acl_get_entry(conn
, posix_acl
, entry_id
, &entry
) == 1) {
2306 SMB_ACL_TAG_T tagtype
;
2307 SMB_ACL_PERMSET_T permset
;
2311 if (entry_id
== SMB_ACL_FIRST_ENTRY
)
2312 entry_id
= SMB_ACL_NEXT_ENTRY
;
2314 if (conn
->vfs_ops
.sys_acl_get_tag_type(conn
, entry
, &tagtype
) == -1)
2317 if (conn
->vfs_ops
.sys_acl_get_permset(conn
, entry
, &permset
) == -1)
2323 case SMB_ACL_USER_OBJ
:
2324 perms
= unix_perms_to_acl_perms(mode
, S_IRUSR
, S_IWUSR
, S_IXUSR
);
2326 case SMB_ACL_GROUP_OBJ
:
2327 perms
= unix_perms_to_acl_perms(mode
, S_IRGRP
, S_IWGRP
, S_IXGRP
);
2330 perms
= S_IRUSR
|S_IWUSR
|S_IXUSR
;
2333 perms
= unix_perms_to_acl_perms(mode
, S_IROTH
, S_IWOTH
, S_IXOTH
);
2339 if (map_acl_perms_to_permset(conn
, perms
, &permset
) == -1)
2342 if (conn
->vfs_ops
.sys_acl_set_permset(conn
, entry
, permset
) == -1)
2347 * If this is a simple 3 element ACL or no elements then it's a standard
2348 * UNIX permission set. Just use chmod...
2351 if ((num_entries
== 3) || (num_entries
== 0))
2357 /****************************************************************************
2358 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
2359 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
2360 Note that name is in UNIX character set.
2361 ****************************************************************************/
2363 int chmod_acl(connection_struct
*conn
, const char *name
, mode_t mode
)
2365 SMB_ACL_T posix_acl
= NULL
;
2368 if ((posix_acl
= conn
->vfs_ops
.sys_acl_get_file(conn
, name
, SMB_ACL_TYPE_ACCESS
)) == NULL
)
2371 if ((ret
= chmod_acl_internals(conn
, posix_acl
, mode
)) == -1)
2374 ret
= conn
->vfs_ops
.sys_acl_set_file(conn
, name
, SMB_ACL_TYPE_ACCESS
, posix_acl
);
2378 conn
->vfs_ops
.sys_acl_free_acl(conn
, posix_acl
);
2382 /****************************************************************************
2383 Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
2384 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
2385 ****************************************************************************/
2387 int fchmod_acl(files_struct
*fsp
, int fd
, mode_t mode
)
2389 connection_struct
*conn
= fsp
->conn
;
2390 SMB_ACL_T posix_acl
= NULL
;
2393 if ((posix_acl
= conn
->vfs_ops
.sys_acl_get_fd(fsp
, fd
)) == NULL
)
2396 if ((ret
= chmod_acl_internals(conn
, posix_acl
, mode
)) == -1)
2399 ret
= conn
->vfs_ops
.sys_acl_set_fd(fsp
, fd
, posix_acl
);
2403 conn
->vfs_ops
.sys_acl_free_acl(conn
, posix_acl
);
2407 BOOL
directory_has_default_acl(connection_struct
*conn
, const char *fname
)
2409 SMB_ACL_T dir_acl
= conn
->vfs_ops
.sys_acl_get_file( conn
, fname
, SMB_ACL_TYPE_DEFAULT
);
2410 BOOL has_acl
= False
;
2411 SMB_ACL_ENTRY_T entry
;
2413 if (dir_acl
!= NULL
&& (conn
->vfs_ops
.sys_acl_get_entry(conn
, dir_acl
, SMB_ACL_FIRST_ENTRY
, &entry
) == 1))
2417 conn
->vfs_ops
.sys_acl_free_acl(conn
, dir_acl
);