Cygwin: strptime: add release note
[newlib-cygwin.git] / winsup / cygwin / sec / acl.cc
blobdb86f9e9e023dcb4ad461b9b5773c82f324e5c30
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
9 details. */
11 #include "winsup.h"
12 #include <stdlib.h>
13 #include <ctype.h>
14 #include "cygerrno.h"
15 #include "security.h"
16 #include "path.h"
17 #include "fhandler.h"
18 #include "dtable.h"
19 #include "cygheap.h"
20 #include "ntdll.h"
21 #include "tls_pbuf.h"
22 #include "sec_posixacl.h"
24 /* How does a correctly constructed new-style Windows ACL claiming to be a
25 POSIX ACL look like?
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)
42 - USER_OBJ allow ACE
43 - USER allow ACEs
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)
52 - GROUP_OBJ allow ACE
53 - GROUP allow ACEs
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)
62 - OTHER_OBJ allow ACE
64 Rinse and repeat for default ACEs with INHERIT flags set.
66 - Default NULL deny ACE (S_ISGID, CLASS_OBJ). */
68 /* POSIX <-> Win32 */
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
75 S_ISGID bit on. */
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) \
93 | CYG_ACE_MASK_VALID)
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 | \
99 FILE_READ_EA)
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)
115 int i;
117 for (i = 0; i < nentries; ++i)
118 if ((aclp[i].a_type == type
119 && (id == ACL_UNDEFINED_ID || aclp[i].a_id == id))
120 || !aclp[i].a_type)
121 return i;
122 return -1;
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! */
130 PSECURITY_DESCRIPTOR
131 set_posix_access (mode_t attr, uid_t uid, gid_t gid,
132 aclent_t *aclbufp, int nentries,
133 security_descriptor &sd_ret,
134 bool is_samba)
136 SECURITY_DESCRIPTOR sd;
137 cyg_ldap cldap;
138 PSID owner = NULL, group = NULL;
139 cygsid smb_owner, smb_group;
140 NTSTATUS status;
141 tmp_pathbuf tp;
142 cygpsid *aclsid;
143 PACL acl;
144 size_t acl_len = sizeof (ACL);
145 mode_t user_obj, group_obj, other_obj, deny;
146 mode_t class_obj = 0;
147 DWORD access;
148 int idx, start_idx, tmp_idx;
149 bool owner_eq_group = false;
150 bool dev_has_admins = false;
151 bool has_class_obj;
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
165 GROUP SIDs. */
166 if (is_samba)
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);
177 if (!owner)
178 owner = sidfromuid (uid, &cldap);
179 if (!group)
180 group = sidfromgid (gid, &cldap);
181 if (!owner || !group)
183 set_errno (EINVAL);
184 return NULL;
186 status = RtlSetOwnerSecurityDescriptor (&sd, owner, FALSE);
187 if (!NT_SUCCESS (status))
189 __seterrno_from_nt_status (status);
190 return NULL;
192 status = RtlSetGroupSecurityDescriptor (&sd, group, FALSE);
193 if (!NT_SUCCESS (status))
195 __seterrno_from_nt_status (status);
196 return NULL;
198 owner_eq_group = RtlEqualSid (owner, group);
199 if (S_ISCHR (attr))
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. */
204 if (!aclbufp)
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;
217 if (S_ISDIR (attr))
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)
237 case USER_OBJ:
238 aclsid[idx] = owner;
239 break;
240 case DEF_USER_OBJ:
241 aclsid[idx] = well_known_creator_owner_sid;
242 break;
243 case USER:
244 case DEF_USER:
245 aclsid[idx] = NO_SID;
246 if (is_samba)
248 uint32_t smb_uid;
249 cygsid *smb_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);
258 if (!aclsid[idx])
259 aclsid[idx] = sidfromuid (aclbufp[idx].a_id, &cldap);
260 break;
261 case GROUP_OBJ:
262 aclsid[idx] = group;
263 break;
264 case DEF_GROUP_OBJ:
265 aclsid[idx] = !(attr & S_ISGID) ? (PSID) well_known_creator_group_sid
266 : group;
267 break;
268 case GROUP:
269 case DEF_GROUP:
270 aclsid[idx] = NO_SID;
271 if (is_samba)
273 uint32_t smb_gid;
274 cygsid *smb_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);
283 if (!aclsid[idx])
284 aclsid[idx] = sidfromgid (aclbufp[idx].a_id, &cldap);
285 break;
286 case CLASS_OBJ:
287 case DEF_CLASS_OBJ:
288 aclsid[idx] = well_known_null_sid;
289 break;
290 case OTHER_OBJ:
291 case DEF_OTHER_OBJ:
292 aclsid[idx] = well_known_world_sid;
293 break;
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. */
302 idx = 0;
303 for (int def = 0; def <= ACL_DEFAULT; def += ACL_DEFAULT)
305 DWORD inherit = def ? SUB_CONTAINERS_AND_OBJECTS_INHERIT | INHERIT_ONLY
306 : NO_INHERITANCE;
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)
315 set_errno (EACCES);
316 return NULL;
318 break;
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? */
324 if (tmp_idx < 0)
325 break;
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);
344 if (tmp_idx < 0)
345 attr &= ~S_ISGID;
347 access = CYG_ACE_ISBITS_TO_WIN (def ? attr & S_ISGID : attr)
348 | CYG_ACE_NEW_STYLE;
349 tmp_idx = searchace (aclbufp, nentries, def | CLASS_OBJ);
350 if (tmp_idx >= 0)
352 has_class_obj = true;
353 class_obj = aclbufp[tmp_idx].a_perm;
354 access |= CYG_ACE_MASK_TO_WIN (class_obj);
356 else
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. */
372 if (!S_ISCHR (attr)
373 && (has_class_obj
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,
378 inherit))
379 return NULL;
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;
391 check_types <<= 2)
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;
398 ++idx)
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))
405 continue;
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);
420 else
421 deny = (aclbufp[idx].a_perm & ~class_obj);
422 if (!deny)
423 continue;
424 access = 0;
425 if (deny & S_IROTH)
426 access |= FILE_DENY_READ;
427 if (deny & S_IWOTH)
428 access |= (aclbufp[idx].a_type & USER_OBJ)
429 ? FILE_DENY_WRITE_OWNER : FILE_DENY_WRITE;
430 if (deny & S_IXOTH)
431 access |= FILE_DENY_EXEC;
432 if (!add_access_denied_ace (acl, access, aclsid[idx], acl_len,
433 inherit))
434 return NULL;
436 /* Create allow ACEs for users, then groups. */
437 for (idx = start_idx;
438 idx < nentries && aclbufp[idx].a_type & check_types;
439 ++idx)
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;
447 if (!is_samba)
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. */
461 if (S_ISDIR (attr)
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,
471 inherit))
472 return NULL;
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;
479 ++idx)
481 if (aclbufp[idx].a_type & GROUP && aclsid[idx] == group)
482 continue;
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))
488 deny = 0;
489 else
490 deny = (~aclbufp[idx].a_perm & other_obj);
491 if (!deny)
492 continue;
493 access = 0;
494 if (deny & S_IROTH)
495 access |= FILE_DENY_READ;
496 if (deny & S_IWOTH)
497 access |= FILE_DENY_WRITE;
498 if (deny & S_IXOTH)
499 access |= FILE_DENY_EXEC;
500 if (!add_access_denied_ace (acl, access, aclsid[idx], acl_len,
501 inherit))
502 return NULL;
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
510 | FILE_ALLOW_WRITE,
511 well_known_admins_sid, acl_len,
512 NO_INHERITANCE))
513 return NULL;
514 /* Create allow ACE for other. It's preceeded by class_obj if it exists.
515 If so, skip it. */
516 if (aclbufp[idx].a_type & CLASS_OBJ)
517 ++idx;
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. */
526 if (S_ISDIR (attr)
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,
531 inherit))
532 return NULL;
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);
543 return NULL;
545 /* Make self relative security descriptor in sd_ret. */
546 DWORD sd_size = 0;
547 RtlAbsoluteToSelfRelativeSD (&sd, sd_ret, &sd_size);
548 if (sd_size <= 0)
550 __seterrno ();
551 return NULL;
553 if (!sd_ret.realloc (sd_size))
555 set_errno (ENOMEM);
556 return NULL;
558 status = RtlAbsoluteToSelfRelativeSD (&sd, sd_ret, &sd_size);
559 if (!NT_SUCCESS (status))
561 __seterrno_from_nt_status (status);
562 return NULL;
564 debug_printf ("Created SD-Size: %u", sd_ret.size ());
565 return sd_ret;
568 /* This function *requires* a verified and sorted acl list! */
570 setacl (HANDLE handle, path_conv &pc, int nentries, aclent_t *aclbufp,
571 bool &writable)
573 security_descriptor sd, sd_ret;
574 mode_t attr = pc.isdir () ? S_IFDIR : 0;
575 uid_t uid;
576 gid_t gid;
578 if (get_file_sd (handle, pc, sd, false))
579 return -1;
580 if (get_posix_access (sd, attr, &uid, &gid, NULL, 0) < 0)
581 return -1;
582 if (!set_posix_access (attr, uid, gid, aclbufp, nentries,
583 sd_ret, pc.fs_is_samba ()))
584 return -1;
585 /* FIXME? Caller needs to know if any write perms are set to allow removing
586 the DOS R/O bit. */
587 writable = true;
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. */
601 static void
602 getace (aclent_t &acl, int type, int id, DWORD win_ace_mask,
603 DWORD win_ace_type, bool new_style)
605 acl.a_type = type;
606 acl.a_id = id;
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)
650 tmp_pathbuf tp;
651 NTSTATUS status;
652 BOOLEAN dummy, acl_exists;
653 SECURITY_DESCRIPTOR_CONTROL ctrl;
654 ULONG rev;
655 PACL acl;
656 PACCESS_ALLOWED_ACE ace;
657 cygpsid owner_sid, group_sid;
658 cyg_ldap cldap;
659 uid_t uid;
660 gid_t gid;
661 mode_t attr = 0;
662 aclent_t *lacl = NULL;
663 cygpsid ace_sid, *aclsid;
664 int pos, type, id, idx;
666 bool owner_eq_group;
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;
680 int types_def = 0;
681 int def_pgrp_pos = -1;
683 if (aclbufp && nentries < MIN_ACL_ENTRIES)
685 set_errno (EINVAL);
686 return -1;
688 /* If reading the security descriptor failed, treat the object as
689 unreadable. */
690 if (!psd)
692 attr_ret &= S_IFMT;
693 if (uid_ret)
694 *uid_ret = ACL_UNDEFINED_ID;
695 if (gid_ret)
696 *gid_ret = ACL_UNDEFINED_ID;
697 if (aclbufp)
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;
710 return 0;
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);
717 return -1;
719 status = RtlGetGroupSecurityDescriptor (psd, (PSID *) &group_sid, &dummy);
720 if (!NT_SUCCESS (status))
722 __seterrno_from_nt_status (status);
723 return -1;
725 status = RtlGetDaclSecurityDescriptor (psd, &acl_exists, &acl, &dummy);
726 if (!NT_SUCCESS (status))
728 __seterrno_from_nt_status (status);
729 return -1;
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;
743 lacl[0].a_id = uid;
744 lacl[1].a_type = GROUP_OBJ;
745 lacl[1].a_id = gid;
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;
759 goto out;
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! */
769 if (just_created
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)))
776 continue;
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. */
793 new_style = true;
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))
800 >= 0)
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;
810 if (S_ISDIR (attr)
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;
826 continue;
828 if (ace_sid == owner_sid)
830 type = USER_OBJ;
831 id = uid;
833 else if (ace_sid == group_sid)
835 type = GROUP_OBJ;
836 id = gid;
838 else if (ace_sid == well_known_world_sid)
840 type = OTHER_OBJ;
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)
848 type = DEF_USER_OBJ;
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;
858 else
860 id = ace_sid.get_id (TRUE, &type, &cldap);
861 if (!type)
862 continue;
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
868 object. */
869 if (just_created && attr & S_ISGID && !saw_group_obj
870 && (type == GROUP || (type == USER_OBJ && saw_user_obj)))
872 type = GROUP_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. */
885 if (saw_user_obj)
887 if (owner_eq_group && !saw_group_obj)
889 type = 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. */
895 id = gid;
896 if (ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
897 saw_group_obj = true;
899 else
900 type = USER;
902 else if (ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
903 saw_user_obj = true;
905 else if (type == GROUP_OBJ)
907 /* Same for the primary group. */
908 if (ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
910 if (saw_group_obj)
911 type = GROUP;
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;
920 if (!new_style)
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
928 GROUP_OBJ entry. */
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;
950 if (S_ISDIR (attr)
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. */
965 type = GROUP_OBJ;
966 id = ACL_UNDEFINED_ID;
968 else
969 type = USER;
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))
980 type = GROUP;
981 else if (ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
982 saw_def_group_obj = true;
984 type |= ACL_DEFAULT;
985 types_def |= type;
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;
991 if (!new_style)
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
999 GROUP_OBJ entry. */
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)
1006 def_pgrp_pos = pos;
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. */
1016 if (just_created)
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;
1064 pos++;
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. */
1072 def_pgrp_pos = pos;
1073 aclsid[pos] = well_known_creator_group_sid;
1074 pos++;
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;
1082 pos++;
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.
1089 permissions. */
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))
1112 mode_t perm;
1114 /* Don't merge if the user already has all permissions, or... */
1115 if (lacl[idx].a_perm == S_IRWXO)
1116 continue;
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)
1120 | lacl[2].a_perm;
1121 if (perm == lacl[idx].a_perm)
1122 continue;
1123 /* Otherwise, if we use the Windows user DB, utilize Authz to make
1124 sure all user permissions are correctly reflecting the Windows
1125 permissions. */
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. */
1136 BOOL ret;
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,
1143 aclsid[gidx], &ret)
1144 && ret)
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. */
1159 if (owner_eq_group)
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);
1168 out:
1169 if (uid_ret)
1170 *uid_ret = uid;
1171 if (gid_ret)
1172 *gid_ret = gid;
1173 attr_ret = attr;
1174 if (aclbufp)
1176 if (pos > nentries)
1178 set_errno (ENOSPC);
1179 return -1;
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);
1186 if (std_acl)
1187 *std_acl = standard_ACEs_only;
1188 return pos;
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))
1198 return -1;
1199 int pos = get_posix_access (sd, attr, NULL, NULL, aclbufp, nentries);
1200 syscall_printf ("%R = getacl(%S)", pos, pc.get_nt_native_path ());
1201 return pos;
1204 extern "C" int
1205 acl (const char *path, int cmd, int nentries, aclent_t *aclbufp)
1207 int res = -1;
1209 fhandler_base *fh = build_fh_name (path, PC_SYM_FOLLOW | PC_KEEP_HANDLE,
1210 stat_suffixes);
1211 if (!fh || !fh->exists ())
1212 set_errno (ENOENT);
1213 else if (fh->error ())
1215 debug_printf ("got %d error from build_fh_name", fh->error ());
1216 set_errno (fh->error ());
1218 else
1219 res = fh->facl (cmd, nentries, aclbufp);
1221 delete fh;
1222 syscall_printf ("%R = acl(%s)", res, path);
1223 return res;
1226 extern "C" int
1227 facl (int fd, int cmd, int nentries, aclent_t *aclbufp)
1229 cygheap_fdget cfd (fd);
1230 if (cfd < 0)
1232 syscall_printf ("-1 = facl (%d)", fd);
1233 return -1;
1235 if (cfd->get_flags () & O_PATH)
1237 set_errno (EBADF);
1238 return -1;
1240 int res = cfd->facl (cmd, nentries, aclbufp);
1241 syscall_printf ("%R = facl(%s) )", res, cfd->get_name ());
1242 return res;
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;
1259 int pos2;
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)
1265 continue;
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))
1270 if (which)
1271 *which = pos;
1272 return ENTRY_ERROR;
1274 switch (aclbufp[pos].a_type)
1276 case USER_OBJ:
1277 if (has_user_obj)
1279 if (which)
1280 *which = pos;
1281 return USER_ERROR;
1283 has_user_obj = true;
1284 break;
1285 case GROUP_OBJ:
1286 if (has_group_obj)
1288 if (which)
1289 *which = pos;
1290 return GRP_ERROR;
1292 has_group_obj = true;
1293 break;
1294 case OTHER_OBJ:
1295 if (has_other_obj)
1297 if (which)
1298 *which = pos;
1299 return OTHER_ERROR;
1301 has_other_obj = true;
1302 break;
1303 case CLASS_OBJ:
1304 if (has_class_obj)
1306 if (which)
1307 *which = pos;
1308 return CLASS_ERROR;
1310 has_class_obj = true;
1311 break;
1312 case USER:
1313 case GROUP:
1314 if ((pos2 = searchace (aclbufp + pos + 1, nentries - pos - 1,
1315 aclbufp[pos].a_type, aclbufp[pos].a_id)) >= 0)
1317 if (which)
1318 *which = pos2;
1319 return DUPLICATE_ERROR;
1321 has_ug_objs = true;
1322 break;
1323 case DEF_USER_OBJ:
1324 if (has_def_user_obj)
1326 if (which)
1327 *which = pos;
1328 return USER_ERROR;
1330 has_def_objs = has_def_user_obj = true;
1331 break;
1332 case DEF_GROUP_OBJ:
1333 if (has_def_group_obj)
1335 if (which)
1336 *which = pos;
1337 return GRP_ERROR;
1339 has_def_objs = has_def_group_obj = true;
1340 break;
1341 case DEF_OTHER_OBJ:
1342 if (has_def_other_obj)
1344 if (which)
1345 *which = pos;
1346 return OTHER_ERROR;
1348 has_def_objs = has_def_other_obj = true;
1349 break;
1350 case DEF_CLASS_OBJ:
1351 if (has_def_class_obj)
1353 if (which)
1354 *which = pos;
1355 return CLASS_ERROR;
1357 has_def_objs = has_def_class_obj = true;
1358 break;
1359 case DEF_USER:
1360 case DEF_GROUP:
1361 if ((pos2 = searchace (aclbufp + pos + 1, nentries - pos - 1,
1362 aclbufp[pos].a_type, aclbufp[pos].a_id)) >= 0)
1364 if (which)
1365 *which = pos2;
1366 return DUPLICATE_ERROR;
1368 has_def_objs = has_def_ug_objs = true;
1369 break;
1370 default:
1371 if (which)
1372 *which = pos;
1373 return ENTRY_ERROR;
1376 if (!has_user_obj
1377 || !has_group_obj
1378 || !has_other_obj
1379 || (has_ug_objs && !has_class_obj))
1381 if (which)
1382 *which = -1;
1383 return MISS_ERROR;
1385 /* Check for missing default entries only on Solaris ACLs. */
1386 if (!posix &&
1387 ((has_def_objs
1388 && !(has_def_user_obj && has_def_group_obj && has_def_other_obj))
1389 || (has_def_ug_objs && !has_def_class_obj)))
1391 if (which)
1392 *which = -1;
1393 return MISS_ERROR;
1395 return 0;
1398 extern "C" int
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. */
1408 mode_t
1409 __aclcalcmask (aclent_t *aclbufp, int nentries)
1411 mode_t mask = 0;
1412 bool need_mask = false;
1413 int mask_idx = -1;
1415 for (int idx = 0; idx < nentries; ++idx)
1416 switch (aclbufp[idx].a_type)
1418 case USER:
1419 case GROUP:
1420 need_mask = true;
1421 fallthrough;
1422 case GROUP_OBJ:
1423 mask |= aclbufp[idx].a_perm;
1424 break;
1425 case CLASS_OBJ:
1426 mask_idx = idx;
1427 break;
1428 default:
1429 break;
1431 if (mask_idx != -1)
1432 aclbufp[mask_idx].a_perm = mask;
1433 if (need_mask && mask_idx == -1)
1434 return mask;
1435 return (acl_perm_t) -1;
1438 static int
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;
1443 if (!ret)
1444 ret = ace (1)->a_id - ace (2)->a_id;
1445 return ret;
1446 #undef ace
1449 /* Sorts any acl. Called from sec_posixacl.cc. */
1451 __aclsort (int nentries, aclent_t *aclbufp)
1453 if (!aclbufp || nentries < 0)
1455 set_errno (EINVAL);
1456 return -1;
1458 if (nentries > 0)
1459 qsort ((void *) aclbufp, nentries, sizeof (aclent_t), acecmp);
1460 return 0;
1463 extern "C" int
1464 aclsort (int nentries, int calclass, aclent_t *aclbufp)
1466 if (!aclbufp || nentries < MIN_ACL_ENTRIES
1467 || aclcheck (aclbufp, nentries, NULL))
1469 set_errno (EINVAL);
1470 return -1;
1472 qsort ((void *) aclbufp, nentries, sizeof (aclent_t), acecmp);
1473 if (calclass)
1474 __aclcalcmask (aclbufp, nentries);
1475 return 0;
1478 extern "C" int
1479 acltomode (aclent_t *aclbufp, int nentries, mode_t *modep)
1481 int pos;
1483 if (!aclbufp || nentries < 1 || !modep)
1485 set_errno (EINVAL);
1486 return -1;
1488 *modep = 0;
1489 if ((pos = searchace (aclbufp, nentries, USER_OBJ)) < 0
1490 || !aclbufp[pos].a_type)
1492 set_errno (EINVAL);
1493 return -1;
1495 *modep |= (aclbufp[pos].a_perm & S_IRWXO) << 6;
1496 if ((pos = searchace (aclbufp, nentries, GROUP_OBJ)) < 0
1497 || !aclbufp[pos].a_type)
1499 set_errno (EINVAL);
1500 return -1;
1502 *modep |= (aclbufp[pos].a_perm & S_IRWXO) << 3;
1503 int cpos;
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)
1510 set_errno (EINVAL);
1511 return -1;
1513 *modep |= aclbufp[pos].a_perm & S_IRWXO;
1514 return 0;
1517 extern "C" int
1518 aclfrommode (aclent_t *aclbufp, int nentries, mode_t *modep)
1520 int pos;
1522 if (!aclbufp || nentries < 1 || !modep)
1524 set_errno (EINVAL);
1525 return -1;
1527 if ((pos = searchace (aclbufp, nentries, USER_OBJ)) < 0
1528 || !aclbufp[pos].a_type)
1530 set_errno (EINVAL);
1531 return -1;
1533 aclbufp[pos].a_perm = (*modep & S_IRWXU) >> 6;
1534 if ((pos = searchace (aclbufp, nentries, GROUP_OBJ)) < 0
1535 || !aclbufp[pos].a_type)
1537 set_errno (EINVAL);
1538 return -1;
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)
1547 set_errno (EINVAL);
1548 return -1;
1550 aclbufp[pos].a_perm = (*modep & S_IRWXO);
1551 return 0;
1554 extern "C" int
1555 acltopbits (aclent_t *aclbufp, int nentries, mode_t *pbitsp)
1557 return acltomode (aclbufp, nentries, pbitsp);
1560 extern "C" int
1561 aclfrompbits (aclent_t *aclbufp, int nentries, mode_t *pbitsp)
1563 return aclfrommode (aclbufp, nentries, pbitsp);
1566 static char *
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' : '-';
1572 return bufp;
1575 #define _OPT(o) (options & (o))
1577 #define _CHK(l) \
1578 if (bufp + (l) >= buf + 2 * NT_MAX_PATH - 1) \
1580 set_errno (ENOMEM); \
1581 return NULL; \
1583 #define _CPY(s) ({ \
1584 const char *_s = (s); \
1585 _CHK (strlen (_s)); \
1586 bufp = stpcpy (bufp, _s); \
1588 #define _PTS(p) { \
1589 _CHK (3); \
1590 bufp = permtostr (bufp, p); \
1593 #define _CMP(s) (!strncmp (bufp, acl_part[s].str, acl_part[s].len))
1595 struct _acl_part
1597 const char *str;
1598 size_t len;
1601 static _acl_part acl_part_l[] =
1603 { "default:", 8 },
1604 { "user:", 5 },
1605 { "group:", 6 },
1606 { "mask:", 5 },
1607 { "other:", 6 }
1610 static _acl_part acl_part_s[] =
1612 { "d:", 2 },
1613 { "u:", 2 },
1614 { "g:", 2 },
1615 { "m:", 2 },
1616 { "o:", 2 }
1619 enum _acl_type {
1620 default_s,
1621 user_s,
1622 group_s,
1623 mask_s,
1624 other_s,
1625 none_s
1628 char *
1629 __acltotext (aclent_t *aclbufp, int aclcnt, const char *prefix, char separator,
1630 int options)
1632 if (!aclbufp || aclcnt < 0 || aclcnt > MAX_ACL_ENTRIES
1633 || (aclcnt > 0 && aclsort (aclcnt, 0, aclbufp)))
1635 set_errno (EINVAL);
1636 return NULL;
1638 cyg_ldap cldap;
1639 tmp_pathbuf tp;
1640 char *buf = tp.t_get ();
1641 char *bufp = buf;
1642 char *entry_start;
1643 bool first = true;
1644 struct passwd *pw;
1645 struct group *gr;
1646 mode_t mask = S_IRWXO;
1647 mode_t def_mask = S_IRWXO;
1648 mode_t effective;
1649 int pos;
1650 _acl_part *acl_part = _OPT (TEXT_ABBREVIATE) ? acl_part_s : acl_part_l;
1652 *bufp = '\0';
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)
1663 if (!first)
1665 _CHK (1);
1666 *bufp++ = separator;
1668 first = false;
1669 /* Rememeber start position of entry to compute TEXT_SMART_INDENT tabs. */
1670 entry_start = bufp;
1671 /* prefix */
1672 if (prefix)
1673 _CPY (prefix);
1674 /* Solaris default acl? */
1675 if (!_OPT (TEXT_IS_POSIX) && aclbufp[pos].a_type & ACL_DEFAULT)
1676 _CPY (acl_part[default_s].str);
1677 /* acl type */
1678 switch (aclbufp[pos].a_type & ~ACL_DEFAULT)
1680 case USER_OBJ:
1681 case USER:
1682 _CPY (acl_part[user_s].str);
1683 break;
1684 case GROUP_OBJ:
1685 case GROUP:
1686 _CPY (acl_part[group_s].str);
1687 break;
1688 case CLASS_OBJ:
1689 _CPY (acl_part[mask_s].str);
1690 break;
1691 case OTHER_OBJ:
1692 _CPY (acl_part[other_s].str);
1693 break;
1695 /* id, if any */
1696 switch (aclbufp[pos].a_type & ~ACL_DEFAULT)
1698 case USER:
1699 if (_OPT (TEXT_NUMERIC_IDS)
1700 || !(pw = internal_getpwuid (aclbufp[pos].a_id, &cldap)))
1702 _CHK (11);
1703 bufp += __small_sprintf (bufp, "%u:", aclbufp[pos].a_id);
1705 else
1707 _CHK (strlen (pw->pw_name + 1));
1708 bufp += __small_sprintf (bufp, "%s:", pw->pw_name);
1710 break;
1711 case GROUP:
1712 if (_OPT (TEXT_NUMERIC_IDS)
1713 || !(gr = internal_getgrgid (aclbufp[pos].a_id, &cldap)))
1715 _CHK (11);
1716 bufp += __small_sprintf (bufp, "%u:", aclbufp[pos].a_id);
1718 else
1720 _CHK (strlen (gr->gr_name));
1721 bufp += __small_sprintf (bufp, "%s:", gr->gr_name);
1723 break;
1724 default:
1725 _CPY (":");
1726 break;
1728 /* real permissions */
1729 _PTS (aclbufp[pos].a_perm);
1730 if (!_OPT (TEXT_SOME_EFFECTIVE | TEXT_ALL_EFFECTIVE))
1731 continue;
1732 /* effective permissions */
1733 switch (aclbufp[pos].a_type)
1735 case USER:
1736 case GROUP_OBJ:
1737 case GROUP:
1738 effective = aclbufp[pos].a_perm & mask;
1739 break;
1740 case DEF_USER:
1741 case DEF_GROUP_OBJ:
1742 case DEF_GROUP:
1743 effective = aclbufp[pos].a_perm & def_mask;
1744 break;
1745 default:
1746 continue;
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;
1753 if (tabs-- > 0)
1755 _CHK (tabs);
1756 while (tabs-- > 0)
1757 *bufp++ = '\t';
1760 _CPY ("\t#effective:");
1761 _PTS (effective);
1764 if (_OPT (TEXT_END_SEPARATOR))
1766 _CHK (1);
1767 *bufp++ = separator;
1769 *bufp = '\0';
1770 return strdup (buf);
1773 extern "C" char *
1774 acltotext (aclent_t *aclbufp, int aclcnt)
1776 return __acltotext (aclbufp, aclcnt, NULL, ',', 0);
1779 static mode_t
1780 permfromstr (char *perm, bool posix_long)
1782 mode_t mode = 0;
1783 int idx;
1785 if (perm[0] == 'r')
1786 mode |= S_IROTH;
1787 else if (perm[0] != '-')
1788 return 01000;
1789 if (perm[1] == 'w')
1790 mode |= S_IWOTH;
1791 else if (perm[1] != '-')
1792 return 01000;
1793 if (perm[2] == 'x')
1794 mode |= S_IXOTH;
1795 else if (perm[2] != '-')
1796 return 01000;
1797 idx = 3;
1798 /* In posix long mode, only tabs up to a hash sign allowed. */
1799 if (posix_long)
1800 while (perm[idx] == '\t')
1801 ++idx;
1802 if (perm[idx] == '\0' || (posix_long && perm[idx] == '#'))
1803 return mode;
1804 return 01000;
1807 void *
1808 __aclfromtext (const char *acltextp, int *aclcnt, bool posix)
1810 if (!acltextp || strlen (acltextp) >= 2 * NT_MAX_PATH)
1812 set_errno (EINVAL);
1813 return NULL;
1815 cyg_ldap cldap;
1816 tmp_pathbuf tp;
1817 const char *delim;
1818 _acl_part *acl_part;
1819 char *bufp, *lasts, *qualifier;
1820 int pos = 0;
1821 int acl_type;
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);
1828 if (posix)
1830 /* Posix long or short form. Any \n in the string means long form. */
1831 if (strchr (buf, '\n'))
1833 delim = "\n";
1834 acl_part = acl_part_l;
1836 else
1838 delim = ",";
1839 acl_part = acl_part_s;
1842 else
1844 /* Solaris aclfromtext format. */
1845 delim = ",";
1846 acl_part = acl_part_l;
1849 for (bufp = strtok_r (buf, delim, &lasts);
1850 bufp;
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))
1862 break;
1863 if (acl_type == none_s)
1865 set_errno (EINVAL);
1866 return NULL;
1868 bufp += acl_part[acl_type].len;
1869 switch (acl_type)
1871 case user_s:
1872 case group_s:
1873 qualifier = bufp;
1874 bufp = strchrnul (bufp, ':');
1875 *bufp++ = '\0';
1876 /* No qualifier? USER_OBJ or GROUP_OBJ */
1877 if (!*qualifier)
1879 lacl[pos].a_type |= (acl_type == user_s) ? USER_OBJ : GROUP_OBJ;
1880 break;
1882 /* Some qualifier, USER or GROUP */
1883 lacl[pos].a_type |= (acl_type == user_s) ? USER : GROUP;
1884 if (isdigit (*qualifier))
1886 char *ep;
1888 id_t id = strtol (qualifier, &ep, 10);
1889 if (*ep == '\0')
1891 lacl[pos].a_id = id;
1892 break;
1895 if (acl_type == user_s)
1897 struct passwd *pw = internal_getpwnam (qualifier, &cldap);
1898 if (pw)
1899 lacl[pos].a_id = pw->pw_uid;
1901 else
1903 struct group *gr = internal_getgrnam (qualifier, &cldap);
1904 if (gr)
1905 lacl[pos].a_id = gr->gr_gid;
1907 if (lacl[pos].a_id == ACL_UNDEFINED_ID)
1909 set_errno (EINVAL);
1910 return NULL;
1912 break;
1913 case mask_s:
1914 case other_s:
1915 if (*bufp++ != ':')
1917 set_errno (EINVAL);
1918 return NULL;
1920 lacl[pos].a_type |= (acl_type == mask_s) ? CLASS_OBJ : OTHER_OBJ;
1921 break;
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)
1927 set_errno (EINVAL);
1928 return NULL;
1930 ++pos;
1932 if (posix)
1934 acl_t acl = (acl_t) acl_init (pos);
1935 if (acl)
1937 memcpy (acl->entry, lacl, pos * sizeof (aclent_t));
1938 acl->count = pos;
1939 if (aclcnt)
1940 *aclcnt = pos;
1942 return (void *) acl;
1944 else
1946 aclent_t *aclp = (aclent_t *) malloc (pos * sizeof (aclent_t));
1947 if (aclp)
1949 memcpy (aclp, lacl, pos * sizeof (aclent_t));
1950 if (aclcnt)
1951 *aclcnt = pos;
1953 return (void *) aclp;
1957 extern "C" aclent_t *
1958 aclfromtext (char *acltextp, int *aclcnt)
1960 return (aclent_t *) __aclfromtext (acltextp, aclcnt, false);