Cygwin: (mostly) drop NT4 and Samba < 3.0 support
[newlib-cygwin.git] / winsup / cygwin / sec / posixacl.cc
blob6b01ded5906b08a5e1cb00f784cc7097f28bc3bd
1 /* sec/posixacl.cc: POSIX ACL functions based on Solaris ACLs.
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7 details. */
9 #include "winsup.h"
10 #include <unistd.h>
11 #include "cygerrno.h"
12 #include "path.h"
13 #include "fhandler.h"
14 #include "dtable.h"
15 #include "cygheap.h"
16 #include "tls_pbuf.h"
17 #include "sec_posixacl.h"
18 #include <acl/libacl.h>
20 #define _ENTRY_SIZE(_cnt) ((_cnt) * sizeof (aclent_t))
21 #define _ACL_SIZE(_cnt) (sizeof (__acl_ext_t) + _ENTRY_SIZE (_cnt))
22 #define ACL_SIZE(_acl) ({ acl_t __acl = _acl; \
23 _ACL_SIZE((__acl)->count - (__acl)->deleted); \
25 #define ACL_PERM_MASK (ACL_READ | ACL_WRITE | ACL_EXECUTE)
27 extern "C" acl_t
28 acl_init (int count)
30 acl_t acl;
32 if (count < 0 || count > UINT16_MAX)
34 set_errno (EINVAL);
35 return NULL;
37 acl = (acl_t) calloc (1, sizeof (__acl_t));
38 if (!acl)
39 return NULL;
40 acl->entry = (aclent_t *) calloc (count, sizeof (aclent_t));
41 if (!acl->entry)
43 free (acl);
44 return NULL;
46 acl->magic = ACL_MAGIC;
47 acl->max_count = count;
48 return acl;
51 extern "C" acl_t
52 acl_dup (acl_t acl)
54 __try
56 acl_t new_acl = acl_init (acl->max_count);
57 if (new_acl)
59 uint16_t new_idx = 0;
61 for (uint16_t idx = 0; idx < acl->count; ++idx)
62 if (acl->entry[idx].a_type != ACL_DELETED_TAG)
63 new_acl->entry[new_idx++] = acl->entry[idx];
64 new_acl->magic = ACL_MAGIC;
65 new_acl->count = new_idx;
66 return new_acl;
69 __except (EINVAL) {}
70 __endtry
71 return NULL;
74 extern "C" int
75 acl_free (void *obj_p)
77 __try
79 acl_t acl;
81 if (obj_p)
83 if (malloc_usable_size (obj_p) >= sizeof (__acl_t))
85 acl = (acl_t) obj_p;
86 if (acl->magic == ACL_MAGIC)
87 free (acl->entry);
89 free (obj_p);
90 return 0;
92 set_errno (EINVAL);
94 __except (EINVAL) {}
95 __endtry
96 return -1;
99 extern "C" int
100 acl_valid (acl_t acl)
102 __try
104 if (!(__aclcheck (acl->entry, acl->count, NULL, true)))
105 return 0;
106 set_errno (EINVAL);
108 __except (EINVAL) {}
109 __endtry
110 return -1;
113 extern "C" int
114 acl_copy_entry (acl_entry_t dest_d, acl_entry_t src_d)
116 __try
118 uint16_t d_idx, s_idx;
119 acl_t d_acl, s_acl;
121 d_acl = __from_entry (dest_d, d_idx);
122 s_acl = __from_entry (src_d, s_idx);
123 if (d_acl && s_acl)
125 d_acl->entry[d_idx] = s_acl->entry[s_idx];
126 return 0;
128 set_errno (EINVAL);
130 __except (EINVAL) {}
131 __endtry
132 return -1;
135 extern "C" int
136 acl_create_entry (acl_t *acl_p, acl_entry_t *entry_p)
138 __try
140 acl_t acl = *acl_p;
141 uint16_t idx;
143 if (acl->deleted > 0)
145 for (idx = 0; idx < acl->count; ++idx)
146 if (acl->entry[idx].a_type == ACL_DELETED_TAG)
148 *entry_p = __to_entry (acl, idx);
149 --acl->deleted;
150 goto fill_entry;
153 if (acl->count >= acl->max_count)
155 aclent_t *new_e;
157 new_e = (aclent_t *) realloc (acl->entry,
158 _ENTRY_SIZE (acl->max_count + 1));
159 if (!new_e)
160 __leave;
161 acl->entry = new_e;
162 ++acl->max_count;
164 idx = acl->count++;
165 *entry_p = __to_entry (acl, idx);
166 fill_entry:
167 acl->entry[idx].a_type = ACL_UNDEFINED_TAG;
168 acl->entry[idx].a_id = ACL_UNDEFINED_ID;
169 acl->entry[idx].a_perm = 0;
170 return 0;
172 __except (EINVAL) {}
173 __endtry
174 return -1;
177 extern "C" int
178 acl_delete_entry (acl_t acl, acl_entry_t entry_d)
180 __try
182 acl_t acl_p;
183 uint16_t idx;
185 acl_p = __from_entry (entry_d, idx);
187 if (acl_p == acl)
189 acl_p->entry[idx].a_type = ACL_DELETED_TAG;
190 acl_p->entry[idx].a_id = ACL_UNDEFINED_ID;
191 acl_p->entry[idx].a_perm = 0;
192 return 0;
194 set_errno (EINVAL);
196 __except (EINVAL) {}
197 __endtry
198 return -1;
201 extern "C" int
202 acl_get_entry (acl_t acl, int entry_id, acl_entry_t *entry_p)
204 __try
206 uint16_t idx;
208 if (entry_id == ACL_FIRST_ENTRY)
209 acl->next = 0;
210 else if (entry_id != ACL_NEXT_ENTRY)
212 set_errno (EINVAL);
213 __leave;
217 if (acl->next >= acl->count)
218 return 0;
219 idx = acl->next++;
221 while (acl->entry[idx].a_type == ACL_DELETED_TAG);
222 *entry_p = __to_entry (acl, idx);
223 return 1;
225 __except (EINVAL) {}
226 __endtry
227 return -1;
230 extern "C" int
231 acl_calc_mask (acl_t *acl_p)
233 __try
235 acl_t acl = *acl_p;
236 mode_t mask = 0;
238 mask = __aclcalcmask (acl->entry, acl->count);
239 /* If __aclcalcmask returns -1 we're done. Otherwise create a
240 mask entry here. */
241 if (mask != (acl_perm_t) -1)
243 acl_entry_t entry_d;
244 uint16_t mask_idx;
246 if (acl_create_entry (&acl, &entry_d) < 0)
247 __leave;
248 if (!__from_entry (entry_d, mask_idx))
250 set_errno (EINVAL);
251 __leave;
253 acl->entry[mask_idx].a_type = ACL_MASK;
254 acl->entry[mask_idx].a_id = ACL_UNDEFINED_ID;
255 acl->entry[mask_idx].a_perm = mask;
256 *acl_p = acl;
258 return 0;
260 __except (EINVAL) {}
261 __endtry
262 return -1;
265 extern "C" int
266 acl_clear_perms (acl_permset_t permset_d)
268 __try
270 acl_t acl;
271 uint16_t idx;
273 acl = __from_permset (permset_d, idx);
274 if (acl)
276 acl->entry[idx].a_perm = 0;
277 return 0;
279 set_errno (EINVAL);
281 __except (EINVAL) {}
282 __endtry
283 return -1;
286 extern "C" int
287 acl_add_perm (acl_permset_t permset_d, acl_perm_t perm)
289 __try
291 acl_t acl;
292 uint16_t idx;
294 acl = __from_permset (permset_d, idx);
295 if (acl && !(perm & ~ACL_PERM_MASK))
297 acl->entry[idx].a_perm |= perm;
298 return 0;
300 set_errno (EINVAL);
302 __except (EINVAL) {}
303 __endtry
304 return -1;
307 extern "C" int
308 acl_delete_perm (acl_permset_t permset_d, acl_perm_t perm)
310 __try
312 acl_t acl;
313 uint16_t idx;
315 acl = __from_permset (permset_d, idx);
316 if (acl && !(perm & ~ACL_PERM_MASK))
318 acl->entry[idx].a_perm &= ~perm;
319 return 0;
321 set_errno (EINVAL);
323 __except (EINVAL) {}
324 __endtry
325 return -1;
328 extern "C" int
329 acl_get_permset (acl_entry_t entry_d, acl_permset_t *permset_p)
331 __try
333 acl_t acl;
334 uint16_t idx;
336 acl = __from_entry (entry_d, idx);
337 if (acl)
339 *permset_p = (acl_permset_t) entry_d;
340 return 0;
342 set_errno (EINVAL);
344 __except (EINVAL) {}
345 __endtry
346 return -1;
349 extern "C" int
350 acl_set_permset (acl_entry_t entry_d, acl_permset_t permset_d)
352 __try
354 acl_t acl_e, acl_p;
355 uint16_t idx_e, idx_p;
357 acl_e = __from_entry (entry_d, idx_e);
358 acl_p = __from_permset (permset_d, idx_p);
359 if (acl_e && acl_p && !(acl_p->entry[idx_p].a_perm & ~ACL_PERM_MASK))
361 acl_e->entry[idx_e].a_perm = acl_p->entry[idx_p].a_perm;
362 return 0;
364 set_errno (EINVAL);
366 __except (EINVAL) {}
367 __endtry
368 return -1;
371 extern "C" void *
372 acl_get_qualifier (acl_entry_t entry_d)
374 __try
376 acl_t acl;
377 uint16_t idx;
379 acl = __from_entry (entry_d, idx);
380 if (acl && (acl->entry[idx].a_type & (ACL_USER | ACL_GROUP)))
382 id_t *id = (id_t *) malloc (sizeof (id_t));
383 if (id)
385 *id = acl->entry[idx].a_id;
386 return (void *) id;
389 else
390 set_errno (EINVAL);
392 __except (EINVAL) {}
393 __endtry
394 return NULL;
397 extern "C" int
398 acl_set_qualifier (acl_entry_t entry_d, const void *qualifier_p)
400 __try
402 acl_t acl;
403 uint16_t idx;
405 acl = __from_entry (entry_d, idx);
406 if (acl && (acl->entry[idx].a_type & (ACL_USER | ACL_GROUP)))
408 acl->entry[idx].a_id = *(id_t *) qualifier_p;
409 return 0;
411 set_errno (EINVAL);
413 __except (EINVAL) {}
414 __endtry
415 return -1;
418 extern "C" int
419 acl_get_tag_type (acl_entry_t entry_d, acl_tag_t *tag_type_p)
421 __try
423 acl_t acl;
424 uint16_t idx;
426 acl = __from_entry (entry_d, idx);
427 if (acl)
429 *tag_type_p = acl->entry[idx].a_type;
430 return 0;
432 set_errno (EINVAL);
434 __except (EINVAL) {}
435 __endtry
436 return -1;
439 extern "C" int
440 acl_set_tag_type (acl_entry_t entry_d, acl_tag_t tag_type)
442 __try
444 acl_t acl;
445 uint16_t idx;
447 acl = __from_entry (entry_d, idx);
448 if (acl)
449 switch (tag_type)
451 case ACL_USER_OBJ:
452 case ACL_GROUP_OBJ:
453 case ACL_MASK:
454 case ACL_OTHER:
455 acl->entry[idx].a_id = ACL_UNDEFINED_ID;
456 fallthrough;
457 case ACL_USER:
458 case ACL_GROUP:
459 acl->entry[idx].a_type = tag_type;
460 return 0;
461 default:
462 break;
464 set_errno (EINVAL);
466 __except (EINVAL) {}
467 __endtry
468 return -1;
471 extern "C" ssize_t
472 acl_size (acl_t acl)
474 __try
476 return (ssize_t) ACL_SIZE (acl);
478 __except (EINVAL) {}
479 __endtry
480 return -1;
483 extern "C" ssize_t
484 acl_copy_ext (void *buf_p, acl_t acl, ssize_t size)
486 __try
488 ssize_t ext_size = (ssize_t) ACL_SIZE (acl);
490 if (size <= 0)
491 set_errno (EINVAL);
492 else if (ext_size > size)
493 set_errno (ERANGE);
494 else
496 uint16_t ext_idx = 0;
497 __acl_ext_t *acl_ext = (__acl_ext_t *) buf_p;
499 acl_ext->count = acl->count - acl->deleted;
500 for (uint16_t idx = 0; idx < acl->count; ++idx)
501 if (acl->entry[idx].a_type != ACL_DELETED_TAG)
502 acl_ext->entry[ext_idx++] = acl->entry[idx];
503 return ext_size;
506 __except (EINVAL) {}
507 __endtry
508 return -1;
511 extern "C" acl_t
512 acl_copy_int (const void *buf_p)
514 __try
516 acl_t acl;
517 __acl_ext_t *acl_ext = (__acl_ext_t *) buf_p;
519 acl = acl_init (acl_ext->count);
520 if (acl)
522 memcpy (acl->entry, acl_ext->entry, _ENTRY_SIZE (acl_ext->count));
523 acl->count = acl_ext->count;
524 return acl;
527 __except (EINVAL) {}
528 __endtry
529 return NULL;
532 extern "C" acl_t
533 acl_from_text (const char *buf_p)
535 __try
537 return (acl_t) __aclfromtext (buf_p, NULL, true);
539 __except (EINVAL) {}
540 __endtry
541 return NULL;
544 extern "C" char *
545 acl_to_text (acl_t acl, ssize_t *len_p)
547 __try
549 char *ret = __acltotext (acl->entry, acl->count, NULL, '\n',
550 TEXT_IS_POSIX
551 | TEXT_SOME_EFFECTIVE
552 | TEXT_END_SEPARATOR);
553 if (ret && len_p)
554 *len_p = strlen (ret);
555 return ret;
557 __except (EINVAL) {}
558 __endtry
559 return NULL;
562 acl_t
563 fhandler_base::acl_get (acl_type_t type)
565 set_errno (ENOTSUP);
566 return NULL;
569 acl_t
570 fhandler_disk_file::acl_get (acl_type_t type)
572 acl_t acl = NULL;
573 int oret = 0;
575 __try
577 tmp_pathbuf tp;
578 aclent_t *aclbufp;
579 uint16_t cnt, access_cnt;
581 if (!pc.has_acls ())
583 set_errno (ENOTSUP);
584 __leave;
586 if (type == ACL_TYPE_DEFAULT && !pc.isdir ())
588 set_errno (ENOTDIR);
589 __leave;
591 aclbufp = (aclent_t *) tp.c_get ();
592 if (!get_handle ())
594 query_open (query_read_control);
595 if (!(oret = open (O_BINARY, 0)))
596 __leave;
598 cnt = facl (GETACL, MAX_ACL_ENTRIES, aclbufp);
599 if (cnt < 0)
600 __leave;
601 /* Set access_cnt to number of non-default entries from file ACL. */
602 if (!pc.isdir ())
603 access_cnt = cnt;
604 else
605 for (access_cnt = 0; access_cnt < cnt; ++access_cnt)
606 if (aclbufp[access_cnt].a_type & ACL_DEFAULT)
607 break;
608 if (type == ACL_TYPE_ACCESS)
610 acl = acl_init (access_cnt);
611 if (!acl)
612 __leave;
613 memcpy (acl->entry, aclbufp, _ENTRY_SIZE (access_cnt));
614 acl->count = access_cnt;
616 else
618 cnt -= access_cnt;
619 acl = acl_init (cnt);
620 if (acl && cnt)
622 memcpy (acl->entry, aclbufp + access_cnt, _ENTRY_SIZE (cnt));
623 acl->count = cnt;
624 for (cnt = 0; cnt < acl->count; ++cnt)
625 acl->entry[cnt].a_type &= ~ACL_DEFAULT;
629 __except (EINVAL) {}
630 __endtry
631 if (oret)
632 close_fs ();
633 return acl;
636 acl_t
637 fhandler_socket_local::acl_get (acl_type_t type)
639 if (!dev ().isfs ())
640 /* acl_get_fd on a socket. */
641 return fhandler_base::acl_get (type);
643 /* acl_get_fd on a socket opened with O_PATH or acl_get_file on a
644 socket file. */
645 if (get_flags () & O_PATH)
647 set_errno (EBADF);
648 return NULL;
650 fhandler_disk_file fh (pc);
651 return fh.acl_get (type);
654 #ifdef __WITH_AF_UNIX
655 acl_t
656 fhandler_socket_unix::acl_get (acl_type_t type)
658 if (!dev ().isfs ())
659 /* acl_get_fd on a socket. */
660 return fhandler_base::acl_get (type);
662 /* acl_get_fd on a socket opened with O_PATH or acl_get_file on a
663 socket file. */
664 if (get_flags () & O_PATH)
666 set_errno (EBADF);
667 return NULL;
669 fhandler_disk_file fh (pc);
670 return fh.acl_get (type);
672 #endif
674 extern "C" acl_t
675 acl_get_fd (int fd)
677 cygheap_fdget cfd (fd);
678 if (cfd < 0)
679 return NULL;
680 return cfd->acl_get (ACL_TYPE_ACCESS);
683 extern "C" acl_t
684 acl_get_file (const char *path_p, acl_type_t type)
686 if (type != ACL_TYPE_ACCESS && type != ACL_TYPE_DEFAULT)
688 set_errno (EINVAL);
689 return NULL;
691 fhandler_base *fh;
692 if (!(fh = build_fh_name (path_p, PC_SYM_FOLLOW, stat_suffixes)))
693 return NULL;
694 if (fh->error ())
696 set_errno (fh->error ());
697 return NULL;
699 acl_t acl = fh->acl_get (type);
700 delete fh;
701 return acl;
705 fhandler_base::acl_set (acl_t acl, acl_type_t type)
707 set_errno (ENOTSUP);
708 return -1;
712 fhandler_disk_file::acl_set (acl_t acl, acl_type_t type)
714 int ret = -1;
715 int oret = 0;
717 __try
719 tmp_pathbuf tp;
720 aclent_t *aclbufp, *aclbuf_from_file;
721 uint16_t cnt, cnt_from_file, access_cnt;
723 if (!pc.has_acls ())
725 set_errno (ENOTSUP);
726 __leave;
728 if (type == ACL_TYPE_DEFAULT && !pc.isdir ())
730 set_errno (ENOTDIR);
731 __leave;
733 if (acl->count > MAX_ACL_ENTRIES)
735 set_errno (EINVAL);
736 __leave;
738 aclbuf_from_file = (aclent_t *) tp.c_get ();
739 if (!get_handle ())
741 query_open (query_write_dac);
742 if (!(oret = open (O_BINARY, 0)))
743 __leave;
745 cnt_from_file = facl (GETACL, MAX_ACL_ENTRIES, aclbuf_from_file);
746 if (cnt_from_file < 0)
747 __leave;
748 aclbufp = (aclent_t *) tp.c_get ();
749 /* Set access_cnt to number of non-default entries from file ACL. */
750 if (!pc.isdir ())
751 access_cnt = cnt_from_file;
752 else
753 for (access_cnt = 0; access_cnt < cnt_from_file; ++access_cnt)
754 if (aclbuf_from_file[access_cnt].a_type & ACL_DEFAULT)
755 break;
756 if (type == ACL_TYPE_ACCESS)
758 /* Check if the number of ACEs fits into the buffer. */
759 if (acl->count - acl->deleted + cnt_from_file - access_cnt
760 > MAX_ACL_ENTRIES)
762 set_errno (EINVAL);
763 __leave;
765 /* Copy the new ACL entries. */
766 cnt = 0;
767 for (uint16_t idx = 0; idx < acl->count; ++idx)
768 if (acl->entry[idx].a_type != ACL_DELETED_TAG)
769 aclbufp[cnt++] = acl->entry[idx];
770 /* Append default ACL from file, if any. */
771 if (access_cnt < cnt_from_file)
773 memcpy (aclbufp + cnt, aclbuf_from_file + access_cnt,
774 _ENTRY_SIZE (cnt_from_file - access_cnt));
775 cnt += cnt_from_file - access_cnt;
778 else
780 /* Check if the number of ACEs fits into the buffer. */
781 if (acl->count - acl->deleted + access_cnt > MAX_ACL_ENTRIES)
783 set_errno (EINVAL);
784 __leave;
786 /* Copy non-default entries from file. */
787 memcpy (aclbufp, aclbuf_from_file, _ENTRY_SIZE (access_cnt));
788 cnt = access_cnt;
789 /* Append new default ACL entries (and add ACL_DEFAULT flag). */
790 for (uint16_t idx = 0; idx < acl->count; ++idx)
791 if (acl->entry[idx].a_type != ACL_DELETED_TAG)
793 aclbufp[cnt] = acl->entry[idx];
794 aclbufp[cnt++].a_type |= ACL_DEFAULT;
797 ret = facl (SETACL, cnt, aclbufp);
799 __except (EINVAL) {}
800 __endtry
801 if (oret)
802 close_fs ();
803 return ret;
807 fhandler_socket_local::acl_set (acl_t acl, acl_type_t type)
809 if (!dev ().isfs ())
810 /* acl_set_fd on a socket. */
811 return fhandler_base::acl_set (acl, type);
813 /* acl_set_fd on a socket opened with O_PATH or acl_set_file on a
814 socket file. */
815 if (get_flags () & O_PATH)
817 set_errno (EBADF);
818 return -1;
820 fhandler_disk_file fh (pc);
821 return fh.acl_set (acl, type);
824 #ifdef __WITH_AF_UNIX
826 fhandler_socket_unix::acl_set (acl_t acl, acl_type_t type)
828 if (!dev ().isfs ())
829 /* acl_set_fd on a socket. */
830 return fhandler_base::acl_set (acl, type);
832 /* acl_set_fd on a socket opened with O_PATH or acl_set_file on a
833 socket file. */
834 if (get_flags () & O_PATH)
836 set_errno (EBADF);
837 return -1;
839 fhandler_disk_file fh (pc);
840 return fh.acl_set (acl, type);
842 #endif
844 extern "C" int
845 acl_set_fd (int fd, acl_t acl)
847 cygheap_fdget cfd (fd);
848 if (cfd < 0)
849 return -1;
850 return cfd->acl_set (acl, ACL_TYPE_ACCESS);
853 extern "C" int
854 acl_set_file(const char *path_p, acl_type_t type, acl_t acl)
856 if (type != ACL_TYPE_ACCESS && type != ACL_TYPE_DEFAULT)
858 set_errno (EINVAL);
859 return -1;
861 fhandler_base *fh;
862 if (!(fh = build_fh_name (path_p, PC_SYM_FOLLOW, stat_suffixes)))
863 return -1;
864 if (fh->error ())
866 set_errno (fh->error ());
867 return -1;
869 int ret = fh->acl_set (acl, type);
870 delete fh;
871 return ret;
874 extern "C" int
875 acl_delete_def_file (const char *path_p)
877 acl_t acl = (acl_t) alloca (sizeof (struct __acl_t));
878 acl->count = acl->max_count = acl->next = 0;
879 if (!acl)
880 return -1;
881 return acl_set_file(path_p, ACL_TYPE_DEFAULT, acl);
884 /* libacl extensions */
886 extern "C" int
887 acl_check (acl_t acl, int *last)
890 __try
892 int ret = 0;
894 if (acl->count != 0)
896 ret = __aclcheck (acl->entry, acl->count, last, true);
897 switch (ret)
899 case GRP_ERROR:
900 case USER_ERROR:
901 case CLASS_ERROR:
902 case OTHER_ERROR:
903 ret = ACL_MULTI_ERROR;
904 break;
905 default:
906 break;
909 return ret;
911 __except (EINVAL) {}
912 __endtry
913 return -1;
916 extern "C" int
917 acl_cmp (acl_t acl1, acl_t acl2)
919 int ret = -1;
921 __try
923 tmp_pathbuf tp;
925 __acl_ext_t *acl1d = (__acl_ext_t *) tp.c_get ();
926 __acl_ext_t *acl2d = (__acl_ext_t *) tp.c_get ();
927 if (acl_copy_ext (acl1d, acl1, NT_MAX_PATH) < 0)
928 __leave;
929 if (acl_copy_ext (acl2d, acl2, NT_MAX_PATH) < 0)
930 __leave;
931 if (acl1d->count != acl2d->count)
932 return 1;
933 if (__aclsort (acl1d->count, acl1d->entry))
934 __leave;
935 if (__aclsort (acl2d->count, acl2d->entry))
936 __leave;
937 for (int idx = 0; idx < acl1d->count; ++idx)
939 if (acl1d->entry[idx].a_type != acl2d->entry[idx].a_type)
941 ret = 1;
942 __leave;
944 if ((acl1d->entry[idx].a_perm & ACL_PERM_MASK)
945 != (acl2d->entry[idx].a_perm & ACL_PERM_MASK))
947 ret = 1;
948 __leave;
950 if ((acl1d->entry[idx].a_type & (ACL_USER | ACL_GROUP))
951 && acl1d->entry[idx].a_id != acl2d->entry[idx].a_id)
953 ret = 1;
954 __leave;
957 ret = 0;
959 __except (EINVAL) {}
960 __endtry
961 return ret;
964 extern "C" int
965 acl_entries (acl_t acl)
967 __try
969 return acl->count - acl->deleted;
971 __except (EINVAL) {}
972 __endtry
973 return -1;
976 extern "C" int
977 acl_equiv_mode (acl_t acl, mode_t *mode_p)
979 __try
981 if (acl->count != 3)
983 set_errno (EINVAL);
984 __leave;
986 int u_idx = -1, g_idx = -1, o_idx = -1;
987 for (int idx = 0; idx < 3; ++idx)
988 switch (acl->entry[idx].a_type)
990 case ACL_USER_OBJ:
991 u_idx = idx;
992 break;
993 case ACL_GROUP_OBJ:
994 g_idx = idx;
995 break;
996 case ACL_OTHER:
997 o_idx = idx;
998 break;
1000 if (u_idx == -1 || g_idx == -1 || o_idx == -1)
1002 set_errno (EINVAL);
1003 __leave;
1005 if (mode_p)
1006 *mode_p = ((acl->entry[u_idx].a_perm & ACL_PERM_MASK) << 6)
1007 | ((acl->entry[g_idx].a_perm & ACL_PERM_MASK) << 3)
1008 | (acl->entry[o_idx].a_perm & ACL_PERM_MASK);
1009 return 0;
1011 __except (EINVAL) {}
1012 __endtry
1013 return -1;
1016 static const char *acl_err_txt[] =
1018 "Multiple entries",
1019 "Duplicate entries",
1020 "Invalid entry type",
1021 "Missing or wrong entry"
1024 extern "C" const char *
1025 acl_error (int code)
1027 if (code < ACL_MULTI_ERROR || code > ACL_MISS_ERROR)
1028 return NULL;
1029 return acl_err_txt[code - ACL_MULTI_ERROR];
1032 static int
1033 __acl_extended_fh (fhandler_base *fh)
1035 int ret = -1;
1037 if (!fh->pc.has_acls ())
1038 set_errno (ENOTSUP);
1039 else
1041 ret = fh->facl (GETACLCNT, 0, NULL);
1042 if (ret >= 0)
1043 ret = (ret > MIN_ACL_ENTRIES) ? 1 : 0;
1045 return ret;
1048 extern "C" int
1049 acl_extended_fd (int fd)
1051 __try
1053 cygheap_fdget cfd (fd);
1054 if (cfd < 0)
1055 __leave;
1056 return __acl_extended_fh (cfd);
1058 __except (EBADF) {}
1059 __endtry
1060 return -1;
1063 static int
1064 __acl_extended_file (path_conv &pc)
1066 int ret = -1;
1068 __try
1070 if (pc.error)
1071 set_errno (pc.error);
1072 else if (!pc.exists ())
1073 set_errno (ENOENT);
1074 else
1076 fhandler_base *fh;
1078 if (!(fh = build_fh_pc (pc)))
1079 __leave;
1080 ret = __acl_extended_fh (fh);
1081 delete fh;
1084 __except (EFAULT) {}
1085 __endtry
1086 return ret;
1089 extern "C" int
1090 acl_extended_file (const char *path_p)
1092 path_conv pc (path_p, PC_SYM_FOLLOW | PC_POSIX | PC_KEEP_HANDLE,
1093 stat_suffixes);
1094 return __acl_extended_file (pc);
1097 extern "C" int
1098 acl_extended_file_nofollow (const char *path_p)
1100 path_conv pc (path_p, PC_SYM_NOFOLLOW | PC_POSIX | PC_KEEP_HANDLE,
1101 stat_suffixes);
1102 return __acl_extended_file (pc);
1105 extern "C" acl_t
1106 acl_from_mode (mode_t mode)
1108 acl_t acl = acl_init (MIN_ACL_ENTRIES);
1109 if (!acl)
1110 return NULL;
1111 acl->count = 3;
1112 acl->entry[0].a_type = USER_OBJ;
1113 acl->entry[0].a_id = ACL_UNDEFINED_ID;
1114 acl->entry[0].a_perm = (mode >> 6) & ACL_PERM_MASK;
1115 acl->entry[1].a_type = GROUP_OBJ;
1116 acl->entry[1].a_id = ACL_UNDEFINED_ID;
1117 acl->entry[1].a_perm = (mode >> 3) & ACL_PERM_MASK;
1118 acl->entry[2].a_type = OTHER_OBJ;
1119 acl->entry[2].a_id = ACL_UNDEFINED_ID;
1120 acl->entry[2].a_perm = mode & ACL_PERM_MASK;
1121 return acl;
1124 extern "C" int
1125 acl_get_perm (acl_permset_t permset_d, acl_perm_t perm)
1127 __try
1129 acl_t acl;
1130 uint16_t idx;
1132 acl = __from_permset (permset_d, idx);
1133 if (acl && !(perm & ~ACL_PERM_MASK))
1134 return (~acl->entry[idx].a_perm & perm) ? 0 : 1;
1135 set_errno (EINVAL);
1137 __except (EINVAL) {}
1138 __endtry
1139 return -1;
1142 extern "C" char *
1143 acl_to_any_text (acl_t acl, const char *prefix, char separator, int options)
1145 __try
1147 return __acltotext (acl->entry, acl->count, prefix, separator,
1148 TEXT_IS_POSIX | options);
1150 __except (EINVAL) {}
1151 __endtry
1152 return NULL;