1 /* sec_acl.cc: Sun compatible ACL functions.
3 Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc.
5 Written by Corinna Vinschen <corinna@vinschen.de>
7 This file is part of Cygwin.
9 This software is a copyrighted work licensed under the terms of the
10 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
26 searchace (__aclent32_t *aclp, int nentries, int type, __uid32_t id = ILLEGAL_UID)
30 for (i = 0; i < nentries; ++i)
31 if ((aclp[i].a_type == type && (id == ILLEGAL_UID || aclp[i].a_id == id))
38 setacl (HANDLE handle, path_conv &pc, int nentries, __aclent32_t *aclbufp,
41 security_descriptor sd_ret;
43 if (get_file_sd (handle, pc, sd_ret))
50 if (!GetSecurityDescriptorOwner (sd_ret, &owner_sid, &dummy))
55 cygsid owner (owner_sid);
59 if (!GetSecurityDescriptorGroup (sd_ret, &group_sid, &dummy))
64 cygsid group (group_sid);
66 /* Initialize local security descriptor. */
67 SECURITY_DESCRIPTOR sd;
68 if (!InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION))
73 if (!SetSecurityDescriptorOwner (&sd, owner, FALSE))
78 if (!SetSecurityDescriptorGroup (&sd, group, FALSE))
84 /* Fill access control list. */
85 PACL acl = (PACL) alloca (3072);
86 size_t acl_len = sizeof (ACL);
94 if (!InitializeAcl (acl, 3072, ACL_REVISION))
102 for (int i = 0; i < nentries; ++i)
105 /* Owner has more standard rights set. */
106 if ((aclbufp[i].a_type & ~ACL_DEFAULT) == USER_OBJ)
107 allow = STANDARD_RIGHTS_ALL
109 ? 0 : (FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES));
111 allow = STANDARD_RIGHTS_READ
112 | (pc.fs_is_samba () ? 0 : FILE_READ_ATTRIBUTES);
113 if (aclbufp[i].a_perm & S_IROTH)
114 allow |= FILE_GENERIC_READ;
115 if (aclbufp[i].a_perm & S_IWOTH)
117 allow |= FILE_GENERIC_WRITE;
120 if (aclbufp[i].a_perm & S_IXOTH)
121 allow |= FILE_GENERIC_EXECUTE & ~FILE_READ_ATTRIBUTES;
122 if ((aclbufp[i].a_perm & (S_IWOTH | S_IXOTH)) == (S_IWOTH | S_IXOTH))
123 allow |= FILE_DELETE_CHILD;
124 /* Set inherit property. */
125 DWORD inheritance = (aclbufp[i].a_type & ACL_DEFAULT)
126 ? (SUB_CONTAINERS_AND_OBJECTS_INHERIT | INHERIT_ONLY)
129 * If a specific acl contains a corresponding default entry with
130 * identical permissions, only one Windows ACE with proper
131 * inheritance bits is created.
133 if (!(aclbufp[i].a_type & ACL_DEFAULT)
134 && aclbufp[i].a_type & (USER|GROUP|OTHER_OBJ)
135 && (pos = searchace (aclbufp + i + 1, nentries - i - 1,
136 aclbufp[i].a_type | ACL_DEFAULT,
137 (aclbufp[i].a_type & (USER|GROUP))
138 ? aclbufp[i].a_id : ILLEGAL_UID)) >= 0
139 && aclbufp[i].a_perm == aclbufp[i + 1 + pos].a_perm)
141 inheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
142 /* This invalidates the corresponding default entry. */
143 aclbufp[i + 1 + pos].a_type = USER|GROUP|ACL_DEFAULT;
145 switch (aclbufp[i].a_type)
148 if (!add_access_allowed_ace (acl, ace_off++, allow,
149 owner, acl_len, inheritance))
153 if (!add_access_allowed_ace (acl, ace_off++, allow,
154 well_known_creator_owner_sid, acl_len, inheritance))
159 if (!(pw = internal_getpwuid (aclbufp[i].a_id))
160 || !sid.getfrompw (pw))
165 if (!add_access_allowed_ace (acl, ace_off++, allow,
166 sid, acl_len, inheritance))
170 if (!add_access_allowed_ace (acl, ace_off++, allow,
171 group, acl_len, inheritance))
175 if (!add_access_allowed_ace (acl, ace_off++, allow,
176 well_known_creator_group_sid, acl_len, inheritance))
181 if (!(gr = internal_getgrgid (aclbufp[i].a_id))
182 || !sid.getfromgr (gr))
187 if (!add_access_allowed_ace (acl, ace_off++, allow,
188 sid, acl_len, inheritance))
193 if (!add_access_allowed_ace (acl, ace_off++, allow,
194 well_known_world_sid,
195 acl_len, inheritance))
200 /* Set AclSize to computed value. */
201 acl->AclSize = acl_len;
202 debug_printf ("ACL-Size: %d", acl_len);
203 /* Create DACL for local security descriptor. */
204 if (!SetSecurityDescriptorDacl (&sd, TRUE, acl, FALSE))
209 /* Make self relative security descriptor in sd_ret. */
211 MakeSelfRelativeSD (&sd, sd_ret, &sd_size);
217 if (!sd_ret.realloc (sd_size))
222 if (!MakeSelfRelativeSD (&sd, sd_ret, &sd_size))
227 debug_printf ("Created SD-Size: %d", sd_ret.size ());
228 return set_file_sd (handle, pc, sd_ret, false);
231 /* Temporary access denied bits */
232 #define DENY_R 040000
233 #define DENY_W 020000
234 #define DENY_X 010000
237 getace (__aclent32_t &acl, int type, int id, DWORD win_ace_mask,
243 if ((win_ace_mask & FILE_READ_BITS) && !(acl.a_perm & (S_IROTH | DENY_R)))
245 if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE)
246 acl.a_perm |= S_IROTH;
247 else if (win_ace_type == ACCESS_DENIED_ACE_TYPE)
248 acl.a_perm |= DENY_R;
251 if ((win_ace_mask & FILE_WRITE_BITS) && !(acl.a_perm & (S_IWOTH | DENY_W)))
253 if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE)
254 acl.a_perm |= S_IWOTH;
255 else if (win_ace_type == ACCESS_DENIED_ACE_TYPE)
256 acl.a_perm |= DENY_W;
259 if ((win_ace_mask & FILE_EXEC_BITS) && !(acl.a_perm & (S_IXOTH | DENY_X)))
261 if (win_ace_type == ACCESS_ALLOWED_ACE_TYPE)
262 acl.a_perm |= S_IXOTH;
263 else if (win_ace_type == ACCESS_DENIED_ACE_TYPE)
264 acl.a_perm |= DENY_X;
269 getacl (HANDLE handle, path_conv &pc, int nentries, __aclent32_t *aclbufp)
271 security_descriptor sd;
273 if (get_file_sd (handle, pc, sd))
282 if (!GetSecurityDescriptorOwner (sd, (PSID *) &owner_sid, &dummy))
284 debug_printf ("GetSecurityDescriptorOwner %E");
288 uid = owner_sid.get_uid ();
290 if (!GetSecurityDescriptorGroup (sd, (PSID *) &group_sid, &dummy))
292 debug_printf ("GetSecurityDescriptorGroup %E");
296 gid = group_sid.get_gid ();
298 __aclent32_t lacl[MAX_ACL_ENTRIES];
299 memset (&lacl, 0, MAX_ACL_ENTRIES * sizeof (__aclent32_t));
300 lacl[0].a_type = USER_OBJ;
302 lacl[1].a_type = GROUP_OBJ;
304 lacl[2].a_type = OTHER_OBJ;
305 lacl[2].a_id = ILLEGAL_GID;
306 lacl[3].a_type = CLASS_OBJ;
307 lacl[3].a_id = ILLEGAL_GID;
308 lacl[3].a_perm = S_IROTH | S_IWOTH | S_IXOTH;
313 if (!GetSecurityDescriptorDacl (sd, &acl_exists, &acl, &dummy))
316 debug_printf ("GetSecurityDescriptorDacl %E");
320 int pos, i, types_def = 0;
322 if (!acl_exists || !acl)
323 for (pos = 0; pos < 3; ++pos) /* Don't change CLASS_OBJ entry */
324 lacl[pos].a_perm = S_IROTH | S_IWOTH | S_IXOTH;
327 for (i = 0; i < acl->AceCount; ++i)
329 ACCESS_ALLOWED_ACE *ace;
331 if (!GetAce (acl, i, (PVOID *) &ace))
334 cygpsid ace_sid ((PSID) &ace->SidStart);
338 if (ace_sid == well_known_world_sid)
343 else if (ace_sid == group_sid)
348 else if (ace_sid == owner_sid)
353 else if (ace_sid == well_known_creator_group_sid)
355 type = GROUP_OBJ | ACL_DEFAULT;
358 else if (ace_sid == well_known_creator_owner_sid)
360 type = USER_OBJ | ACL_DEFAULT;
364 id = ace_sid.get_id (true, &type);
368 if (!(ace->Header.AceFlags & INHERIT_ONLY || type & ACL_DEFAULT))
370 if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0)
371 getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType);
373 if ((ace->Header.AceFlags & SUB_CONTAINERS_AND_OBJECTS_INHERIT)
376 if (type == USER_OBJ)
378 else if (type == GROUP_OBJ)
382 if ((pos = searchace (lacl, MAX_ACL_ENTRIES, type, id)) >= 0)
383 getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType);
386 /* Include DEF_CLASS_OBJ if any default ace exists */
387 if ((types_def & (USER|GROUP))
388 && ((pos = searchace (lacl, MAX_ACL_ENTRIES, DEF_CLASS_OBJ)) >= 0))
390 lacl[pos].a_type = DEF_CLASS_OBJ;
391 lacl[pos].a_id = ILLEGAL_GID;
392 lacl[pos].a_perm = S_IRWXU | S_IRWXG | S_IRWXO;
395 if ((pos = searchace (lacl, MAX_ACL_ENTRIES, 0)) < 0)
396 pos = MAX_ACL_ENTRIES;
398 if (owner_sid == group_sid)
399 lacl[0].a_perm = lacl[1].a_perm;
405 memcpy (aclbufp, lacl, pos * sizeof (__aclent32_t));
406 for (i = 0; i < pos; ++i)
407 aclbufp[i].a_perm &= ~(DENY_R | DENY_W | DENY_X);
408 aclsort32 (pos, 0, aclbufp);
410 syscall_printf ("%d = getacl (%S)", pos, pc.get_nt_native_path ());
415 acl_worker (const char *path, int cmd, int nentries, __aclent32_t *aclbufp,
419 fhandler_base *fh = build_fh_name (path, NULL, fmode, stat_suffixes);
422 debug_printf ("got %d error from build_fh_name", fh->error ());
423 set_errno (fh->error ());
425 else if (!fh->exists ())
428 res = fh->facl (cmd, nentries, aclbufp);
431 syscall_printf ("%d = acl (%s)", res, path);
436 acl32 (const char *path, int cmd, int nentries, __aclent32_t *aclbufp)
438 return acl_worker (path, cmd, nentries, aclbufp, PC_SYM_FOLLOW);
442 lacl32 (const char *path, int cmd, int nentries, __aclent32_t *aclbufp)
444 return acl_worker (path, cmd, nentries, aclbufp, PC_SYM_NOFOLLOW);
448 facl32 (int fd, int cmd, int nentries, __aclent32_t *aclbufp)
450 cygheap_fdget cfd (fd);
453 syscall_printf ("-1 = facl (%d)", fd);
456 int res = cfd->facl (cmd, nentries, aclbufp);
457 syscall_printf ("%d = facl (%s) )", res, cfd->get_name ());
462 aclcheck32 (__aclent32_t *aclbufp, int nentries, int *which)
464 bool has_user_obj = false;
465 bool has_group_obj = false;
466 bool has_other_obj = false;
467 bool has_class_obj = false;
468 bool has_ug_objs = false;
469 bool has_def_user_obj = false;
470 bool has_def_group_obj = false;
471 bool has_def_other_obj = false;
472 bool has_def_class_obj = false;
473 bool has_def_ug_objs = false;
476 for (int pos = 0; pos < nentries; ++pos)
477 switch (aclbufp[pos].a_type)
495 has_group_obj = true;
504 has_other_obj = true;
513 has_class_obj = true;
517 if ((pos2 = searchace (aclbufp + pos + 1, nentries - pos - 1,
518 aclbufp[pos].a_type, aclbufp[pos].a_id)) >= 0)
522 return DUPLICATE_ERROR;
527 if (has_def_user_obj)
533 has_def_user_obj = true;
536 if (has_def_group_obj)
542 has_def_group_obj = true;
545 if (has_def_other_obj)
551 has_def_other_obj = true;
554 if (has_def_class_obj)
560 has_def_class_obj = true;
564 if ((pos2 = searchace (aclbufp + pos + 1, nentries - pos - 1,
565 aclbufp[pos].a_type, aclbufp[pos].a_id)) >= 0)
569 return DUPLICATE_ERROR;
571 has_def_ug_objs = true;
580 /* These checks are not ok yet since CLASS_OBJ isn't fully implemented. */
581 || (has_ug_objs && !has_class_obj)
582 || (has_def_ug_objs && !has_def_class_obj)
594 acecmp (const void *a1, const void *a2)
596 #define ace(i) ((const __aclent32_t *) a##i)
597 int ret = ace (1)->a_type - ace (2)->a_type;
599 ret = ace (1)->a_id - ace (2)->a_id;
605 aclsort32 (int nentries, int, __aclent32_t *aclbufp)
607 if (aclcheck32 (aclbufp, nentries, NULL))
609 if (!aclbufp || nentries < 1)
614 qsort ((void *) aclbufp, nentries, sizeof (__aclent32_t), acecmp);
619 acltomode32 (__aclent32_t *aclbufp, int nentries, mode_t *modep)
623 if (!aclbufp || nentries < 1 || !modep)
629 if ((pos = searchace (aclbufp, nentries, USER_OBJ)) < 0
630 || !aclbufp[pos].a_type)
635 *modep |= (aclbufp[pos].a_perm & S_IRWXO) << 6;
636 if ((pos = searchace (aclbufp, nentries, GROUP_OBJ)) < 0
637 || !aclbufp[pos].a_type)
642 *modep |= (aclbufp[pos].a_perm & S_IRWXO) << 3;
644 if ((cpos = searchace (aclbufp, nentries, CLASS_OBJ)) >= 0
645 && aclbufp[cpos].a_type == CLASS_OBJ)
646 *modep |= ((aclbufp[pos].a_perm & S_IRWXO) & aclbufp[cpos].a_perm) << 3;
647 if ((pos = searchace (aclbufp, nentries, OTHER_OBJ)) < 0
648 || !aclbufp[pos].a_type)
653 *modep |= aclbufp[pos].a_perm & S_IRWXO;
658 aclfrommode32 (__aclent32_t *aclbufp, int nentries, mode_t *modep)
662 if (!aclbufp || nentries < 1 || !modep)
667 if ((pos = searchace (aclbufp, nentries, USER_OBJ)) < 0
668 || !aclbufp[pos].a_type)
673 aclbufp[pos].a_perm = (*modep & S_IRWXU) >> 6;
674 if ((pos = searchace (aclbufp, nentries, GROUP_OBJ)) < 0
675 || !aclbufp[pos].a_type)
680 aclbufp[pos].a_perm = (*modep & S_IRWXG) >> 3;
681 if ((pos = searchace (aclbufp, nentries, CLASS_OBJ)) >= 0
682 && aclbufp[pos].a_type == CLASS_OBJ)
683 aclbufp[pos].a_perm = (*modep & S_IRWXG) >> 3;
684 if ((pos = searchace (aclbufp, nentries, OTHER_OBJ)) < 0
685 || !aclbufp[pos].a_type)
690 aclbufp[pos].a_perm = (*modep & S_IRWXO);
695 acltopbits32 (__aclent32_t *aclbufp, int nentries, mode_t *pbitsp)
697 return acltomode32 (aclbufp, nentries, pbitsp);
701 aclfrompbits32 (__aclent32_t *aclbufp, int nentries, mode_t *pbitsp)
703 return aclfrommode32 (aclbufp, nentries, pbitsp);
707 permtostr (mode_t perm)
711 pbuf[0] = (perm & S_IROTH) ? 'r' : '-';
712 pbuf[1] = (perm & S_IWOTH) ? 'w' : '-';
713 pbuf[2] = (perm & S_IXOTH) ? 'x' : '-';
719 acltotext32 (__aclent32_t *aclbufp, int aclcnt)
721 if (!aclbufp || aclcnt < 1 || aclcnt > MAX_ACL_ENTRIES
722 || aclcheck32 (aclbufp, aclcnt, NULL))
731 for (int pos = 0; pos < aclcnt; ++pos)
736 if (aclbufp[pos].a_type & ACL_DEFAULT)
737 strcat (buf, "default");
738 switch (aclbufp[pos].a_type & ~ACL_DEFAULT)
741 __small_sprintf (buf + strlen (buf), "user::%s",
742 permtostr (aclbufp[pos].a_perm));
745 __small_sprintf (buf + strlen (buf), "user:%d:%s",
746 aclbufp[pos].a_id, permtostr (aclbufp[pos].a_perm));
749 __small_sprintf (buf + strlen (buf), "group::%s",
750 permtostr (aclbufp[pos].a_perm));
753 __small_sprintf (buf + strlen (buf), "group:%d:%s",
754 aclbufp[pos].a_id, permtostr (aclbufp[pos].a_perm));
757 __small_sprintf (buf + strlen (buf), "mask::%s",
758 permtostr (aclbufp[pos].a_perm));
761 __small_sprintf (buf + strlen (buf), "other::%s",
762 permtostr (aclbufp[pos].a_perm));
773 permfromstr (char *perm)
777 if (strlen (perm) != 3)
781 else if (perm[0] != '-')
785 else if (perm[1] != '-')
789 else if (perm[2] != '-')
794 extern "C" __aclent32_t *
795 aclfromtext32 (char *acltextp, int *)
802 char buf[strlen (acltextp) + 1];
803 __aclent32_t lacl[MAX_ACL_ENTRIES];
804 memset (lacl, 0, sizeof lacl);
806 strcpy (buf, acltextp);
808 for (char *c = strtok_r (buf, ",", &lasts);
810 c = strtok_r (NULL, ",", &lasts))
812 if (!strncmp (c, "default", 7))
814 lacl[pos].a_type |= ACL_DEFAULT;
817 if (!strncmp (c, "user:", 5))
820 lacl[pos].a_type |= USER_OBJ;
823 lacl[pos].a_type |= USER;
827 struct passwd *pw = internal_getpwnam (c);
833 lacl[pos].a_id = pw->pw_uid;
834 c = strechr (c, ':');
836 else if (isdigit (*c))
837 lacl[pos].a_id = strtol (c, &c, 10);
845 else if (!strncmp (c, "group:", 6))
848 lacl[pos].a_type |= GROUP_OBJ;
851 lacl[pos].a_type |= GROUP;
855 struct __group32 *gr = internal_getgrnam (c);
861 lacl[pos].a_id = gr->gr_gid;
862 c = strechr (c, ':');
864 else if (isdigit (*c))
865 lacl[pos].a_id = strtol (c, &c, 10);
873 else if (!strncmp (c, "mask:", 5))
876 lacl[pos].a_type |= CLASS_OBJ;
883 else if (!strncmp (c, "other:", 6))
886 lacl[pos].a_type |= OTHER_OBJ;
893 if ((lacl[pos].a_perm = permfromstr (c)) == 01000)
900 __aclent32_t *aclp = (__aclent32_t *) malloc (pos * sizeof (__aclent32_t));
902 memcpy (aclp, lacl, pos * sizeof (__aclent32_t));
906 /* __aclent16_t and __aclent32_t have same size and same member offsets */
907 static __aclent32_t *
908 acl16to32 (__aclent16_t *aclbufp, int nentries)
910 __aclent32_t *aclbufp32 = (__aclent32_t *) aclbufp;
912 for (int i = 0; i < nentries; i++)
913 aclbufp32[i].a_id &= USHRT_MAX;
918 acl (const char *path, int cmd, int nentries, __aclent16_t *aclbufp)
920 return acl32 (path, cmd, nentries, acl16to32 (aclbufp, nentries));
924 facl (int fd, int cmd, int nentries, __aclent16_t *aclbufp)
926 return facl32 (fd, cmd, nentries, acl16to32 (aclbufp, nentries));
930 lacl (const char *path, int cmd, int nentries, __aclent16_t *aclbufp)
932 return lacl32 (path, cmd, nentries, acl16to32 (aclbufp, nentries));
936 aclcheck (__aclent16_t *aclbufp, int nentries, int *which)
938 return aclcheck32 (acl16to32 (aclbufp, nentries), nentries, which);
942 aclsort (int nentries, int i, __aclent16_t *aclbufp)
944 return aclsort32 (nentries, i, acl16to32 (aclbufp, nentries));
949 acltomode (__aclent16_t *aclbufp, int nentries, mode_t *modep)
951 return acltomode32 (acl16to32 (aclbufp, nentries), nentries, modep);
955 aclfrommode (__aclent16_t *aclbufp, int nentries, mode_t *modep)
957 return aclfrommode32 ((__aclent32_t *)aclbufp, nentries, modep);
961 acltopbits (__aclent16_t *aclbufp, int nentries, mode_t *pbitsp)
963 return acltopbits32 (acl16to32 (aclbufp, nentries), nentries, pbitsp);
967 aclfrompbits (__aclent16_t *aclbufp, int nentries, mode_t *pbitsp)
969 return aclfrompbits32 ((__aclent32_t *)aclbufp, nentries, pbitsp);
973 acltotext (__aclent16_t *aclbufp, int aclcnt)
975 return acltotext32 (acl16to32 (aclbufp, aclcnt), aclcnt);
978 extern "C" __aclent16_t *
979 aclfromtext (char *acltextp, int * aclcnt)
981 return (__aclent16_t *) aclfromtext32 (acltextp, aclcnt);