1 /* sec/acl.cc: Solaris compatible ACL functions.
3 Written by Corinna Vinschen <corinna@vinschen.de>
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
22 #include "sec_posixacl.h"
24 /* How does a correctly constructed new-style Windows ACL claiming to be a
27 - NULL deny ACE (special bits, CLASS_OBJ).
29 - USER_OBJ deny. If the user has less permissions than the sum of CLASS_OBJ
30 (or GROUP_OBJ if CLASS_OBJ doesn't exist) and OTHER_OBJ, deny the excess
31 permissions so that group and other perms don't spill into the owner perms.
33 USER_OBJ deny ACE == ~USER_OBJ & (CLASS_OBJ | OTHER_OBJ)
35 USER_OBJ deny ACE == ~USER_OBJ & (GROUP_OBJ | OTHER_OBJ)
37 - USER deny. If a user has more permissions than CLASS_OBJ, or if the
38 user has less permissions than OTHER_OBJ, deny the excess permissions.
40 USER deny ACE == (USER & ~CLASS_OBJ) | (~USER & OTHER_OBJ)
45 The POSIX permissions returned for a USER entry are the allow bits alone!
47 - GROUP{_OBJ} deny. If a group has more permissions than CLASS_OBJ,
48 or less permissions than OTHER_OBJ, deny the excess permissions.
50 GROUP{_OBJ} deny ACEs == (GROUP & ~CLASS_OBJ)
55 The POSIX permissions returned for a GROUP entry are the allow bits alone!
57 - 2. GROUP{_OBJ} deny. If a group has less permissions than OTHER_OBJ,
58 deny the excess permissions.
60 2. GROUP{_OBJ} deny ACEs == (~GROUP & OTHER_OBJ)
64 Rinse and repeat for default ACEs with INHERIT flags set.
66 - Default NULL deny ACE (S_ISGID, CLASS_OBJ). */
70 /* Historically, these bits are stored in a NULL allow SID ACE. To distinguish
71 the new ACL style from the old one, we're using an access denied ACE, plus
72 setting an as yet unused bit in the access mask. The new ACEs can exist
73 twice in an ACL, the "normal one" containing CLASS_OBJ and special bits
74 and the one with INHERIT bit set to pass the DEF_CLASS_OBJ bits and the
76 #define CYG_ACE_ISVTX 0x001 /* 0x200 <-> 0x001 */
77 #define CYG_ACE_ISGID 0x002 /* 0x400 <-> 0x002 */
78 #define CYG_ACE_ISUID 0x004 /* 0x800 <-> 0x004 */
79 #define CYG_ACE_ISBITS_TO_POSIX(val) \
80 (((val) & 0x007) << 9)
81 #define CYG_ACE_ISBITS_TO_WIN(val) \
82 (((val) & (S_ISVTX | S_ISUID | S_ISGID)) >> 9)
84 #define CYG_ACE_MASK_X 0x008 /* 0x001 <-> 0x008 */
85 #define CYG_ACE_MASK_W 0x010 /* 0x002 <-> 0x010 */
86 #define CYG_ACE_MASK_R 0x020 /* 0x004 <-> 0x020 */
87 #define CYG_ACE_MASK_RWX 0x038
88 #define CYG_ACE_MASK_VALID 0x040 /* has mask if set */
89 #define CYG_ACE_MASK_TO_POSIX(val) \
90 (((val) & CYG_ACE_MASK_RWX) >> 3)
91 #define CYG_ACE_MASK_TO_WIN(val) \
92 ((((val) & S_IRWXO) << 3) \
94 #define CYG_ACE_NEW_STYLE READ_CONTROL /* New style if set. */
96 /* Define own bit masks rather than using the GENERIC masks. The latter
97 also contain standard rights, which we don't need here. */
98 #define FILE_ALLOW_READ (FILE_READ_DATA | FILE_READ_ATTRIBUTES | \
100 #define FILE_DENY_READ (FILE_READ_DATA | FILE_READ_EA)
101 #define FILE_ALLOW_WRITE (FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | \
102 FILE_WRITE_EA | FILE_APPEND_DATA)
103 #define FILE_DENY_WRITE FILE_ALLOW_WRITE | FILE_DELETE_CHILD
104 #define FILE_DENY_WRITE_OWNER (FILE_WRITE_DATA | FILE_WRITE_EA | \
105 FILE_APPEND_DATA | FILE_DELETE_CHILD)
106 #define FILE_ALLOW_EXEC (FILE_EXECUTE)
107 #define FILE_DENY_EXEC FILE_ALLOW_EXEC
109 #define STD_RIGHTS_OTHER (STANDARD_RIGHTS_READ | SYNCHRONIZE)
110 #define STD_RIGHTS_OWNER (STANDARD_RIGHTS_ALL | SYNCHRONIZE)
113 searchace (aclent_t
*aclp
, int nentries
, int type
, uid_t id
)
117 for (i
= 0; i
< nentries
; ++i
)
118 if ((aclp
[i
].a_type
== type
119 && (id
== ACL_UNDEFINED_ID
|| aclp
[i
].a_id
== id
))
125 /* From the attributes and the POSIX ACL list, compute a new-style Cygwin
126 security descriptor. The function returns a pointer to the
127 SECURITY_DESCRIPTOR in sd_ret, or NULL if the function fails.
129 This function *requires* a verified and sorted acl list! */
131 set_posix_access (mode_t attr
, uid_t uid
, gid_t gid
,
132 aclent_t
*aclbufp
, int nentries
,
133 security_descriptor
&sd_ret
,
136 SECURITY_DESCRIPTOR sd
;
138 PSID owner
= NULL
, group
= NULL
;
139 cygsid smb_owner
, smb_group
;
144 size_t acl_len
= sizeof (ACL
);
145 mode_t user_obj
, group_obj
, other_obj
, deny
;
146 mode_t class_obj
= 0;
148 int idx
, start_idx
, tmp_idx
;
149 bool owner_eq_group
= false;
150 bool dev_has_admins
= false;
153 /* Initialize local security descriptor. */
154 RtlCreateSecurityDescriptor (&sd
, SECURITY_DESCRIPTOR_REVISION
);
156 /* As in alloc_sd, set SE_DACL_PROTECTED to prevent the DACL from being
157 modified by inheritable ACEs. */
158 RtlSetControlSecurityDescriptor (&sd
, SE_DACL_PROTECTED
, SE_DACL_PROTECTED
);
160 /* Fetch owner and group and set in security descriptor.
162 For Samba we check if there's an RFC2307 mapping in place, otherwise
163 we're trying to create an ACL with the wrong Windows SIDs rather than
164 the correct Unix SIDs. Same happens below for mapping other USER and
168 uint32_t smb_uid
, smb_gid
;
170 smb_uid
= cygheap
->ugid_cache
.reverse_get_uid (uid
);
171 if (smb_uid
!= ILLEGAL_UID
)
172 owner
= smb_owner
.create (22, 2, 1, smb_uid
);
173 smb_gid
= cygheap
->ugid_cache
.reverse_get_gid (gid
);
174 if (smb_gid
!= ILLEGAL_GID
)
175 group
= smb_group
.create (22, 2, 2, smb_gid
);
178 owner
= sidfromuid (uid
, &cldap
);
180 group
= sidfromgid (gid
, &cldap
);
181 if (!owner
|| !group
)
186 status
= RtlSetOwnerSecurityDescriptor (&sd
, owner
, FALSE
);
187 if (!NT_SUCCESS (status
))
189 __seterrno_from_nt_status (status
);
192 status
= RtlSetGroupSecurityDescriptor (&sd
, group
, FALSE
);
193 if (!NT_SUCCESS (status
))
195 __seterrno_from_nt_status (status
);
198 owner_eq_group
= RtlEqualSid (owner
, group
);
200 dev_has_admins
= well_known_admins_sid
== owner
201 || well_known_admins_sid
== group
;
203 /* No POSIX ACL? Use attr to generate one from scratch. */
206 aclbufp
= (aclent_t
*) tp
.c_get ();
207 aclbufp
[0].a_type
= USER_OBJ
;
208 aclbufp
[0].a_id
= ACL_UNDEFINED_ID
;
209 aclbufp
[0].a_perm
= (attr
>> 6) & S_IRWXO
;
210 aclbufp
[1].a_type
= GROUP_OBJ
;
211 aclbufp
[1].a_id
= ACL_UNDEFINED_ID
;
212 aclbufp
[1].a_perm
= (attr
>> 3) & S_IRWXO
;
213 aclbufp
[2].a_type
= OTHER_OBJ
;
214 aclbufp
[2].a_id
= ACL_UNDEFINED_ID
;
215 aclbufp
[2].a_perm
= attr
& S_IRWXO
;
216 nentries
= MIN_ACL_ENTRIES
;
219 aclbufp
[3].a_type
= DEF_USER_OBJ
;
220 aclbufp
[3].a_id
= ACL_UNDEFINED_ID
;
221 aclbufp
[3].a_perm
= (attr
>> 6) & S_IRWXO
;
222 aclbufp
[4].a_type
= GROUP_OBJ
;
223 aclbufp
[4].a_id
= ACL_UNDEFINED_ID
;
224 aclbufp
[4].a_perm
= (attr
>> 3) & S_IRWXO
;
225 aclbufp
[5].a_type
= OTHER_OBJ
;
226 aclbufp
[5].a_id
= ACL_UNDEFINED_ID
;
227 aclbufp
[5].a_perm
= attr
& S_IRWXO
;
228 nentries
+= MIN_ACL_ENTRIES
;
232 /* Collect SIDs of all entries in aclbufp. */
233 aclsid
= (cygpsid
*) tp
.w_get ();
234 for (idx
= 0; idx
< nentries
; ++idx
)
235 switch (aclbufp
[idx
].a_type
)
241 aclsid
[idx
] = well_known_creator_owner_sid
;
245 aclsid
[idx
] = NO_SID
;
251 smb_uid
= cygheap
->ugid_cache
.reverse_get_uid (aclbufp
[idx
].a_id
);
252 if (smb_uid
!= ILLEGAL_UID
)
254 smb_sid
= (cygsid
*) alloca (sizeof (cygsid
));
255 aclsid
[idx
] = smb_sid
->create (22, 2, 1, smb_uid
);
259 aclsid
[idx
] = sidfromuid (aclbufp
[idx
].a_id
, &cldap
);
265 aclsid
[idx
] = !(attr
& S_ISGID
) ? (PSID
) well_known_creator_group_sid
270 aclsid
[idx
] = NO_SID
;
276 smb_gid
= cygheap
->ugid_cache
.reverse_get_gid (aclbufp
[idx
].a_id
);
277 if (smb_gid
!= ILLEGAL_GID
)
279 smb_sid
= (cygsid
*) alloca (sizeof (cygsid
));
280 aclsid
[idx
] = smb_sid
->create (22, 2, 2, smb_gid
);
284 aclsid
[idx
] = sidfromgid (aclbufp
[idx
].a_id
, &cldap
);
288 aclsid
[idx
] = well_known_null_sid
;
292 aclsid
[idx
] = well_known_world_sid
;
296 /* Initialize ACL. */
297 acl
= (PACL
) tp
.w_get ();
298 RtlCreateAcl (acl
, ACL_MAXIMUM_SIZE
, ACL_REVISION
);
300 /* This loop has two runs, the first handling the actual permission,
301 the second handling the default permissions. */
303 for (int def
= 0; def
<= ACL_DEFAULT
; def
+= ACL_DEFAULT
)
305 DWORD inherit
= def
? SUB_CONTAINERS_AND_OBJECTS_INHERIT
| INHERIT_ONLY
308 /* No default ACEs on files. */
309 if (def
&& !S_ISDIR (attr
))
311 /* Trying to set default ACEs on a non-directory is an error.
312 The underlying functions on Linux return EACCES. */
313 if (idx
< nentries
&& aclbufp
[idx
].a_type
& ACL_DEFAULT
)
321 /* To check if the NULL SID deny ACE is required we need user_obj. */
322 tmp_idx
= searchace (aclbufp
, nentries
, def
| USER_OBJ
);
323 /* No default entries present? */
326 user_obj
= aclbufp
[tmp_idx
].a_perm
;
327 /* To compute deny access masks, we need group_obj, other_obj and... */
328 tmp_idx
= searchace (aclbufp
, nentries
, def
| GROUP_OBJ
);
329 group_obj
= aclbufp
[tmp_idx
].a_perm
;
330 tmp_idx
= searchace (aclbufp
, nentries
, def
| OTHER_OBJ
);
331 other_obj
= aclbufp
[tmp_idx
].a_perm
;
333 /* ... class_obj. Create NULL deny ACE. Only the S_ISGID attribute gets
334 inherited. For directories check if we are also going to generate
335 default entries. If not we have a problem. We can't generate only a
336 single, inheritable NULL SID ACE because that leads to (fixable, TODO)
337 access problems when trying to create the matching child permissions.
338 Therefore we remove the S_ISGID bit on the directory because having it
339 set would be misleading. */
340 if (!def
&& S_ISDIR (attr
) && (attr
& S_ISGID
))
342 /* Check for a required entry per POSIX. */
343 tmp_idx
= searchace (aclbufp
, nentries
, DEF_USER_OBJ
);
347 access
= CYG_ACE_ISBITS_TO_WIN (def
? attr
& S_ISGID
: attr
)
349 tmp_idx
= searchace (aclbufp
, nentries
, def
| CLASS_OBJ
);
352 has_class_obj
= true;
353 class_obj
= aclbufp
[tmp_idx
].a_perm
;
354 access
|= CYG_ACE_MASK_TO_WIN (class_obj
);
358 /* Setting class_obj to group_obj allows to write below code without
359 additional checks for existence of a CLASS_OBJ. */
360 has_class_obj
= false;
361 class_obj
= group_obj
;
363 /* Note that Windows filters the ACE Mask value so it only reflects
364 the bit values supported by the object type. The result is that
365 we can't set a CLASS_OBJ value for ptys. The get_posix_access
366 function has to workaround that.
368 We also don't write the NULL SID ACE in case we have a simple POSIX
369 permission ACL with the user perms >= group perms >= other perms and
370 no special bits set. In all other cases we either need the NULL SID
371 ACE or we write it to avoid calls to AuthZ from get_posix_access. */
374 || access
!= CYG_ACE_NEW_STYLE
375 || ((user_obj
| group_obj
| other_obj
) != user_obj
376 || (group_obj
| other_obj
) != group_obj
))
377 && !add_access_denied_ace (acl
, access
, well_known_null_sid
, acl_len
,
381 /* Do we potentially chmod a file with owner SID == group SID? If so,
382 make sure the owner perms are always >= group perms. */
383 if (!def
&& owner_eq_group
)
384 aclbufp
[0].a_perm
|= group_obj
& class_obj
;
386 /* This loop has two runs, the first w/ check_types == (USER_OBJ | USER),
387 the second w/ check_types == (GROUP_OBJ | GROUP). Each run creates
388 first the deny, then the allow ACEs for the current types. */
389 for (int check_types
= USER_OBJ
| USER
;
390 check_types
< CLASS_OBJ
;
393 /* Create deny ACEs for users, then 1st run for groups. For groups,
394 only take CLASS_OBJ permissions into account. Class permissions
395 are handled in the 2nd deny loop below. */
396 for (start_idx
= idx
;
397 idx
< nentries
&& aclbufp
[idx
].a_type
& check_types
;
400 /* Avoid creating DENY ACEs for the second occurrence of
401 accounts which show up twice, as USER_OBJ and USER, or
402 GROUP_OBJ and GROUP. */
403 if ((aclbufp
[idx
].a_type
& USER
&& aclsid
[idx
] == owner
)
404 || (aclbufp
[idx
].a_type
& GROUP
&& aclsid
[idx
] == group
))
406 /* For the rules how to construct the deny access mask, see the
407 comment right at the start of this file. */
408 if (aclbufp
[idx
].a_type
& USER_OBJ
)
409 deny
= ~aclbufp
[idx
].a_perm
& (class_obj
| other_obj
);
410 else if (aclbufp
[idx
].a_type
& USER
)
411 deny
= (aclbufp
[idx
].a_perm
& ~class_obj
)
412 | (~aclbufp
[idx
].a_perm
& other_obj
);
413 /* Accommodate Windows: Only generate deny masks for SYSTEM
414 and the Administrators group in terms of the execute bit,
415 if they are not the primary group. */
416 else if (aclbufp
[idx
].a_type
& GROUP
417 && (aclsid
[idx
] == well_known_system_sid
418 || aclsid
[idx
] == well_known_admins_sid
))
419 deny
= aclbufp
[idx
].a_perm
& ~(class_obj
| S_IROTH
| S_IWOTH
);
421 deny
= (aclbufp
[idx
].a_perm
& ~class_obj
);
426 access
|= FILE_DENY_READ
;
428 access
|= (aclbufp
[idx
].a_type
& USER_OBJ
)
429 ? FILE_DENY_WRITE_OWNER
: FILE_DENY_WRITE
;
431 access
|= FILE_DENY_EXEC
;
432 if (!add_access_denied_ace (acl
, access
, aclsid
[idx
], acl_len
,
436 /* Create allow ACEs for users, then groups. */
437 for (idx
= start_idx
;
438 idx
< nentries
&& aclbufp
[idx
].a_type
& check_types
;
441 /* Don't set FILE_READ/WRITE_ATTRIBUTES unconditionally on Samba,
442 otherwise it enforces read permissions. */
443 access
= STD_RIGHTS_OTHER
| (is_samba
? 0 : FILE_READ_ATTRIBUTES
);
444 if (aclbufp
[idx
].a_type
& USER_OBJ
)
446 access
|= STD_RIGHTS_OWNER
;
448 access
|= FILE_WRITE_ATTRIBUTES
;
449 /* Set FILE_DELETE_CHILD on files with "rwx" perms for the
450 owner so that the owner gets "full control" (Duh). */
451 if (aclbufp
[idx
].a_perm
== S_IRWXO
)
452 access
|= FILE_DELETE_CHILD
;
454 if (aclbufp
[idx
].a_perm
& S_IROTH
)
455 access
|= FILE_ALLOW_READ
;
456 if (aclbufp
[idx
].a_perm
& S_IWOTH
)
457 access
|= FILE_ALLOW_WRITE
;
458 if (aclbufp
[idx
].a_perm
& S_IXOTH
)
459 access
|= FILE_ALLOW_EXEC
;
460 /* Handle S_ISVTX. */
462 && (aclbufp
[idx
].a_perm
& (S_IWOTH
| S_IXOTH
))
463 == (S_IWOTH
| S_IXOTH
)
464 && (!(attr
& S_ISVTX
) || aclbufp
[idx
].a_type
& USER_OBJ
))
465 access
|= FILE_DELETE_CHILD
;
466 /* For ptys, make sure the Administrators group has WRITE_DAC
467 and WRITE_OWNER perms. */
468 if (dev_has_admins
&& aclsid
[idx
] == well_known_admins_sid
)
469 access
|= STD_RIGHTS_OWNER
;
470 if (!add_access_allowed_ace (acl
, access
, aclsid
[idx
], acl_len
,
474 /* 2nd deny loop: Create deny ACEs for groups when they have less
475 permissions than OTHER_OBJ. */
476 if (check_types
== (GROUP_OBJ
| GROUP
))
477 for (idx
= start_idx
;
478 idx
< nentries
&& aclbufp
[idx
].a_type
& check_types
;
481 if (aclbufp
[idx
].a_type
& GROUP
&& aclsid
[idx
] == group
)
483 /* Only generate deny masks for SYSTEM and the Administrators
484 group if they are the primary group. */
485 if (aclbufp
[idx
].a_type
& GROUP
486 && (aclsid
[idx
] == well_known_system_sid
487 || aclsid
[idx
] == well_known_admins_sid
))
490 deny
= (~aclbufp
[idx
].a_perm
& other_obj
);
495 access
|= FILE_DENY_READ
;
497 access
|= FILE_DENY_WRITE
;
499 access
|= FILE_DENY_EXEC
;
500 if (!add_access_denied_ace (acl
, access
, aclsid
[idx
], acl_len
,
505 /* For ptys if the admins group isn't in the ACL, add an ACE to make
506 sure the admins group has WRITE_DAC and WRITE_OWNER perms. */
507 if (S_ISCHR (attr
) && !dev_has_admins
508 && !add_access_allowed_ace (acl
,
509 STD_RIGHTS_OWNER
| FILE_ALLOW_READ
511 well_known_admins_sid
, acl_len
,
514 /* Create allow ACE for other. It's preceeded by class_obj if it exists.
516 if (aclbufp
[idx
].a_type
& CLASS_OBJ
)
518 access
= STD_RIGHTS_OTHER
| (is_samba
? 0 : FILE_READ_ATTRIBUTES
);
519 if (aclbufp
[idx
].a_perm
& S_IROTH
)
520 access
|= FILE_ALLOW_READ
;
521 if (aclbufp
[idx
].a_perm
& S_IWOTH
)
522 access
|= FILE_ALLOW_WRITE
;
523 if (aclbufp
[idx
].a_perm
& S_IXOTH
)
524 access
|= FILE_ALLOW_EXEC
;
525 /* Handle S_ISVTX. */
527 && (aclbufp
[idx
].a_perm
& (S_IWOTH
| S_IXOTH
)) == (S_IWOTH
| S_IXOTH
)
528 && !(attr
& S_ISVTX
))
529 access
|= FILE_DELETE_CHILD
;
530 if (!add_access_allowed_ace (acl
, access
, aclsid
[idx
++], acl_len
,
535 /* Set AclSize to computed value. */
536 acl
->AclSize
= acl_len
;
537 debug_printf ("ACL-Size: %u", acl_len
);
538 /* Create DACL for local security descriptor. */
539 status
= RtlSetDaclSecurityDescriptor (&sd
, TRUE
, acl
, FALSE
);
540 if (!NT_SUCCESS (status
))
542 __seterrno_from_nt_status (status
);
545 /* Make self relative security descriptor in sd_ret. */
547 RtlAbsoluteToSelfRelativeSD (&sd
, sd_ret
, &sd_size
);
553 if (!sd_ret
.realloc (sd_size
))
558 status
= RtlAbsoluteToSelfRelativeSD (&sd
, sd_ret
, &sd_size
);
559 if (!NT_SUCCESS (status
))
561 __seterrno_from_nt_status (status
);
564 debug_printf ("Created SD-Size: %u", sd_ret
.size ());
568 /* This function *requires* a verified and sorted acl list! */
570 setacl (HANDLE handle
, path_conv
&pc
, int nentries
, aclent_t
*aclbufp
,
573 security_descriptor sd
, sd_ret
;
574 mode_t attr
= pc
.isdir () ? S_IFDIR
: 0;
578 if (get_file_sd (handle
, pc
, sd
, false))
580 if (get_posix_access (sd
, attr
, &uid
, &gid
, NULL
, 0) < 0)
582 if (!set_posix_access (attr
, uid
, gid
, aclbufp
, nentries
,
583 sd_ret
, pc
.fs_is_samba ()))
585 /* FIXME? Caller needs to know if any write perms are set to allow removing
588 return set_file_sd (handle
, pc
, sd_ret
, false);
591 /* Temporary access denied bits used by getace and get_posix_access during
592 Windows ACL processing. These bits get removed before the created POSIX
593 ACL gets published. */
594 #define DENY_R 040000
595 #define DENY_W 020000
596 #define DENY_X 010000
597 #define DENY_RWX (DENY_R | DENY_W | DENY_X)
599 /* New style ACL means, just read the bits and store them away. Don't
600 create masked values on your own. */
602 getace (aclent_t
&acl
, int type
, int id
, DWORD win_ace_mask
,
603 DWORD win_ace_type
, bool new_style
)
608 if ((win_ace_mask
& FILE_READ_BITS
)
609 && (new_style
|| !(acl
.a_perm
& (S_IROTH
| DENY_R
))))
611 if (win_ace_type
== ACCESS_ALLOWED_ACE_TYPE
)
612 acl
.a_perm
|= S_IROTH
;
613 else if (win_ace_type
== ACCESS_DENIED_ACE_TYPE
)
614 acl
.a_perm
|= DENY_R
;
617 if ((win_ace_mask
& FILE_WRITE_BITS
)
618 && (new_style
|| !(acl
.a_perm
& (S_IWOTH
| DENY_W
))))
620 if (win_ace_type
== ACCESS_ALLOWED_ACE_TYPE
)
621 acl
.a_perm
|= S_IWOTH
;
622 else if (win_ace_type
== ACCESS_DENIED_ACE_TYPE
)
623 acl
.a_perm
|= DENY_W
;
626 if ((win_ace_mask
& FILE_EXEC_BITS
)
627 && (new_style
|| !(acl
.a_perm
& (S_IXOTH
| DENY_X
))))
629 if (win_ace_type
== ACCESS_ALLOWED_ACE_TYPE
)
630 acl
.a_perm
|= S_IXOTH
;
631 else if (win_ace_type
== ACCESS_DENIED_ACE_TYPE
)
632 acl
.a_perm
|= DENY_X
;
636 /* From the SECURITY_DESCRIPTOR given in psd, compute user, owner, posix
637 attributes, as well as the POSIX acl. The function returns the number
638 of entries returned in aclbufp, or -1 in case of error.
640 When called from chmod, it also returns the fact if the ACL is a "standard"
641 ACL. A "standard" ACL is an ACL which only consists of ACEs for owner,
642 group, other, as well as (this is Windows) the Administrators group and
643 SYSTEM. See fhandler_disk_file::fchmod for how this is used to fake
644 stock POSIX perms even if Administrators and SYSTEM is in the ACE. */
646 get_posix_access (PSECURITY_DESCRIPTOR psd
,
647 mode_t
&attr_ret
, uid_t
*uid_ret
, gid_t
*gid_ret
,
648 aclent_t
*aclbufp
, int nentries
, bool *std_acl
)
652 BOOLEAN dummy
, acl_exists
;
653 SECURITY_DESCRIPTOR_CONTROL ctrl
;
656 PACCESS_ALLOWED_ACE ace
;
657 cygpsid owner_sid
, group_sid
;
662 aclent_t
*lacl
= NULL
;
663 cygpsid ace_sid
, *aclsid
;
664 int pos
, type
, id
, idx
;
667 bool just_created
= false;
668 bool standard_ACEs_only
= true;
669 bool new_style
= false;
670 bool saw_user_obj
= false;
671 bool saw_group_obj
= false;
672 bool saw_other_obj
= false;
673 bool saw_def_user_obj
= false;
674 bool saw_def_group_obj
= false;
675 bool has_class_perm
= false;
676 bool has_def_class_perm
= false;
678 mode_t class_perm
= 0;
679 mode_t def_class_perm
= 0;
681 int def_pgrp_pos
= -1;
683 if (aclbufp
&& nentries
< MIN_ACL_ENTRIES
)
688 /* If reading the security descriptor failed, treat the object as
694 *uid_ret
= ACL_UNDEFINED_ID
;
696 *gid_ret
= ACL_UNDEFINED_ID
;
699 aclbufp
[0].a_type
= USER_OBJ
;
700 aclbufp
[0].a_id
= ACL_UNDEFINED_ID
;
701 aclbufp
[0].a_perm
= 0;
702 aclbufp
[1].a_type
= GROUP_OBJ
;
703 aclbufp
[1].a_id
= ACL_UNDEFINED_ID
;
704 aclbufp
[1].a_perm
= 0;
705 aclbufp
[2].a_type
= OTHER_OBJ
;
706 aclbufp
[2].a_id
= ACL_UNDEFINED_ID
;
707 aclbufp
[2].a_perm
= 0;
708 return MIN_ACL_ENTRIES
;
712 /* Fetch owner, group, and ACL from security descriptor. */
713 status
= RtlGetOwnerSecurityDescriptor (psd
, (PSID
*) &owner_sid
, &dummy
);
714 if (!NT_SUCCESS (status
))
716 __seterrno_from_nt_status (status
);
719 status
= RtlGetGroupSecurityDescriptor (psd
, (PSID
*) &group_sid
, &dummy
);
720 if (!NT_SUCCESS (status
))
722 __seterrno_from_nt_status (status
);
725 status
= RtlGetDaclSecurityDescriptor (psd
, &acl_exists
, &acl
, &dummy
);
726 if (!NT_SUCCESS (status
))
728 __seterrno_from_nt_status (status
);
731 /* Set uidret, gidret, and initalize attributes. */
732 uid
= owner_sid
.get_uid (&cldap
);
733 gid
= group_sid
.get_gid (&cldap
);
734 attr
= attr_ret
& S_IFMT
;
735 just_created
= attr_ret
& S_JUSTCREATED
;
736 /* Remember the fact that owner and group are the same account. */
737 owner_eq_group
= owner_sid
== group_sid
;
739 /* Create and initialize local aclent_t array. */
740 lacl
= (aclent_t
*) tp
.c_get ();
741 memset (lacl
, 0, MAX_ACL_ENTRIES
* sizeof (aclent_t
*));
742 lacl
[0].a_type
= USER_OBJ
;
744 lacl
[1].a_type
= GROUP_OBJ
;
746 lacl
[2].a_type
= OTHER_OBJ
;
747 lacl
[2].a_id
= ACL_UNDEFINED_ID
;
748 /* Create array to collect SIDs of all entries in lacl. */
749 aclsid
= (cygpsid
*) tp
.w_get ();
750 aclsid
[0] = owner_sid
;
751 aclsid
[1] = group_sid
;
752 aclsid
[2] = well_known_world_sid
;
754 /* No ACEs? Everybody has full access. */
755 if (!acl_exists
|| !acl
|| acl
->AceCount
== 0)
757 for (pos
= 0; pos
< MIN_ACL_ENTRIES
; ++pos
)
758 lacl
[pos
].a_perm
= S_IROTH
| S_IWOTH
| S_IXOTH
;
762 /* Files and dirs are created with a NULL descriptor, so inheritence
763 rules kick in. If no inheritable entries exist in the parent object,
764 Windows will create entries according to the user token's default DACL.
765 These entries are not desired and we ignore them at creation time.
766 We're just checking the SE_DACL_AUTO_INHERITED flag here, since that's
767 what we set in get_file_sd. Read the longish comment there before
768 changing this test! */
770 && NT_SUCCESS (RtlGetControlSecurityDescriptor (psd
, &ctrl
, &rev
))
771 && !(ctrl
& SE_DACL_AUTO_INHERITED
))
773 else for (idx
= 0; idx
< acl
->AceCount
; ++idx
)
775 if (!NT_SUCCESS (RtlGetAce (acl
, idx
, (PVOID
*) &ace
)))
778 ace_sid
= (PSID
) &ace
->SidStart
;
780 if (ace_sid
== well_known_null_sid
)
782 /* Fetch special bits. */
783 attr
|= CYG_ACE_ISBITS_TO_POSIX (ace
->Mask
);
784 if (ace
->Header
.AceType
== ACCESS_DENIED_ACE_TYPE
785 && ace
->Mask
& CYG_ACE_NEW_STYLE
)
787 /* New-style ACL. Note the fact that a mask value is present
788 since that changes how getace fetches the information. That's
789 fine, because the NULL deny ACE is supposed to precede all
790 USER, GROUP and GROUP_OBJ entries. Any ACL not created that
791 way has been rearranged by the Windows functionality to create
792 the brain-dead "canonical" ACL order and is broken anyway. */
794 attr
|= CYG_ACE_ISBITS_TO_POSIX (ace
->Mask
);
795 if (ace
->Mask
& CYG_ACE_MASK_VALID
)
797 if (!(ace
->Header
.AceFlags
& INHERIT_ONLY
))
799 if ((pos
= searchace (lacl
, MAX_ACL_ENTRIES
, CLASS_OBJ
))
802 lacl
[pos
].a_type
= CLASS_OBJ
;
803 lacl
[pos
].a_id
= ACL_UNDEFINED_ID
;
804 lacl
[pos
].a_perm
= CYG_ACE_MASK_TO_POSIX (ace
->Mask
);
805 aclsid
[pos
] = well_known_null_sid
;
806 has_class_perm
= true;
807 class_perm
= lacl
[pos
].a_perm
;
811 && (ace
->Header
.AceFlags
& SUB_CONTAINERS_AND_OBJECTS_INHERIT
) != 0)
813 if ((pos
= searchace (lacl
, MAX_ACL_ENTRIES
,
814 DEF_CLASS_OBJ
)) >= 0)
816 lacl
[pos
].a_type
= DEF_CLASS_OBJ
;
817 lacl
[pos
].a_id
= ACL_UNDEFINED_ID
;
818 lacl
[pos
].a_perm
= CYG_ACE_MASK_TO_POSIX (ace
->Mask
);
819 aclsid
[pos
] = well_known_null_sid
;
820 has_def_class_perm
= true;
821 def_class_perm
= lacl
[pos
].a_perm
;
828 if (ace_sid
== owner_sid
)
833 else if (ace_sid
== group_sid
)
838 else if (ace_sid
== well_known_world_sid
)
841 id
= ACL_UNDEFINED_ID
;
842 if (ace
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
843 && !(ace
->Header
.AceFlags
& INHERIT_ONLY
))
844 saw_other_obj
= true;
846 else if (ace_sid
== well_known_creator_owner_sid
)
849 id
= ACL_UNDEFINED_ID
;
850 saw_def_user_obj
= true;
852 else if (ace_sid
== well_known_creator_group_sid
)
854 type
= DEF_GROUP_OBJ
;
855 id
= ACL_UNDEFINED_ID
;
856 saw_def_group_obj
= true;
860 id
= ace_sid
.get_id (TRUE
, &type
, &cldap
);
864 /* If the SGID attribute is set on a just created file or dir, the
865 first group in the ACL is the desired primary group of the new
866 object. Alternatively, the first repetition of the owner SID is
867 the desired primary group, and we mark the object as owner_eq_group
869 if (just_created
&& attr
& S_ISGID
&& !saw_group_obj
870 && (type
== GROUP
|| (type
== USER_OBJ
&& saw_user_obj
)))
873 lacl
[1].a_id
= gid
= id
;
874 if (type
== USER_OBJ
)
875 owner_eq_group
= true;
877 if (!(ace
->Header
.AceFlags
& INHERIT_ONLY
|| type
& ACL_DEFAULT
))
879 if (type
== USER_OBJ
)
881 /* If we get a second entry for the owner SID, it's either a
882 GROUP_OBJ entry for the same SID, if owner SID == group SID,
883 or it's an additional USER entry. The latter can happen
884 when chown'ing a file. */
887 if (owner_eq_group
&& !saw_group_obj
)
890 /* Gid and uid are not necessarily the same even if the
891 SID is the same: /etc/group is in use and the user got
892 added to /etc/group using another gid than the uid.
893 This is a border case but it happened and resetting id
894 to gid is not much of a burden. */
896 if (ace
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
)
897 saw_group_obj
= true;
902 else if (ace
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
)
905 else if (type
== GROUP_OBJ
)
907 /* Same for the primary group. */
908 if (ace
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
)
912 saw_group_obj
= true;
915 if ((pos
= searchace (lacl
, MAX_ACL_ENTRIES
, type
, id
)) >= 0)
917 getace (lacl
[pos
], type
, id
, ace
->Mask
, ace
->Header
.AceType
,
918 new_style
&& type
& (USER
| GROUP_OBJ
| GROUP
));
919 aclsid
[pos
] = ace_sid
;
922 /* Fix up CLASS_OBJ value. */
923 if (type
& (USER
| GROUP
))
925 has_class_perm
= true;
926 /* Accommodate Windows: Never add SYSTEM and Admins to
927 CLASS_OBJ. Unless (implicitly) if they are the
929 if (ace_sid
!= well_known_system_sid
930 && ace_sid
!= well_known_admins_sid
)
932 class_perm
|= lacl
[pos
].a_perm
;
933 standard_ACEs_only
= false;
937 /* For a newly created file, we'd like to know if we're running
938 with a standard ACL, one only consisting of POSIX perms, plus
939 SYSTEM and Admins as maximum non-POSIX perms entries. If it's
940 a standard ACL, we apply umask. That's not entirely correct,
941 but it's probably the best we can do. Chmod also wants to
942 know this. See there for the details. */
943 else if (type
& (USER
| GROUP
)
944 && standard_ACEs_only
945 && ace_sid
!= well_known_system_sid
946 && ace_sid
!= well_known_admins_sid
)
947 standard_ACEs_only
= false;
951 && (ace
->Header
.AceFlags
& SUB_CONTAINERS_AND_OBJECTS_INHERIT
) != 0)
953 if (type
== USER_OBJ
)
955 /* As above: If we get a second entry for the owner SID, it's
956 a GROUP_OBJ entry for the same SID if owner SID == group SID,
957 but this time only if the S_ISGID bit is set. Otherwise it's
958 an additional USER entry. */
959 if (saw_def_user_obj
)
961 if (owner_eq_group
&& !saw_def_group_obj
&& attr
& S_ISGID
)
963 /* Needs post-processing in the following GROUP_OBJ block.
964 Set id to ACL_UNDEFINED_ID to play it safe. */
966 id
= ACL_UNDEFINED_ID
;
971 else if (ace
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
)
972 saw_def_user_obj
= true;
974 if (type
== GROUP_OBJ
)
976 /* If the SGID bit is set, the inheritable entry for the
977 primary group is, in fact, the DEF_GROUP_OBJ entry,
978 so don't change the type to GROUP in this case. */
979 if (!new_style
|| saw_def_group_obj
|| !(attr
& S_ISGID
))
981 else if (ace
->Header
.AceType
== ACCESS_ALLOWED_ACE_TYPE
)
982 saw_def_group_obj
= true;
986 if ((pos
= searchace (lacl
, MAX_ACL_ENTRIES
, type
, id
)) >= 0)
988 getace (lacl
[pos
], type
, id
, ace
->Mask
, ace
->Header
.AceType
,
989 new_style
&& type
& (USER
| GROUP_OBJ
| GROUP
));
990 aclsid
[pos
] = ace_sid
;
993 /* Fix up DEF_CLASS_OBJ value. */
994 if (type
& (USER
| GROUP
))
996 has_def_class_perm
= true;
997 /* Accommodate Windows: Never add SYSTEM and Admins to
998 CLASS_OBJ. Unless (implicitly) if they are the
1000 if (ace_sid
!= well_known_system_sid
1001 && ace_sid
!= well_known_admins_sid
)
1002 def_class_perm
|= lacl
[pos
].a_perm
;
1004 /* And note the position of the DEF_GROUP_OBJ entry. */
1005 if (type
== DEF_GROUP_OBJ
)
1011 /* If this is a just created file, and this is an ACL with only standard
1012 entries, or if standard POSIX permissions are missing (probably no
1013 inherited ACEs so created from a default DACL), assign the permissions
1014 specified by the file creation mask. The values get masked by the
1015 actually requested permissions by the caller per POSIX 1003.1e draft 17. */
1018 mode_t perms
= (S_IRWXU
| S_IRWXG
| S_IRWXO
) & ~cygheap
->umask
;
1019 if (standard_ACEs_only
|| !saw_user_obj
)
1020 lacl
[0].a_perm
= (perms
>> 6) & S_IRWXO
;
1021 if (standard_ACEs_only
|| !saw_group_obj
)
1022 lacl
[1].a_perm
= (perms
>> 3) & S_IRWXO
;
1023 if (standard_ACEs_only
|| !saw_other_obj
)
1024 lacl
[2].a_perm
= perms
& S_IRWXO
;
1026 /* If this is an old-style or non-Cygwin ACL, and secondary user and group
1027 entries exist in the ACL, fake a matching CLASS_OBJ entry. The CLASS_OBJ
1028 permissions are the or'ed permissions of the primary group permissions
1029 and all secondary user and group permissions. */
1030 if (!new_style
&& has_class_perm
1031 && (pos
= searchace (lacl
, MAX_ACL_ENTRIES
, 0)) >= 0)
1033 lacl
[pos
].a_type
= CLASS_OBJ
;
1034 lacl
[pos
].a_id
= ACL_UNDEFINED_ID
;
1035 class_perm
|= lacl
[1].a_perm
;
1036 lacl
[pos
].a_perm
= class_perm
;
1037 aclsid
[pos
] = well_known_null_sid
;
1039 /* For ptys, fake a mask if the admins group is neither owner nor group.
1040 In that case we have an extra ACE for the admins group, and we need a
1041 CLASS_OBJ to get a valid POSIX ACL. However, Windows filters the ACE
1042 Mask value so it only reflects the bit values supported by the object
1043 type. The result is that we can't set an explicit CLASS_OBJ value for
1044 ptys in the NULL SID ACE. */
1045 else if (S_ISCHR (attr
) && owner_sid
!= well_known_admins_sid
1046 && group_sid
!= well_known_admins_sid
1047 && (pos
= searchace (lacl
, MAX_ACL_ENTRIES
, CLASS_OBJ
)) >= 0)
1049 lacl
[pos
].a_type
= CLASS_OBJ
;
1050 lacl
[pos
].a_id
= ACL_UNDEFINED_ID
;
1051 lacl
[pos
].a_perm
= lacl
[1].a_perm
; /* == group perms */
1052 aclsid
[pos
] = well_known_null_sid
;
1054 /* Ensure that the default acl contains at least
1055 DEF_(USER|GROUP|OTHER)_OBJ entries. */
1056 if (types_def
&& (pos
= searchace (lacl
, MAX_ACL_ENTRIES
, 0)) >= 0)
1058 if (!(types_def
& USER_OBJ
))
1060 lacl
[pos
].a_type
= DEF_USER_OBJ
;
1061 lacl
[pos
].a_id
= uid
;
1062 lacl
[pos
].a_perm
= lacl
[0].a_perm
;
1063 aclsid
[pos
] = well_known_creator_owner_sid
;
1066 if (!(types_def
& GROUP_OBJ
) && pos
< MAX_ACL_ENTRIES
)
1068 lacl
[pos
].a_type
= DEF_GROUP_OBJ
;
1069 lacl
[pos
].a_id
= gid
;
1070 lacl
[pos
].a_perm
= lacl
[1].a_perm
;
1071 /* Note the position of the DEF_GROUP_OBJ entry. */
1073 aclsid
[pos
] = well_known_creator_group_sid
;
1076 if (!(types_def
& OTHER_OBJ
) && pos
< MAX_ACL_ENTRIES
)
1078 lacl
[pos
].a_type
= DEF_OTHER_OBJ
;
1079 lacl
[pos
].a_id
= ACL_UNDEFINED_ID
;
1080 lacl
[pos
].a_perm
= lacl
[2].a_perm
;
1081 aclsid
[pos
] = well_known_world_sid
;
1085 /* If this is an old-style or non-Cygwin ACL, and secondary user default
1086 and group default entries exist in the ACL, fake a matching DEF_CLASS_OBJ
1087 entry. The DEF_CLASS_OBJ permissions are the or'ed permissions of the
1088 primary group default permissions and all secondary user and group def.
1090 if (!new_style
&& has_def_class_perm
1091 && (pos
= searchace (lacl
, MAX_ACL_ENTRIES
, 0)) >= 0)
1093 lacl
[pos
].a_type
= DEF_CLASS_OBJ
;
1094 lacl
[pos
].a_id
= ACL_UNDEFINED_ID
;
1095 lacl
[pos
].a_perm
= def_class_perm
;
1096 if (def_pgrp_pos
>= 0)
1097 lacl
[pos
].a_perm
|= lacl
[def_pgrp_pos
].a_perm
;
1098 aclsid
[pos
] = well_known_null_sid
;
1101 /* Make sure `pos' contains the number of used entries in lacl. */
1102 if ((pos
= searchace (lacl
, MAX_ACL_ENTRIES
, 0)) < 0)
1103 pos
= MAX_ACL_ENTRIES
;
1105 /* For old-style or non-Cygwin ACLs, check for merging permissions. */
1106 if (!just_created
&& !new_style
)
1107 for (idx
= 0; idx
< pos
; ++idx
)
1109 if (lacl
[idx
].a_type
& (USER_OBJ
| USER
)
1110 && !(lacl
[idx
].a_type
& ACL_DEFAULT
))
1114 /* Don't merge if the user already has all permissions, or... */
1115 if (lacl
[idx
].a_perm
== S_IRWXO
)
1117 /* ...if the sum of perms is less than or equal the user's perms. */
1118 perm
= lacl
[idx
].a_perm
1119 | (has_class_perm
? class_perm
: lacl
[1].a_perm
)
1121 if (perm
== lacl
[idx
].a_perm
)
1123 /* Otherwise, if we use the Windows user DB, utilize Authz to make
1124 sure all user permissions are correctly reflecting the Windows
1126 if (cygheap
->pg
.nss_pwd_db ()
1127 && authz_get_user_attribute (&perm
, psd
, aclsid
[idx
]))
1128 lacl
[idx
].a_perm
= perm
;
1129 /* Otherwise we only check the current user. If the user entry
1130 has a deny ACE, don't check. */
1131 else if (lacl
[idx
].a_id
== myself
->uid
1132 && !(lacl
[idx
].a_perm
& DENY_RWX
))
1134 /* Sum up all permissions of groups the user is member of, plus
1135 everyone perms, and merge them to user perms. */
1138 perm
= lacl
[2].a_perm
& S_IRWXO
;
1139 for (int gidx
= 1; gidx
< pos
; ++gidx
)
1140 if (lacl
[gidx
].a_type
& (GROUP_OBJ
| GROUP
)
1141 && CheckTokenMembership (cygheap
->user
.issetuid ()
1142 ? cygheap
->user
.imp_token () : NULL
,
1145 perm
|= lacl
[gidx
].a_perm
& S_IRWXO
;
1146 lacl
[idx
].a_perm
|= perm
;
1149 /* For all groups, if everyone has more permissions, add everyone
1150 perms to group perms. Skip groups with deny ACE. */
1151 else if (lacl
[idx
].a_type
& (GROUP_OBJ
| GROUP
)
1152 && !(lacl
[idx
].a_type
& ACL_DEFAULT
)
1153 && !(lacl
[idx
].a_perm
& DENY_RWX
))
1154 lacl
[idx
].a_perm
|= lacl
[2].a_perm
& S_IRWXO
;
1156 /* If owner SID == group SID (Microsoft Accounts) merge group perms into
1157 user perms but leave group perms intact. That's a fake, but it allows
1158 to keep track of the POSIX group perms without much effort. */
1160 lacl
[0].a_perm
|= lacl
[1].a_perm
;
1161 /* Construct POSIX permission bits. Fortunately we know exactly where
1162 to fetch the affecting bits from, at least as long as the array
1163 hasn't been sorted. */
1164 attr
|= (lacl
[0].a_perm
& S_IRWXO
) << 6;
1165 attr
|= ((has_class_perm
? class_perm
: lacl
[1].a_perm
) & S_IRWXO
) << 3;
1166 attr
|= (lacl
[2].a_perm
& S_IRWXO
);
1181 memcpy (aclbufp
, lacl
, pos
* sizeof (aclent_t
));
1182 for (idx
= 0; idx
< pos
; ++idx
)
1183 aclbufp
[idx
].a_perm
&= S_IRWXO
;
1184 aclsort (pos
, 0, aclbufp
);
1187 *std_acl
= standard_ACEs_only
;
1192 getacl (HANDLE handle
, path_conv
&pc
, int nentries
, aclent_t
*aclbufp
)
1194 security_descriptor sd
;
1195 mode_t attr
= pc
.isdir () ? S_IFDIR
: 0;
1197 if (get_file_sd (handle
, pc
, sd
, false))
1199 int pos
= get_posix_access (sd
, attr
, NULL
, NULL
, aclbufp
, nentries
);
1200 syscall_printf ("%R = getacl(%S)", pos
, pc
.get_nt_native_path ());
1205 acl (const char *path
, int cmd
, int nentries
, aclent_t
*aclbufp
)
1209 fhandler_base
*fh
= build_fh_name (path
, PC_SYM_FOLLOW
| PC_KEEP_HANDLE
,
1211 if (!fh
|| !fh
->exists ())
1213 else if (fh
->error ())
1215 debug_printf ("got %d error from build_fh_name", fh
->error ());
1216 set_errno (fh
->error ());
1219 res
= fh
->facl (cmd
, nentries
, aclbufp
);
1222 syscall_printf ("%R = acl(%s)", res
, path
);
1227 facl (int fd
, int cmd
, int nentries
, aclent_t
*aclbufp
)
1229 cygheap_fdget
cfd (fd
);
1232 syscall_printf ("-1 = facl (%d)", fd
);
1235 if (cfd
->get_flags () & O_PATH
)
1240 int res
= cfd
->facl (cmd
, nentries
, aclbufp
);
1241 syscall_printf ("%R = facl(%s) )", res
, cfd
->get_name ());
1246 __aclcheck (aclent_t
*aclbufp
, int nentries
, int *which
, bool posix
)
1248 bool has_user_obj
= false;
1249 bool has_group_obj
= false;
1250 bool has_other_obj
= false;
1251 bool has_class_obj
= false;
1252 bool has_ug_objs
= false;
1253 bool has_def_objs
= false;
1254 bool has_def_user_obj
= false;
1255 bool has_def_group_obj
= false;
1256 bool has_def_other_obj
= false;
1257 bool has_def_class_obj
= false;
1258 bool has_def_ug_objs
= false;
1261 for (int pos
= 0; pos
< nentries
; ++pos
)
1263 /* POSIX ACLs may contain deleted entries. Just ignore them. */
1264 if (posix
&& aclbufp
[pos
].a_type
== ACL_DELETED_TAG
)
1266 /* POSIX defines two sorts of ACLs, access and default, none of which
1267 is supposed to have the ACL_DEFAULT flag set. */
1268 if (posix
&& (aclbufp
[pos
].a_type
& ACL_DEFAULT
))
1274 switch (aclbufp
[pos
].a_type
)
1283 has_user_obj
= true;
1292 has_group_obj
= true;
1301 has_other_obj
= true;
1310 has_class_obj
= true;
1314 if ((pos2
= searchace (aclbufp
+ pos
+ 1, nentries
- pos
- 1,
1315 aclbufp
[pos
].a_type
, aclbufp
[pos
].a_id
)) >= 0)
1319 return DUPLICATE_ERROR
;
1324 if (has_def_user_obj
)
1330 has_def_objs
= has_def_user_obj
= true;
1333 if (has_def_group_obj
)
1339 has_def_objs
= has_def_group_obj
= true;
1342 if (has_def_other_obj
)
1348 has_def_objs
= has_def_other_obj
= true;
1351 if (has_def_class_obj
)
1357 has_def_objs
= has_def_class_obj
= true;
1361 if ((pos2
= searchace (aclbufp
+ pos
+ 1, nentries
- pos
- 1,
1362 aclbufp
[pos
].a_type
, aclbufp
[pos
].a_id
)) >= 0)
1366 return DUPLICATE_ERROR
;
1368 has_def_objs
= has_def_ug_objs
= true;
1379 || (has_ug_objs
&& !has_class_obj
))
1385 /* Check for missing default entries only on Solaris ACLs. */
1388 && !(has_def_user_obj
&& has_def_group_obj
&& has_def_other_obj
))
1389 || (has_def_ug_objs
&& !has_def_class_obj
)))
1399 aclcheck (aclent_t
*aclbufp
, int nentries
, int *which
)
1401 return __aclcheck (aclbufp
, nentries
, which
, false);
1404 /* For the sake of acl_calc_mask, return -1 if the ACL doesn't need a mask
1405 or if a mask entry already exists (__aclcalcmask sets the mask by itself).
1406 Otherwise return the mask value so acl_calc_mask can create a mask entry.
1407 This doesn't matter when called from aclsort. */
1409 __aclcalcmask (aclent_t
*aclbufp
, int nentries
)
1412 bool need_mask
= false;
1415 for (int idx
= 0; idx
< nentries
; ++idx
)
1416 switch (aclbufp
[idx
].a_type
)
1423 mask
|= aclbufp
[idx
].a_perm
;
1432 aclbufp
[mask_idx
].a_perm
= mask
;
1433 if (need_mask
&& mask_idx
== -1)
1435 return (acl_perm_t
) -1;
1439 acecmp (const void *a1
, const void *a2
)
1441 #define ace(i) ((const aclent_t *) a##i)
1442 int ret
= ace (1)->a_type
- ace (2)->a_type
;
1444 ret
= ace (1)->a_id
- ace (2)->a_id
;
1449 /* Sorts any acl. Called from sec_posixacl.cc. */
1451 __aclsort (int nentries
, aclent_t
*aclbufp
)
1453 if (!aclbufp
|| nentries
< 0)
1459 qsort ((void *) aclbufp
, nentries
, sizeof (aclent_t
), acecmp
);
1464 aclsort (int nentries
, int calclass
, aclent_t
*aclbufp
)
1466 if (!aclbufp
|| nentries
< MIN_ACL_ENTRIES
1467 || aclcheck (aclbufp
, nentries
, NULL
))
1472 qsort ((void *) aclbufp
, nentries
, sizeof (aclent_t
), acecmp
);
1474 __aclcalcmask (aclbufp
, nentries
);
1479 acltomode (aclent_t
*aclbufp
, int nentries
, mode_t
*modep
)
1483 if (!aclbufp
|| nentries
< 1 || !modep
)
1489 if ((pos
= searchace (aclbufp
, nentries
, USER_OBJ
)) < 0
1490 || !aclbufp
[pos
].a_type
)
1495 *modep
|= (aclbufp
[pos
].a_perm
& S_IRWXO
) << 6;
1496 if ((pos
= searchace (aclbufp
, nentries
, GROUP_OBJ
)) < 0
1497 || !aclbufp
[pos
].a_type
)
1502 *modep
|= (aclbufp
[pos
].a_perm
& S_IRWXO
) << 3;
1504 if ((cpos
= searchace (aclbufp
, nentries
, CLASS_OBJ
)) >= 0
1505 && aclbufp
[cpos
].a_type
== CLASS_OBJ
)
1506 *modep
|= ((aclbufp
[pos
].a_perm
& S_IRWXO
) & aclbufp
[cpos
].a_perm
) << 3;
1507 if ((pos
= searchace (aclbufp
, nentries
, OTHER_OBJ
)) < 0
1508 || !aclbufp
[pos
].a_type
)
1513 *modep
|= aclbufp
[pos
].a_perm
& S_IRWXO
;
1518 aclfrommode (aclent_t
*aclbufp
, int nentries
, mode_t
*modep
)
1522 if (!aclbufp
|| nentries
< 1 || !modep
)
1527 if ((pos
= searchace (aclbufp
, nentries
, USER_OBJ
)) < 0
1528 || !aclbufp
[pos
].a_type
)
1533 aclbufp
[pos
].a_perm
= (*modep
& S_IRWXU
) >> 6;
1534 if ((pos
= searchace (aclbufp
, nentries
, GROUP_OBJ
)) < 0
1535 || !aclbufp
[pos
].a_type
)
1540 aclbufp
[pos
].a_perm
= (*modep
& S_IRWXG
) >> 3;
1541 if ((pos
= searchace (aclbufp
, nentries
, CLASS_OBJ
)) >= 0
1542 && aclbufp
[pos
].a_type
== CLASS_OBJ
)
1543 aclbufp
[pos
].a_perm
= (*modep
& S_IRWXG
) >> 3;
1544 if ((pos
= searchace (aclbufp
, nentries
, OTHER_OBJ
)) < 0
1545 || !aclbufp
[pos
].a_type
)
1550 aclbufp
[pos
].a_perm
= (*modep
& S_IRWXO
);
1555 acltopbits (aclent_t
*aclbufp
, int nentries
, mode_t
*pbitsp
)
1557 return acltomode (aclbufp
, nentries
, pbitsp
);
1561 aclfrompbits (aclent_t
*aclbufp
, int nentries
, mode_t
*pbitsp
)
1563 return aclfrommode (aclbufp
, nentries
, pbitsp
);
1567 permtostr (char *bufp
, mode_t perm
)
1569 *bufp
++ = (perm
& S_IROTH
) ? 'r' : '-';
1570 *bufp
++ = (perm
& S_IWOTH
) ? 'w' : '-';
1571 *bufp
++ = (perm
& S_IXOTH
) ? 'x' : '-';
1575 #define _OPT(o) (options & (o))
1578 if (bufp + (l) >= buf + 2 * NT_MAX_PATH - 1) \
1580 set_errno (ENOMEM); \
1583 #define _CPY(s) ({ \
1584 const char *_s = (s); \
1585 _CHK (strlen (_s)); \
1586 bufp = stpcpy (bufp, _s); \
1590 bufp = permtostr (bufp, p); \
1593 #define _CMP(s) (!strncmp (bufp, acl_part[s].str, acl_part[s].len))
1601 static _acl_part acl_part_l
[] =
1610 static _acl_part acl_part_s
[] =
1629 __acltotext (aclent_t
*aclbufp
, int aclcnt
, const char *prefix
, char separator
,
1632 if (!aclbufp
|| aclcnt
< 0 || aclcnt
> MAX_ACL_ENTRIES
1633 || (aclcnt
> 0 && aclsort (aclcnt
, 0, aclbufp
)))
1640 char *buf
= tp
.t_get ();
1646 mode_t mask
= S_IRWXO
;
1647 mode_t def_mask
= S_IRWXO
;
1650 _acl_part
*acl_part
= _OPT (TEXT_ABBREVIATE
) ? acl_part_s
: acl_part_l
;
1653 /* If effective rights are requested, fetch mask values. */
1654 if (_OPT (TEXT_SOME_EFFECTIVE
| TEXT_ALL_EFFECTIVE
))
1656 if ((pos
= searchace (aclbufp
, aclcnt
, CLASS_OBJ
)) >= 0)
1657 mask
= aclbufp
[pos
].a_perm
;
1658 if ((pos
= searchace (aclbufp
, aclcnt
, DEF_CLASS_OBJ
)) >= 0)
1659 def_mask
= aclbufp
[pos
].a_perm
;
1661 for (pos
= 0; pos
< aclcnt
; ++pos
)
1666 *bufp
++ = separator
;
1669 /* Rememeber start position of entry to compute TEXT_SMART_INDENT tabs. */
1674 /* Solaris default acl? */
1675 if (!_OPT (TEXT_IS_POSIX
) && aclbufp
[pos
].a_type
& ACL_DEFAULT
)
1676 _CPY (acl_part
[default_s
].str
);
1678 switch (aclbufp
[pos
].a_type
& ~ACL_DEFAULT
)
1682 _CPY (acl_part
[user_s
].str
);
1686 _CPY (acl_part
[group_s
].str
);
1689 _CPY (acl_part
[mask_s
].str
);
1692 _CPY (acl_part
[other_s
].str
);
1696 switch (aclbufp
[pos
].a_type
& ~ACL_DEFAULT
)
1699 if (_OPT (TEXT_NUMERIC_IDS
)
1700 || !(pw
= internal_getpwuid (aclbufp
[pos
].a_id
, &cldap
)))
1703 bufp
+= __small_sprintf (bufp
, "%u:", aclbufp
[pos
].a_id
);
1707 _CHK (strlen (pw
->pw_name
+ 1));
1708 bufp
+= __small_sprintf (bufp
, "%s:", pw
->pw_name
);
1712 if (_OPT (TEXT_NUMERIC_IDS
)
1713 || !(gr
= internal_getgrgid (aclbufp
[pos
].a_id
, &cldap
)))
1716 bufp
+= __small_sprintf (bufp
, "%u:", aclbufp
[pos
].a_id
);
1720 _CHK (strlen (gr
->gr_name
));
1721 bufp
+= __small_sprintf (bufp
, "%s:", gr
->gr_name
);
1728 /* real permissions */
1729 _PTS (aclbufp
[pos
].a_perm
);
1730 if (!_OPT (TEXT_SOME_EFFECTIVE
| TEXT_ALL_EFFECTIVE
))
1732 /* effective permissions */
1733 switch (aclbufp
[pos
].a_type
)
1738 effective
= aclbufp
[pos
].a_perm
& mask
;
1743 effective
= aclbufp
[pos
].a_perm
& def_mask
;
1748 if (_OPT (TEXT_ALL_EFFECTIVE
) || effective
!= aclbufp
[pos
].a_perm
)
1750 if (_OPT (TEXT_SMART_INDENT
))
1752 int tabs
= 3 - (bufp
- entry_start
) / 8;
1760 _CPY ("\t#effective:");
1764 if (_OPT (TEXT_END_SEPARATOR
))
1767 *bufp
++ = separator
;
1770 return strdup (buf
);
1774 acltotext (aclent_t
*aclbufp
, int aclcnt
)
1776 return __acltotext (aclbufp
, aclcnt
, NULL
, ',', 0);
1780 permfromstr (char *perm
, bool posix_long
)
1787 else if (perm
[0] != '-')
1791 else if (perm
[1] != '-')
1795 else if (perm
[2] != '-')
1798 /* In posix long mode, only tabs up to a hash sign allowed. */
1800 while (perm
[idx
] == '\t')
1802 if (perm
[idx
] == '\0' || (posix_long
&& perm
[idx
] == '#'))
1808 __aclfromtext (const char *acltextp
, int *aclcnt
, bool posix
)
1810 if (!acltextp
|| strlen (acltextp
) >= 2 * NT_MAX_PATH
)
1818 _acl_part
*acl_part
;
1819 char *bufp
, *lasts
, *qualifier
;
1823 aclent_t
*lacl
= (aclent_t
*) tp
.c_get ();
1824 memset (lacl
, 0, MAX_ACL_ENTRIES
* sizeof (aclent_t
*));
1825 char *buf
= tp
.t_get ();
1826 stpcpy (buf
, acltextp
);
1830 /* Posix long or short form. Any \n in the string means long form. */
1831 if (strchr (buf
, '\n'))
1834 acl_part
= acl_part_l
;
1839 acl_part
= acl_part_s
;
1844 /* Solaris aclfromtext format. */
1846 acl_part
= acl_part_l
;
1849 for (bufp
= strtok_r (buf
, delim
, &lasts
);
1851 bufp
= strtok_r (NULL
, delim
, &lasts
))
1853 /* Handle default acl entries only for Solaris ACLs. */
1854 if (!posix
&& _CMP (default_s
))
1856 lacl
[pos
].a_type
|= ACL_DEFAULT
;
1857 bufp
+= acl_part
[default_s
].len
;
1859 lacl
[pos
].a_id
= ACL_UNDEFINED_ID
;
1860 for (acl_type
= user_s
; acl_type
< none_s
; ++acl_type
)
1861 if (_CMP (acl_type
))
1863 if (acl_type
== none_s
)
1868 bufp
+= acl_part
[acl_type
].len
;
1874 bufp
= strchrnul (bufp
, ':');
1876 /* No qualifier? USER_OBJ or GROUP_OBJ */
1879 lacl
[pos
].a_type
|= (acl_type
== user_s
) ? USER_OBJ
: GROUP_OBJ
;
1882 /* Some qualifier, USER or GROUP */
1883 lacl
[pos
].a_type
|= (acl_type
== user_s
) ? USER
: GROUP
;
1884 if (isdigit (*qualifier
))
1888 id_t id
= strtol (qualifier
, &ep
, 10);
1891 lacl
[pos
].a_id
= id
;
1895 if (acl_type
== user_s
)
1897 struct passwd
*pw
= internal_getpwnam (qualifier
, &cldap
);
1899 lacl
[pos
].a_id
= pw
->pw_uid
;
1903 struct group
*gr
= internal_getgrnam (qualifier
, &cldap
);
1905 lacl
[pos
].a_id
= gr
->gr_gid
;
1907 if (lacl
[pos
].a_id
== ACL_UNDEFINED_ID
)
1920 lacl
[pos
].a_type
|= (acl_type
== mask_s
) ? CLASS_OBJ
: OTHER_OBJ
;
1923 /* In posix long mode, the next char after the permissions may be a tab
1924 followed by effective permissions we can ignore here. */
1925 if ((lacl
[pos
].a_perm
= permfromstr (bufp
, *delim
== '\n')) == 01000)
1934 acl_t acl
= (acl_t
) acl_init (pos
);
1937 memcpy (acl
->entry
, lacl
, pos
* sizeof (aclent_t
));
1942 return (void *) acl
;
1946 aclent_t
*aclp
= (aclent_t
*) malloc (pos
* sizeof (aclent_t
));
1949 memcpy (aclp
, lacl
, pos
* sizeof (aclent_t
));
1953 return (void *) aclp
;
1957 extern "C" aclent_t
*
1958 aclfromtext (char *acltextp
, int *aclcnt
)
1960 return (aclent_t
*) __aclfromtext (acltextp
, aclcnt
, false);