More NEWS updates.
[rsync.git] / lib / sysacls.c
bloba5abe408d77c5ccb97b0ae66c996ea3f8dfea119
1 /*
2 * Unix SMB/CIFS implementation.
3 * Based on the Samba ACL support code.
4 * Copyright (C) Jeremy Allison 2000.
5 * Copyright (C) 2007-2022 Wayne Davison
7 * The permission functions have been changed to get/set all bits via
8 * one call. Some functions that rsync doesn't need were also removed.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * with this program; if not, visit the http://fsf.org website.
24 #include "rsync.h"
25 #include "sysacls.h"
27 #ifdef SUPPORT_ACLS
29 #ifdef DEBUG
30 #undef DEBUG
31 #endif
32 #define DEBUG(x, y)
34 void SAFE_FREE(void *mem)
36 if (mem)
37 free(mem);
41 This file wraps all differing system ACL interfaces into a consistent
42 one based on the POSIX interface. It also returns the correct errors
43 for older UNIX systems that don't support ACLs.
45 The interfaces that each ACL implementation must support are as follows :
47 int sys_acl_get_entry(SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
48 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
49 int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *bits_p, id_t *u_g_id_p)
50 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
51 SMB_ACL_T sys_acl_get_fd(int fd)
52 SMB_ACL_T sys_acl_init(int count)
53 int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
54 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
55 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits)
56 int sys_acl_valid(SMB_ACL_T theacl)
57 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
58 int sys_acl_set_fd(int fd, SMB_ACL_T theacl)
59 int sys_acl_delete_def_file(const char *path)
60 int sys_acl_free_acl(SMB_ACL_T posix_acl)
64 #if defined(HAVE_POSIX_ACLS) /*--------------------------------------------*/
66 /* Identity mapping - easy. */
68 int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
70 return acl_get_entry(the_acl, entry_id, entry_p);
73 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
75 return acl_get_tag_type(entry_d, tag_type_p);
78 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
80 return acl_get_file(path_p, type);
83 #if 0
84 SMB_ACL_T sys_acl_get_fd(int fd)
86 return acl_get_fd(fd);
88 #endif
90 #if defined(HAVE_ACL_GET_PERM_NP)
91 #define acl_get_perm(p, b) acl_get_perm_np(p, b)
92 #endif
94 int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *bits_p, id_t *u_g_id_p)
96 acl_permset_t permset;
98 if (acl_get_tag_type(entry, tag_type_p) != 0
99 || acl_get_permset(entry, &permset) != 0)
100 return -1;
102 *bits_p = (acl_get_perm(permset, ACL_READ) ? 4 : 0)
103 | (acl_get_perm(permset, ACL_WRITE) ? 2 : 0)
104 | (acl_get_perm(permset, ACL_EXECUTE) ? 1 : 0);
106 if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP) {
107 void *qual;
108 if ((qual = acl_get_qualifier(entry)) == NULL)
109 return -1;
110 *u_g_id_p = *(id_t*)qual;
111 acl_free(qual);
114 return 0;
117 SMB_ACL_T sys_acl_init(int count)
119 return acl_init(count);
122 int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
124 return acl_create_entry(pacl, pentry);
127 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
129 if (acl_set_tag_type(entry, tag_type) != 0)
130 return -1;
132 if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP) {
133 if (acl_set_qualifier(entry, (void*)&u_g_id) != 0)
134 return -1;
137 return sys_acl_set_access_bits(entry, bits);
140 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits)
142 acl_permset_t permset;
143 int rc;
144 if ((rc = acl_get_permset(entry, &permset)) != 0)
145 return rc;
146 acl_clear_perms(permset);
147 if (bits & 4)
148 acl_add_perm(permset, ACL_READ);
149 if (bits & 2)
150 acl_add_perm(permset, ACL_WRITE);
151 if (bits & 1)
152 acl_add_perm(permset, ACL_EXECUTE);
153 return acl_set_permset(entry, permset);
156 int sys_acl_valid(SMB_ACL_T theacl)
158 return acl_valid(theacl);
161 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
163 return acl_set_file(name, acltype, theacl);
166 #if 0
167 int sys_acl_set_fd(int fd, SMB_ACL_T theacl)
169 return acl_set_fd(fd, theacl);
171 #endif
173 int sys_acl_delete_def_file(const char *name)
175 return acl_delete_def_file(name);
178 int sys_acl_free_acl(SMB_ACL_T the_acl)
180 return acl_free(the_acl);
183 #elif defined(HAVE_TRU64_ACLS) /*--------------------------------------------*/
185 * The interface to DEC/Compaq Tru64 UNIX ACLs
186 * is based on Draft 13 of the POSIX spec which is
187 * slightly different from the Draft 16 interface.
189 * Also, some of the permset manipulation functions
190 * such as acl_clear_perm() and acl_add_perm() appear
191 * to be broken on Tru64 so we have to manipulate
192 * the permission bits in the permset directly.
194 int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
196 SMB_ACL_ENTRY_T entry;
198 if (entry_id == SMB_ACL_FIRST_ENTRY && acl_first_entry(the_acl) != 0) {
199 return -1;
202 errno = 0;
203 if ((entry = acl_get_entry(the_acl)) != NULL) {
204 *entry_p = entry;
205 return 1;
208 return errno ? -1 : 0;
211 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
213 return acl_get_tag_type(entry_d, tag_type_p);
216 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
218 return acl_get_file((char *)path_p, type);
221 #if 0
222 SMB_ACL_T sys_acl_get_fd(int fd)
224 return acl_get_fd(fd, ACL_TYPE_ACCESS);
226 #endif
228 int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *bits_p, id_t *u_g_id_p)
230 acl_permset_t permset;
232 if (acl_get_tag_type(entry, tag_type_p) != 0
233 || acl_get_permset(entry, &permset) != 0)
234 return -1;
236 *bits_p = *permset & 7; /* Tru64 doesn't have acl_get_perm() */
238 if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP) {
239 void *qual;
240 if ((qual = acl_get_qualifier(entry)) == NULL)
241 return -1;
242 *u_g_id_p = *(id_t*)qual;
243 acl_free_qualifier(qual, *tag_type_p);
246 return 0;
249 SMB_ACL_T sys_acl_init(int count)
251 return acl_init(count);
254 int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
256 SMB_ACL_ENTRY_T entry;
258 if ((entry = acl_create_entry(pacl)) == NULL) {
259 return -1;
262 *pentry = entry;
263 return 0;
266 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
268 if (acl_set_tag_type(entry, tag_type) != 0)
269 return -1;
271 if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP) {
272 if (acl_set_qualifier(entry, (void*)&u_g_id) != 0)
273 return -1;
276 return sys_acl_set_access_bits(entry, bits);
279 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits)
281 acl_permset_t permset;
282 int rc;
283 if ((rc = acl_get_permset(entry, &permset)) != 0)
284 return rc;
285 *permset = bits & 7;
286 return acl_set_permset(entry, permset);
289 int sys_acl_valid(SMB_ACL_T theacl)
291 acl_entry_t entry;
293 return acl_valid(theacl, &entry);
296 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
298 return acl_set_file((char *)name, acltype, theacl);
301 #if 0
302 int sys_acl_set_fd(int fd, SMB_ACL_T theacl)
304 return acl_set_fd(fd, ACL_TYPE_ACCESS, theacl);
306 #endif
308 int sys_acl_delete_def_file(const char *name)
310 return acl_delete_def_file((char *)name);
313 int sys_acl_free_acl(SMB_ACL_T the_acl)
315 return acl_free(the_acl);
318 #elif defined(HAVE_UNIXWARE_ACLS) || defined(HAVE_SOLARIS_ACLS) /*-----------*/
321 * Donated by Michael Davidson <md@sco.COM> for UnixWare / OpenUNIX.
322 * Modified by Toomas Soome <tsoome@ut.ee> for Solaris.
326 * Note that while this code implements sufficient functionality
327 * to support the sys_acl_* interfaces it does not provide all
328 * of the semantics of the POSIX ACL interfaces.
330 * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
331 * from a call to sys_acl_get_entry() should not be assumed to be
332 * valid after calling any of the following functions, which may
333 * reorder the entries in the ACL.
335 * sys_acl_valid()
336 * sys_acl_set_file()
337 * sys_acl_set_fd()
341 * The only difference between Solaris and UnixWare / OpenUNIX is
342 * that the #defines for the ACL operations have different names
344 #if defined(HAVE_UNIXWARE_ACLS)
346 #define SETACL ACL_SET
347 #define GETACL ACL_GET
348 #define GETACLCNT ACL_CNT
350 #endif
353 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
355 if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
356 errno = EINVAL;
357 return -1;
360 if (entry_p == NULL) {
361 errno = EINVAL;
362 return -1;
365 if (entry_id == SMB_ACL_FIRST_ENTRY) {
366 acl_d->next = 0;
369 if (acl_d->next < 0) {
370 errno = EINVAL;
371 return -1;
374 if (acl_d->next >= acl_d->count) {
375 return 0;
378 *entry_p = &acl_d->acl[acl_d->next++];
380 return 1;
383 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
385 *type_p = entry_d->a_type;
387 return 0;
391 * There is no way of knowing what size the ACL returned by
392 * GETACL will be unless you first call GETACLCNT which means
393 * making an additional system call.
395 * In the hope of avoiding the cost of the additional system
396 * call in most cases, we initially allocate enough space for
397 * an ACL with INITIAL_ACL_SIZE entries. If this turns out to
398 * be too small then we use GETACLCNT to find out the actual
399 * size, reallocate the ACL buffer, and then call GETACL again.
402 #define INITIAL_ACL_SIZE 16
404 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
406 SMB_ACL_T acl_d;
407 int count; /* # of ACL entries allocated */
408 int naccess; /* # of access ACL entries */
409 int ndefault; /* # of default ACL entries */
411 if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
412 errno = EINVAL;
413 return NULL;
416 count = INITIAL_ACL_SIZE;
417 if ((acl_d = sys_acl_init(count)) == NULL) {
418 return NULL;
422 * If there isn't enough space for the ACL entries we use
423 * GETACLCNT to determine the actual number of ACL entries
424 * reallocate and try again. This is in a loop because it
425 * is possible that someone else could modify the ACL and
426 * increase the number of entries between the call to
427 * GETACLCNT and the call to GETACL.
429 while ((count = acl(path_p, GETACL, count, &acl_d->acl[0])) < 0
430 && errno == ENOSPC) {
432 sys_acl_free_acl(acl_d);
434 if ((count = acl(path_p, GETACLCNT, 0, NULL)) < 0) {
435 return NULL;
438 if ((acl_d = sys_acl_init(count)) == NULL) {
439 return NULL;
443 if (count < 0) {
444 sys_acl_free_acl(acl_d);
445 return NULL;
449 * calculate the number of access and default ACL entries
451 * Note: we assume that the acl() system call returned a
452 * well formed ACL which is sorted so that all of the
453 * access ACL entries precede any default ACL entries
455 for (naccess = 0; naccess < count; naccess++) {
456 if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
457 break;
459 ndefault = count - naccess;
462 * if the caller wants the default ACL we have to copy
463 * the entries down to the start of the acl[] buffer
464 * and mask out the ACL_DEFAULT flag from the type field
466 if (type == SMB_ACL_TYPE_DEFAULT) {
467 int i, j;
469 for (i = 0, j = naccess; i < ndefault; i++, j++) {
470 acl_d->acl[i] = acl_d->acl[j];
471 acl_d->acl[i].a_type &= ~ACL_DEFAULT;
474 acl_d->count = ndefault;
475 } else {
476 acl_d->count = naccess;
479 return acl_d;
482 #if 0
483 SMB_ACL_T sys_acl_get_fd(int fd)
485 SMB_ACL_T acl_d;
486 int count; /* # of ACL entries allocated */
487 int naccess; /* # of access ACL entries */
489 count = INITIAL_ACL_SIZE;
490 if ((acl_d = sys_acl_init(count)) == NULL) {
491 return NULL;
494 while ((count = facl(fd, GETACL, count, &acl_d->acl[0])) < 0
495 && errno == ENOSPC) {
497 sys_acl_free_acl(acl_d);
499 if ((count = facl(fd, GETACLCNT, 0, NULL)) < 0) {
500 return NULL;
503 if ((acl_d = sys_acl_init(count)) == NULL) {
504 return NULL;
508 if (count < 0) {
509 sys_acl_free_acl(acl_d);
510 return NULL;
514 * calculate the number of access ACL entries
516 for (naccess = 0; naccess < count; naccess++) {
517 if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
518 break;
521 acl_d->count = naccess;
523 return acl_d;
525 #endif
527 int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *bits_p, id_t *u_g_id_p)
529 *tag_type_p = entry->a_type;
531 *bits_p = entry->a_perm;
533 if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP)
534 *u_g_id_p = entry->a_id;
536 return 0;
539 SMB_ACL_T sys_acl_init(int count)
541 SMB_ACL_T a;
543 if (count < 0) {
544 errno = EINVAL;
545 return NULL;
549 * note that since the definition of the structure pointed
550 * to by the SMB_ACL_T includes the first element of the
551 * acl[] array, this actually allocates an ACL with room
552 * for (count+1) entries
554 if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof a[0] + count * sizeof (struct acl))) == NULL) {
555 errno = ENOMEM;
556 return NULL;
559 a->size = count + 1;
560 a->count = 0;
561 a->next = -1;
563 return a;
567 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
569 SMB_ACL_T acl_d;
570 SMB_ACL_ENTRY_T entry_d;
572 if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
573 errno = EINVAL;
574 return -1;
577 if (acl_d->count >= acl_d->size) {
578 errno = ENOSPC;
579 return -1;
582 entry_d = &acl_d->acl[acl_d->count++];
583 entry_d->a_type = 0;
584 entry_d->a_id = -1;
585 entry_d->a_perm = 0;
586 *entry_p = entry_d;
588 return 0;
591 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
593 entry->a_type = tag_type;
595 if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP)
596 entry->a_id = u_g_id;
598 entry->a_perm = bits;
600 return 0;
603 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry_d, uint32 bits)
605 entry_d->a_perm = bits;
606 return 0;
610 * sort the ACL and check it for validity
612 * if it's a minimal ACL with only 4 entries then we
613 * need to recalculate the mask permissions to make
614 * sure that they are the same as the GROUP_OBJ
615 * permissions as required by the UnixWare acl() system call.
617 * (note: since POSIX allows minimal ACLs which only contain
618 * 3 entries - ie there is no mask entry - we should, in theory,
619 * check for this and add a mask entry if necessary - however
620 * we "know" that the caller of this interface always specifies
621 * a mask so, in practice "this never happens" (tm) - if it *does*
622 * happen aclsort() will fail and return an error and someone will
623 * have to fix it ...)
626 static int acl_sort(SMB_ACL_T acl_d)
628 int fixmask = (acl_d->count <= 4);
630 if (aclsort(acl_d->count, fixmask, acl_d->acl) != 0) {
631 errno = EINVAL;
632 return -1;
634 return 0;
637 int sys_acl_valid(SMB_ACL_T acl_d)
639 return acl_sort(acl_d);
642 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
644 struct stat s;
645 struct acl *acl_p;
646 int acl_count;
647 struct acl *acl_buf = NULL;
648 int ret;
650 if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
651 errno = EINVAL;
652 return -1;
655 if (acl_sort(acl_d) != 0) {
656 return -1;
659 acl_p = &acl_d->acl[0];
660 acl_count = acl_d->count;
663 * if it's a directory there is extra work to do
664 * since the acl() system call will replace both
665 * the access ACLs and the default ACLs (if any)
667 if (stat(name, &s) != 0) {
668 return -1;
670 if (S_ISDIR(s.st_mode)) {
671 SMB_ACL_T acc_acl;
672 SMB_ACL_T def_acl;
673 SMB_ACL_T tmp_acl;
674 int i;
676 if (type == SMB_ACL_TYPE_ACCESS) {
677 acc_acl = acl_d;
678 def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
680 } else {
681 def_acl = acl_d;
682 acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
685 if (tmp_acl == NULL) {
686 return -1;
690 * allocate a temporary buffer for the complete ACL
692 acl_count = acc_acl->count + def_acl->count;
693 acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count);
695 if (acl_buf == NULL) {
696 sys_acl_free_acl(tmp_acl);
697 errno = ENOMEM;
698 return -1;
702 * copy the access control and default entries into the buffer
704 memcpy(&acl_buf[0], &acc_acl->acl[0],
705 acc_acl->count * sizeof acl_buf[0]);
707 memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
708 def_acl->count * sizeof acl_buf[0]);
711 * set the ACL_DEFAULT flag on the default entries
713 for (i = acc_acl->count; i < acl_count; i++) {
714 acl_buf[i].a_type |= ACL_DEFAULT;
717 sys_acl_free_acl(tmp_acl);
719 } else if (type != SMB_ACL_TYPE_ACCESS) {
720 errno = EINVAL;
721 return -1;
724 ret = acl(name, SETACL, acl_count, acl_p);
726 SAFE_FREE(acl_buf);
728 return ret;
731 #if 0
732 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
734 if (acl_sort(acl_d) != 0) {
735 return -1;
738 return facl(fd, SETACL, acl_d->count, &acl_d->acl[0]);
740 #endif
742 int sys_acl_delete_def_file(const char *path)
744 SMB_ACL_T acl_d;
745 int ret;
748 * fetching the access ACL and rewriting it has
749 * the effect of deleting the default ACL
751 if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
752 return -1;
755 ret = acl(path, SETACL, acl_d->count, acl_d->acl);
757 sys_acl_free_acl(acl_d);
759 return ret;
762 int sys_acl_free_acl(SMB_ACL_T acl_d)
764 SAFE_FREE(acl_d);
765 return 0;
768 #elif defined(HAVE_HPUX_ACLS) /*---------------------------------------------*/
770 #ifdef HAVE_DL_H
771 #include <dl.h>
772 #endif
775 * Based on the Solaris/SCO code - with modifications.
779 * Note that while this code implements sufficient functionality
780 * to support the sys_acl_* interfaces it does not provide all
781 * of the semantics of the POSIX ACL interfaces.
783 * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
784 * from a call to sys_acl_get_entry() should not be assumed to be
785 * valid after calling any of the following functions, which may
786 * reorder the entries in the ACL.
788 * sys_acl_valid()
789 * sys_acl_set_file()
790 * sys_acl_set_fd()
793 /* This checks if the POSIX ACL system call is defined */
794 /* which basically corresponds to whether JFS 3.3 or */
795 /* higher is installed. If acl() was called when it */
796 /* isn't defined, it causes the process to core dump */
797 /* so it is important to check this and avoid acl() */
798 /* calls if it isn't there. */
800 #ifdef __TANDEM
801 inline int do_acl(const char *path_p, int cmd, int nentries, struct acl *aclbufp)
803 return acl((char*)path_p, cmd, nentries, aclbufp);
805 #define acl(p,c,n,a) do_acl(p,c,n,a)
806 #endif
808 static BOOL hpux_acl_call_presence(void)
810 #ifndef __TANDEM
811 shl_t handle = NULL;
812 void *value;
813 int ret_val=0;
814 static BOOL already_checked=0;
816 if (already_checked)
817 return True;
819 ret_val = shl_findsym(&handle, "acl", TYPE_PROCEDURE, &value);
821 if (ret_val != 0) {
822 DEBUG(5, ("hpux_acl_call_presence: shl_findsym() returned %d, errno = %d, error %s\n",
823 ret_val, errno, strerror(errno)));
824 DEBUG(5, ("hpux_acl_call_presence: acl() system call is not present. Check if you have JFS 3.3 and above?\n"));
825 return False;
828 DEBUG(10, ("hpux_acl_call_presence: acl() system call is present. We have JFS 3.3 or above \n"));
830 already_checked = True;
831 #endif
832 return True;
835 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
837 if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
838 errno = EINVAL;
839 return -1;
842 if (entry_p == NULL) {
843 errno = EINVAL;
844 return -1;
847 if (entry_id == SMB_ACL_FIRST_ENTRY) {
848 acl_d->next = 0;
851 if (acl_d->next < 0) {
852 errno = EINVAL;
853 return -1;
856 if (acl_d->next >= acl_d->count) {
857 return 0;
860 *entry_p = &acl_d->acl[acl_d->next++];
862 return 1;
865 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
867 *type_p = entry_d->a_type;
869 return 0;
873 * There is no way of knowing what size the ACL returned by
874 * ACL_GET will be unless you first call ACL_CNT which means
875 * making an additional system call.
877 * In the hope of avoiding the cost of the additional system
878 * call in most cases, we initially allocate enough space for
879 * an ACL with INITIAL_ACL_SIZE entries. If this turns out to
880 * be too small then we use ACL_CNT to find out the actual
881 * size, reallocate the ACL buffer, and then call ACL_GET again.
884 #define INITIAL_ACL_SIZE 16
886 #ifndef NACLENTRIES
887 #define NACLENTRIES 0
888 #endif
890 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
892 SMB_ACL_T acl_d;
893 int count; /* # of ACL entries allocated */
894 int naccess; /* # of access ACL entries */
895 int ndefault; /* # of default ACL entries */
897 if (hpux_acl_call_presence() == False) {
898 /* Looks like we don't have the acl() system call on HPUX.
899 * May be the system doesn't have the latest version of JFS.
901 return NULL;
904 if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
905 errno = EINVAL;
906 return NULL;
909 count = INITIAL_ACL_SIZE;
910 if ((acl_d = sys_acl_init(count)) == NULL) {
911 return NULL;
915 * If there isn't enough space for the ACL entries we use
916 * ACL_CNT to determine the actual number of ACL entries
917 * reallocate and try again. This is in a loop because it
918 * is possible that someone else could modify the ACL and
919 * increase the number of entries between the call to
920 * ACL_CNT and the call to ACL_GET.
922 while ((count = acl(path_p, ACL_GET, count, &acl_d->acl[0])) < 0 && errno == ENOSPC) {
924 sys_acl_free_acl(acl_d);
926 if ((count = acl(path_p, ACL_CNT, NACLENTRIES, NULL)) < 0) {
927 return NULL;
930 if ((acl_d = sys_acl_init(count)) == NULL) {
931 return NULL;
935 if (count < 0) {
936 sys_acl_free_acl(acl_d);
937 return NULL;
941 * calculate the number of access and default ACL entries
943 * Note: we assume that the acl() system call returned a
944 * well formed ACL which is sorted so that all of the
945 * access ACL entries precede any default ACL entries
947 for (naccess = 0; naccess < count; naccess++) {
948 if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
949 break;
951 ndefault = count - naccess;
954 * if the caller wants the default ACL we have to copy
955 * the entries down to the start of the acl[] buffer
956 * and mask out the ACL_DEFAULT flag from the type field
958 if (type == SMB_ACL_TYPE_DEFAULT) {
959 int i, j;
961 for (i = 0, j = naccess; i < ndefault; i++, j++) {
962 acl_d->acl[i] = acl_d->acl[j];
963 acl_d->acl[i].a_type &= ~ACL_DEFAULT;
966 acl_d->count = ndefault;
967 } else {
968 acl_d->count = naccess;
971 return acl_d;
974 #if 0
975 SMB_ACL_T sys_acl_get_fd(int fd)
978 * HPUX doesn't have the facl call. Fake it using the path.... JRA.
981 files_struct *fsp = file_find_fd(fd);
983 if (fsp == NULL) {
984 errno = EBADF;
985 return NULL;
989 * We know we're in the same conn context. So we
990 * can use the relative path.
993 return sys_acl_get_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
995 #endif
997 int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *bits_p, id_t *u_g_id_p)
999 *tag_type_p = entry->a_type;
1001 *bits_p = entry->a_perm;
1003 if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP)
1004 *u_g_id_p = entry->a_id;
1006 return 0;
1009 SMB_ACL_T sys_acl_init(int count)
1011 SMB_ACL_T a;
1013 if (count < 0) {
1014 errno = EINVAL;
1015 return NULL;
1019 * note that since the definition of the structure pointed
1020 * to by the SMB_ACL_T includes the first element of the
1021 * acl[] array, this actually allocates an ACL with room
1022 * for (count+1) entries
1024 if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof a[0] + count * sizeof (struct acl))) == NULL) {
1025 errno = ENOMEM;
1026 return NULL;
1029 a->size = count + 1;
1030 a->count = 0;
1031 a->next = -1;
1033 return a;
1037 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
1039 SMB_ACL_T acl_d;
1040 SMB_ACL_ENTRY_T entry_d;
1042 if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
1043 errno = EINVAL;
1044 return -1;
1047 if (acl_d->count >= acl_d->size) {
1048 errno = ENOSPC;
1049 return -1;
1052 entry_d = &acl_d->acl[acl_d->count++];
1053 entry_d->a_type = 0;
1054 entry_d->a_id = -1;
1055 entry_d->a_perm = 0;
1056 *entry_p = entry_d;
1058 return 0;
1061 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
1063 entry->a_type = tag_type;
1065 if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP)
1066 entry->a_id = u_g_id;
1068 entry->a_perm = bits;
1070 return 0;
1073 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry_d, uint32 bits)
1075 entry_d->a_perm = bits;
1077 return 0;
1080 /* Structure to capture the count for each type of ACE. */
1082 struct hpux_acl_types {
1083 int n_user;
1084 int n_def_user;
1085 int n_user_obj;
1086 int n_def_user_obj;
1088 int n_group;
1089 int n_def_group;
1090 int n_group_obj;
1091 int n_def_group_obj;
1093 int n_other;
1094 int n_other_obj;
1095 int n_def_other_obj;
1097 int n_class_obj;
1098 int n_def_class_obj;
1100 int n_illegal_obj;
1103 /* count_obj:
1104 * Counts the different number of objects in a given array of ACL
1105 * structures.
1106 * Inputs:
1108 * acl_count - Count of ACLs in the array of ACL structures.
1109 * aclp - Array of ACL structures.
1110 * acl_type_count - Pointer to acl_types structure. Should already be
1111 * allocated.
1112 * Output:
1114 * acl_type_count - This structure is filled up with counts of various
1115 * acl types.
1118 static void hpux_count_obj(int acl_count, struct acl *aclp, struct hpux_acl_types *acl_type_count)
1120 int i;
1122 memset(acl_type_count, 0, sizeof (struct hpux_acl_types));
1124 for (i = 0; i < acl_count; i++) {
1125 switch (aclp[i].a_type) {
1126 case USER:
1127 acl_type_count->n_user++;
1128 break;
1129 case USER_OBJ:
1130 acl_type_count->n_user_obj++;
1131 break;
1132 case DEF_USER_OBJ:
1133 acl_type_count->n_def_user_obj++;
1134 break;
1135 case GROUP:
1136 acl_type_count->n_group++;
1137 break;
1138 case GROUP_OBJ:
1139 acl_type_count->n_group_obj++;
1140 break;
1141 case DEF_GROUP_OBJ:
1142 acl_type_count->n_def_group_obj++;
1143 break;
1144 case OTHER_OBJ:
1145 acl_type_count->n_other_obj++;
1146 break;
1147 case DEF_OTHER_OBJ:
1148 acl_type_count->n_def_other_obj++;
1149 break;
1150 case CLASS_OBJ:
1151 acl_type_count->n_class_obj++;
1152 break;
1153 case DEF_CLASS_OBJ:
1154 acl_type_count->n_def_class_obj++;
1155 break;
1156 case DEF_USER:
1157 acl_type_count->n_def_user++;
1158 break;
1159 case DEF_GROUP:
1160 acl_type_count->n_def_group++;
1161 break;
1162 default:
1163 acl_type_count->n_illegal_obj++;
1164 break;
1169 /* swap_acl_entries: Swaps two ACL entries.
1171 * Inputs: aclp0, aclp1 - ACL entries to be swapped.
1174 static void hpux_swap_acl_entries(struct acl *aclp0, struct acl *aclp1)
1176 struct acl temp_acl;
1178 temp_acl.a_type = aclp0->a_type;
1179 temp_acl.a_id = aclp0->a_id;
1180 temp_acl.a_perm = aclp0->a_perm;
1182 aclp0->a_type = aclp1->a_type;
1183 aclp0->a_id = aclp1->a_id;
1184 aclp0->a_perm = aclp1->a_perm;
1186 aclp1->a_type = temp_acl.a_type;
1187 aclp1->a_id = temp_acl.a_id;
1188 aclp1->a_perm = temp_acl.a_perm;
1191 /* prohibited_duplicate_type
1192 * Identifies if given ACL type can have duplicate entries or
1193 * not.
1195 * Inputs: acl_type - ACL Type.
1197 * Outputs:
1199 * Return..
1201 * True - If the ACL type matches any of the prohibited types.
1202 * False - If the ACL type doesn't match any of the prohibited types.
1205 static BOOL hpux_prohibited_duplicate_type(int acl_type)
1207 switch (acl_type) {
1208 case USER:
1209 case GROUP:
1210 case DEF_USER:
1211 case DEF_GROUP:
1212 return True;
1213 default:
1214 return False;
1218 /* get_needed_class_perm
1219 * Returns the permissions of a ACL structure only if the ACL
1220 * type matches one of the pre-determined types for computing
1221 * CLASS_OBJ permissions.
1223 * Inputs: aclp - Pointer to ACL structure.
1226 static int hpux_get_needed_class_perm(struct acl *aclp)
1228 switch (aclp->a_type) {
1229 case USER:
1230 case GROUP_OBJ:
1231 case GROUP:
1232 case DEF_USER_OBJ:
1233 case DEF_USER:
1234 case DEF_GROUP_OBJ:
1235 case DEF_GROUP:
1236 case DEF_CLASS_OBJ:
1237 case DEF_OTHER_OBJ:
1238 return aclp->a_perm;
1239 default:
1240 return 0;
1244 /* acl_sort for HPUX.
1245 * Sorts the array of ACL structures as per the description in
1246 * aclsort man page. Refer to aclsort man page for more details
1248 * Inputs:
1250 * acl_count - Count of ACLs in the array of ACL structures.
1251 * calclass - If this is not zero, then we compute the CLASS_OBJ
1252 * permissions.
1253 * aclp - Array of ACL structures.
1255 * Outputs:
1257 * aclp - Sorted array of ACL structures.
1259 * Outputs:
1261 * Returns 0 for success -1 for failure. Prints a message to the Samba
1262 * debug log in case of failure.
1265 static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp)
1267 #if !defined(HAVE_HPUX_ACLSORT)
1269 * The aclsort() system call is available on the latest HPUX General
1270 * Patch Bundles. So for HPUX, we developed our version of acl_sort
1271 * function. Because, we don't want to update to a new
1272 * HPUX GR bundle just for aclsort() call.
1275 struct hpux_acl_types acl_obj_count;
1276 int n_class_obj_perm = 0;
1277 int i, j;
1279 if (!acl_count) {
1280 DEBUG(10, ("Zero acl count passed. Returning Success\n"));
1281 return 0;
1284 if (aclp == NULL) {
1285 DEBUG(0, ("Null ACL pointer in hpux_acl_sort. Returning Failure. \n"));
1286 return -1;
1289 /* Count different types of ACLs in the ACLs array */
1291 hpux_count_obj(acl_count, aclp, &acl_obj_count);
1293 /* There should be only one entry each of type USER_OBJ, GROUP_OBJ,
1294 * CLASS_OBJ and OTHER_OBJ
1297 if (acl_obj_count.n_user_obj != 1
1298 || acl_obj_count.n_group_obj != 1
1299 || acl_obj_count.n_class_obj != 1
1300 || acl_obj_count.n_other_obj != 1) {
1301 DEBUG(0, ("hpux_acl_sort: More than one entry or no entries for \
1302 USER OBJ or GROUP_OBJ or OTHER_OBJ or CLASS_OBJ\n"));
1303 return -1;
1306 /* If any of the default objects are present, there should be only
1307 * one of them each.
1309 if (acl_obj_count.n_def_user_obj > 1 || acl_obj_count.n_def_group_obj > 1
1310 || acl_obj_count.n_def_other_obj > 1 || acl_obj_count.n_def_class_obj > 1) {
1311 DEBUG(0, ("hpux_acl_sort: More than one entry for DEF_CLASS_OBJ \
1312 or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n"));
1313 return -1;
1316 /* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl
1317 * structures.
1319 * Sorting crieteria - First sort by ACL type. If there are multiple entries of
1320 * same ACL type, sort by ACL id.
1322 * I am using the trivial kind of sorting method here because, performance isn't
1323 * really effected by the ACLs feature. More over there aren't going to be more
1324 * than 17 entries on HPUX.
1327 for (i = 0; i < acl_count; i++) {
1328 for (j = i+1; j < acl_count; j++) {
1329 if (aclp[i].a_type > aclp[j].a_type) {
1330 /* ACL entries out of order, swap them */
1331 hpux_swap_acl_entries((aclp+i), (aclp+j));
1332 } else if (aclp[i].a_type == aclp[j].a_type) {
1333 /* ACL entries of same type, sort by id */
1334 if (aclp[i].a_id > aclp[j].a_id) {
1335 hpux_swap_acl_entries((aclp+i), (aclp+j));
1336 } else if (aclp[i].a_id == aclp[j].a_id) {
1337 /* We have a duplicate entry. */
1338 if (hpux_prohibited_duplicate_type(aclp[i].a_type)) {
1339 DEBUG(0, ("hpux_acl_sort: Duplicate entry: Type(hex): %x Id: %d\n",
1340 aclp[i].a_type, aclp[i].a_id));
1341 return -1;
1348 /* set the class obj permissions to the computed one. */
1349 if (calclass) {
1350 int n_class_obj_index = -1;
1352 for (i = 0;i < acl_count; i++) {
1353 n_class_obj_perm |= hpux_get_needed_class_perm((aclp+i));
1354 if (aclp[i].a_type == CLASS_OBJ)
1355 n_class_obj_index = i;
1357 aclp[n_class_obj_index].a_perm = n_class_obj_perm;
1360 return 0;
1361 #else
1362 return aclsort(acl_count, calclass, aclp);
1363 #endif
1367 * sort the ACL and check it for validity
1369 * if it's a minimal ACL with only 4 entries then we
1370 * need to recalculate the mask permissions to make
1371 * sure that they are the same as the GROUP_OBJ
1372 * permissions as required by the UnixWare acl() system call.
1374 * (note: since POSIX allows minimal ACLs which only contain
1375 * 3 entries - ie there is no mask entry - we should, in theory,
1376 * check for this and add a mask entry if necessary - however
1377 * we "know" that the caller of this interface always specifies
1378 * a mask so, in practice "this never happens" (tm) - if it *does*
1379 * happen aclsort() will fail and return an error and someone will
1380 * have to fix it ...)
1383 static int acl_sort(SMB_ACL_T acl_d)
1385 int fixmask = (acl_d->count <= 4);
1387 if (hpux_acl_sort(acl_d->count, fixmask, acl_d->acl) != 0) {
1388 errno = EINVAL;
1389 return -1;
1391 return 0;
1394 int sys_acl_valid(SMB_ACL_T acl_d)
1396 return acl_sort(acl_d);
1399 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
1401 struct stat s;
1402 struct acl *acl_p;
1403 int acl_count;
1404 struct acl *acl_buf = NULL;
1405 int ret;
1407 if (hpux_acl_call_presence() == False) {
1408 /* Looks like we don't have the acl() system call on HPUX.
1409 * May be the system doesn't have the latest version of JFS.
1411 errno=ENOSYS;
1412 return -1;
1415 if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
1416 errno = EINVAL;
1417 return -1;
1420 if (acl_sort(acl_d) != 0) {
1421 return -1;
1424 acl_p = &acl_d->acl[0];
1425 acl_count = acl_d->count;
1428 * if it's a directory there is extra work to do
1429 * since the acl() system call will replace both
1430 * the access ACLs and the default ACLs (if any)
1432 if (stat(name, &s) != 0) {
1433 return -1;
1435 if (S_ISDIR(s.st_mode)) {
1436 SMB_ACL_T acc_acl;
1437 SMB_ACL_T def_acl;
1438 SMB_ACL_T tmp_acl;
1439 int i;
1441 if (type == SMB_ACL_TYPE_ACCESS) {
1442 acc_acl = acl_d;
1443 def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
1445 } else {
1446 def_acl = acl_d;
1447 acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
1450 if (tmp_acl == NULL) {
1451 return -1;
1455 * allocate a temporary buffer for the complete ACL
1457 acl_count = acc_acl->count + def_acl->count;
1458 acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count);
1460 if (acl_buf == NULL) {
1461 sys_acl_free_acl(tmp_acl);
1462 errno = ENOMEM;
1463 return -1;
1467 * copy the access control and default entries into the buffer
1469 memcpy(&acl_buf[0], &acc_acl->acl[0],
1470 acc_acl->count * sizeof acl_buf[0]);
1472 memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
1473 def_acl->count * sizeof acl_buf[0]);
1476 * set the ACL_DEFAULT flag on the default entries
1478 for (i = acc_acl->count; i < acl_count; i++) {
1479 acl_buf[i].a_type |= ACL_DEFAULT;
1482 sys_acl_free_acl(tmp_acl);
1484 } else if (type != SMB_ACL_TYPE_ACCESS) {
1485 errno = EINVAL;
1486 return -1;
1489 ret = acl(name, ACL_SET, acl_count, acl_p);
1491 if (acl_buf) {
1492 free(acl_buf);
1495 return ret;
1498 #if 0
1499 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
1502 * HPUX doesn't have the facl call. Fake it using the path.... JRA.
1505 files_struct *fsp = file_find_fd(fd);
1507 if (fsp == NULL) {
1508 errno = EBADF;
1509 return NULL;
1512 if (acl_sort(acl_d) != 0) {
1513 return -1;
1517 * We know we're in the same conn context. So we
1518 * can use the relative path.
1521 return sys_acl_set_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS, acl_d);
1523 #endif
1525 int sys_acl_delete_def_file(const char *path)
1527 SMB_ACL_T acl_d;
1528 int ret;
1531 * fetching the access ACL and rewriting it has
1532 * the effect of deleting the default ACL
1534 if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
1535 return -1;
1538 ret = acl(path, ACL_SET, acl_d->count, acl_d->acl);
1540 sys_acl_free_acl(acl_d);
1542 return ret;
1545 int sys_acl_free_acl(SMB_ACL_T acl_d)
1547 free(acl_d);
1548 return 0;
1551 #elif defined(HAVE_IRIX_ACLS) /*---------------------------------------------*/
1553 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
1555 if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
1556 errno = EINVAL;
1557 return -1;
1560 if (entry_p == NULL) {
1561 errno = EINVAL;
1562 return -1;
1565 if (entry_id == SMB_ACL_FIRST_ENTRY) {
1566 acl_d->next = 0;
1569 if (acl_d->next < 0) {
1570 errno = EINVAL;
1571 return -1;
1574 if (acl_d->next >= acl_d->aclp->acl_cnt) {
1575 return 0;
1578 *entry_p = &acl_d->aclp->acl_entry[acl_d->next++];
1580 return 1;
1583 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
1585 *type_p = entry_d->ae_tag;
1587 return 0;
1590 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
1592 SMB_ACL_T a;
1594 if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) {
1595 errno = ENOMEM;
1596 return NULL;
1598 if ((a->aclp = acl_get_file(path_p, type)) == NULL) {
1599 SAFE_FREE(a);
1600 return NULL;
1602 a->next = -1;
1603 a->freeaclp = True;
1604 return a;
1607 #if 0
1608 SMB_ACL_T sys_acl_get_fd(int fd)
1610 SMB_ACL_T a;
1612 if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) {
1613 errno = ENOMEM;
1614 return NULL;
1616 if ((a->aclp = acl_get_fd(fd)) == NULL) {
1617 SAFE_FREE(a);
1618 return NULL;
1620 a->next = -1;
1621 a->freeaclp = True;
1622 return a;
1624 #endif
1626 int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *bits_p, id_t *u_g_id_p)
1628 *tag_type_p = entry->ae_tag;
1630 *bits_p = entry->ae_perm;
1632 if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP)
1633 *u_g_id_p = entry->ae_id;
1635 return 0;
1638 SMB_ACL_T sys_acl_init(int count)
1640 SMB_ACL_T a;
1642 if (count < 0) {
1643 errno = EINVAL;
1644 return NULL;
1647 if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof a[0] + sizeof (struct acl))) == NULL) {
1648 errno = ENOMEM;
1649 return NULL;
1652 a->next = -1;
1653 a->freeaclp = False;
1654 a->aclp = (struct acl *)((char *)a + sizeof a[0]);
1655 a->aclp->acl_cnt = 0;
1657 return a;
1661 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
1663 SMB_ACL_T acl_d;
1664 SMB_ACL_ENTRY_T entry_d;
1666 if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
1667 errno = EINVAL;
1668 return -1;
1671 if (acl_d->aclp->acl_cnt >= ACL_MAX_ENTRIES) {
1672 errno = ENOSPC;
1673 return -1;
1676 entry_d = &acl_d->aclp->acl_entry[acl_d->aclp->acl_cnt++];
1677 entry_d->ae_tag = 0;
1678 entry_d->ae_id = 0;
1679 entry_d->ae_perm = 0;
1680 *entry_p = entry_d;
1682 return 0;
1685 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
1687 entry->ae_tag = tag_type;
1689 if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP)
1690 entry->ae_id = u_g_id;
1692 entry->ae_perm = bits;
1694 return 0;
1697 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry_d, uint32 bits)
1699 entry_d->ae_perm = bits;
1701 return 0;
1704 int sys_acl_valid(SMB_ACL_T acl_d)
1706 return acl_valid(acl_d->aclp);
1709 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
1711 return acl_set_file(name, type, acl_d->aclp);
1714 #if 0
1715 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
1717 return acl_set_fd(fd, acl_d->aclp);
1719 #endif
1721 int sys_acl_delete_def_file(const char *name)
1723 return acl_delete_def_file(name);
1726 int sys_acl_free_acl(SMB_ACL_T acl_d)
1728 if (acl_d->freeaclp) {
1729 acl_free(acl_d->aclp);
1731 acl_free(acl_d);
1732 return 0;
1735 #elif defined(HAVE_AIX_ACLS) /*----------------------------------------------*/
1737 /* Donated by Medha Date, mdate@austin.ibm.com, for IBM */
1739 int sys_acl_get_entry(SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
1741 struct acl_entry_link *link;
1742 int keep_going;
1744 if (entry_id == SMB_ACL_FIRST_ENTRY)
1745 theacl->count = 0;
1746 else if (entry_id != SMB_ACL_NEXT_ENTRY) {
1747 errno = EINVAL;
1748 return -1;
1751 DEBUG(10, ("This is the count: %d\n", theacl->count));
1753 /* Check if count was previously set to -1. *
1754 * If it was, that means we reached the end *
1755 * of the acl last time. */
1756 if (theacl->count == -1)
1757 return 0;
1759 link = theacl;
1760 /* To get to the next acl, traverse linked list until index *
1761 * of acl matches the count we are keeping. This count is *
1762 * incremented each time we return an acl entry. */
1764 for (keep_going = 0; keep_going < theacl->count; keep_going++)
1765 link = link->nextp;
1767 *entry_p = link->entryp;
1769 #if 0
1771 struct new_acl_entry *entry = *entry_p;
1772 DEBUG(10, ("*entry_p is %lx\n", (long)entry));
1773 DEBUG(10, ("*entry_p->ace_access is %d\n", entry->ace_access));
1775 #endif
1777 /* Increment count */
1778 theacl->count++;
1779 if (link->nextp == NULL)
1780 theacl->count = -1;
1782 return 1;
1785 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
1787 /* Initialize tag type */
1789 *tag_type_p = -1;
1790 DEBUG(10, ("the tagtype is %d\n", entry_d->ace_id->id_type));
1792 /* Depending on what type of entry we have, *
1793 * return tag type. */
1794 switch (entry_d->ace_id->id_type) {
1795 case ACEID_USER:
1796 *tag_type_p = SMB_ACL_USER;
1797 break;
1798 case ACEID_GROUP:
1799 *tag_type_p = SMB_ACL_GROUP;
1800 break;
1802 case SMB_ACL_USER_OBJ:
1803 case SMB_ACL_GROUP_OBJ:
1804 case SMB_ACL_OTHER:
1805 *tag_type_p = entry_d->ace_id->id_type;
1806 break;
1808 default:
1809 return -1;
1812 return 0;
1815 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
1817 struct acl *file_acl = (struct acl *)NULL;
1818 struct acl_entry *acl_entry;
1819 struct new_acl_entry *new_acl_entry;
1820 struct ace_id *idp;
1821 struct acl_entry_link *acl_entry_link;
1822 struct acl_entry_link *acl_entry_link_head;
1823 int i;
1824 int rc = 0;
1826 /* AIX has no DEFAULT */
1827 if (type == SMB_ACL_TYPE_DEFAULT) {
1828 #ifdef ENOTSUP
1829 errno = ENOTSUP;
1830 #else
1831 errno = ENOSYS;
1832 #endif
1833 return NULL;
1836 /* Get the acl using statacl */
1838 DEBUG(10, ("Entering sys_acl_get_file\n"));
1839 DEBUG(10, ("path_p is %s\n", path_p));
1841 file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
1843 if (file_acl == NULL) {
1844 errno=ENOMEM;
1845 DEBUG(0, ("Error in AIX sys_acl_get_file: %d\n", errno));
1846 return NULL;
1849 memset(file_acl, 0, BUFSIZ);
1851 rc = statacl((char *)path_p, 0, file_acl, BUFSIZ);
1852 if (rc == -1) {
1853 DEBUG(0, ("statacl returned %d with errno %d\n", rc, errno));
1854 SAFE_FREE(file_acl);
1855 return NULL;
1858 DEBUG(10, ("Got facl and returned it\n"));
1860 /* Point to the first acl entry in the acl */
1861 acl_entry = file_acl->acl_ext;
1863 /* Begin setting up the head of the linked list *
1864 * that will be used for the storing the acl *
1865 * in a way that is useful for the posix_acls.c *
1866 * code. */
1868 acl_entry_link_head = acl_entry_link = sys_acl_init(0);
1869 if (acl_entry_link_head == NULL)
1870 return NULL;
1872 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
1873 if (acl_entry_link->entryp == NULL) {
1874 SAFE_FREE(file_acl);
1875 errno = ENOMEM;
1876 DEBUG(0, ("Error in AIX sys_acl_get_file is %d\n", errno));
1877 return NULL;
1880 DEBUG(10, ("acl_entry is %d\n", acl_entry));
1881 DEBUG(10, ("acl_last(file_acl) id %d\n", acl_last(file_acl)));
1883 /* Check if the extended acl bit is on. *
1884 * If it isn't, do not show the *
1885 * contents of the acl since AIX intends *
1886 * the extended info to remain unused */
1888 if (file_acl->acl_mode & S_IXACL){
1889 /* while we are not pointing to the very end */
1890 while (acl_entry < acl_last(file_acl)) {
1891 /* before we malloc anything, make sure this is */
1892 /* a valid acl entry and one that we want to map */
1893 idp = id_nxt(acl_entry->ace_id);
1894 if ((acl_entry->ace_type == ACC_SPECIFY || acl_entry->ace_type == ACC_PERMIT)
1895 && idp != id_last(acl_entry)) {
1896 acl_entry = acl_nxt(acl_entry);
1897 continue;
1900 idp = acl_entry->ace_id;
1902 /* Check if this is the first entry in the linked list. *
1903 * The first entry needs to keep prevp pointing to NULL *
1904 * and already has entryp allocated. */
1906 if (acl_entry_link_head->count != 0) {
1907 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
1909 if (acl_entry_link->nextp == NULL) {
1910 SAFE_FREE(file_acl);
1911 errno = ENOMEM;
1912 DEBUG(0, ("Error in AIX sys_acl_get_file is %d\n", errno));
1913 return NULL;
1916 acl_entry_link->nextp->prevp = acl_entry_link;
1917 acl_entry_link = acl_entry_link->nextp;
1918 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
1919 if (acl_entry_link->entryp == NULL) {
1920 SAFE_FREE(file_acl);
1921 errno = ENOMEM;
1922 DEBUG(0, ("Error in AIX sys_acl_get_file is %d\n", errno));
1923 return NULL;
1925 acl_entry_link->nextp = NULL;
1928 acl_entry_link->entryp->ace_len = acl_entry->ace_len;
1930 /* Don't really need this since all types are going *
1931 * to be specified but, it's better than leaving it 0 */
1933 acl_entry_link->entryp->ace_type = acl_entry->ace_type;
1935 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
1937 memcpy(acl_entry_link->entryp->ace_id, idp, sizeof (struct ace_id));
1939 /* The access in the acl entries must be left shifted by *
1940 * three bites, because they will ultimately be compared *
1941 * to S_IRUSR, S_IWUSR, and S_IXUSR. */
1943 switch (acl_entry->ace_type){
1944 case ACC_PERMIT:
1945 case ACC_SPECIFY:
1946 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
1947 acl_entry_link->entryp->ace_access <<= 6;
1948 acl_entry_link_head->count++;
1949 break;
1950 case ACC_DENY:
1951 /* Since there is no way to return a DENY acl entry *
1952 * change to PERMIT and then shift. */
1953 DEBUG(10, ("acl_entry->ace_access is %d\n", acl_entry->ace_access));
1954 acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
1955 DEBUG(10, ("acl_entry_link->entryp->ace_access is %d\n", acl_entry_link->entryp->ace_access));
1956 acl_entry_link->entryp->ace_access <<= 6;
1957 acl_entry_link_head->count++;
1958 break;
1959 default:
1960 return 0;
1963 DEBUG(10, ("acl_entry = %d\n", acl_entry));
1964 DEBUG(10, ("The ace_type is %d\n", acl_entry->ace_type));
1966 acl_entry = acl_nxt(acl_entry);
1968 } /* end of if enabled */
1970 /* Since owner, group, other acl entries are not *
1971 * part of the acl entries in an acl, they must *
1972 * be dummied up to become part of the list. */
1974 for (i = 1; i < 4; i++) {
1975 DEBUG(10, ("i is %d\n", i));
1976 if (acl_entry_link_head->count != 0) {
1977 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
1978 if (acl_entry_link->nextp == NULL) {
1979 SAFE_FREE(file_acl);
1980 errno = ENOMEM;
1981 DEBUG(0, ("Error in AIX sys_acl_get_file is %d\n", errno));
1982 return NULL;
1985 acl_entry_link->nextp->prevp = acl_entry_link;
1986 acl_entry_link = acl_entry_link->nextp;
1987 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
1988 if (acl_entry_link->entryp == NULL) {
1989 SAFE_FREE(file_acl);
1990 errno = ENOMEM;
1991 DEBUG(0, ("Error in AIX sys_acl_get_file is %d\n", errno));
1992 return NULL;
1996 acl_entry_link->nextp = NULL;
1998 new_acl_entry = acl_entry_link->entryp;
1999 idp = new_acl_entry->ace_id;
2001 new_acl_entry->ace_len = sizeof (struct acl_entry);
2002 new_acl_entry->ace_type = ACC_PERMIT;
2003 idp->id_len = sizeof (struct ace_id);
2004 DEBUG(10, ("idp->id_len = %d\n", idp->id_len));
2005 memset(idp->id_data, 0, sizeof (uid_t));
2007 switch (i) {
2008 case 2:
2009 new_acl_entry->ace_access = file_acl->g_access << 6;
2010 idp->id_type = SMB_ACL_GROUP_OBJ;
2011 break;
2013 case 3:
2014 new_acl_entry->ace_access = file_acl->o_access << 6;
2015 idp->id_type = SMB_ACL_OTHER;
2016 break;
2018 case 1:
2019 new_acl_entry->ace_access = file_acl->u_access << 6;
2020 idp->id_type = SMB_ACL_USER_OBJ;
2021 break;
2023 default:
2024 return NULL;
2028 acl_entry_link_head->count++;
2029 DEBUG(10, ("new_acl_entry->ace_access = %d\n", new_acl_entry->ace_access));
2032 acl_entry_link_head->count = 0;
2033 SAFE_FREE(file_acl);
2035 return acl_entry_link_head;
2038 #if 0
2039 SMB_ACL_T sys_acl_get_fd(int fd)
2041 struct acl *file_acl = (struct acl *)NULL;
2042 struct acl_entry *acl_entry;
2043 struct new_acl_entry *new_acl_entry;
2044 struct ace_id *idp;
2045 struct acl_entry_link *acl_entry_link;
2046 struct acl_entry_link *acl_entry_link_head;
2047 int i;
2048 int rc = 0;
2050 /* Get the acl using fstatacl */
2052 DEBUG(10, ("Entering sys_acl_get_fd\n"));
2053 DEBUG(10, ("fd is %d\n", fd));
2054 file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2056 if (file_acl == NULL) {
2057 errno=ENOMEM;
2058 DEBUG(0, ("Error in sys_acl_get_fd is %d\n", errno));
2059 return NULL;
2062 memset(file_acl, 0, BUFSIZ);
2064 rc = fstatacl(fd, 0, file_acl, BUFSIZ);
2065 if (rc == -1) {
2066 DEBUG(0, ("The fstatacl call returned %d with errno %d\n", rc, errno));
2067 SAFE_FREE(file_acl);
2068 return NULL;
2071 DEBUG(10, ("Got facl and returned it\n"));
2073 /* Point to the first acl entry in the acl */
2075 acl_entry = file_acl->acl_ext;
2076 /* Begin setting up the head of the linked list *
2077 * that will be used for the storing the acl *
2078 * in a way that is useful for the posix_acls.c *
2079 * code. */
2081 acl_entry_link_head = acl_entry_link = sys_acl_init(0);
2082 if (acl_entry_link_head == NULL){
2083 SAFE_FREE(file_acl);
2084 return NULL;
2087 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2089 if (acl_entry_link->entryp == NULL) {
2090 errno = ENOMEM;
2091 DEBUG(0, ("Error in sys_acl_get_fd is %d\n", errno));
2092 SAFE_FREE(file_acl);
2093 return NULL;
2096 DEBUG(10, ("acl_entry is %d\n", acl_entry));
2097 DEBUG(10, ("acl_last(file_acl) id %d\n", acl_last(file_acl)));
2099 /* Check if the extended acl bit is on. *
2100 * If it isn't, do not show the *
2101 * contents of the acl since AIX intends *
2102 * the extended info to remain unused */
2104 if (file_acl->acl_mode & S_IXACL){
2105 /* while we are not pointing to the very end */
2106 while (acl_entry < acl_last(file_acl)) {
2107 /* before we malloc anything, make sure this is */
2108 /* a valid acl entry and one that we want to map */
2110 idp = id_nxt(acl_entry->ace_id);
2111 if ((acl_entry->ace_type == ACC_SPECIFY ||
2112 (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
2113 acl_entry = acl_nxt(acl_entry);
2114 continue;
2117 idp = acl_entry->ace_id;
2119 /* Check if this is the first entry in the linked list. *
2120 * The first entry needs to keep prevp pointing to NULL *
2121 * and already has entryp allocated. */
2123 if (acl_entry_link_head->count != 0) {
2124 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2125 if (acl_entry_link->nextp == NULL) {
2126 errno = ENOMEM;
2127 DEBUG(0, ("Error in sys_acl_get_fd is %d\n", errno));
2128 SAFE_FREE(file_acl);
2129 return NULL;
2131 acl_entry_link->nextp->prevp = acl_entry_link;
2132 acl_entry_link = acl_entry_link->nextp;
2133 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2134 if (acl_entry_link->entryp == NULL) {
2135 errno = ENOMEM;
2136 DEBUG(0, ("Error in sys_acl_get_fd is %d\n", errno));
2137 SAFE_FREE(file_acl);
2138 return NULL;
2141 acl_entry_link->nextp = NULL;
2144 acl_entry_link->entryp->ace_len = acl_entry->ace_len;
2146 /* Don't really need this since all types are going *
2147 * to be specified but, it's better than leaving it 0 */
2149 acl_entry_link->entryp->ace_type = acl_entry->ace_type;
2150 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2152 memcpy(acl_entry_link->entryp->ace_id, idp, sizeof (struct ace_id));
2154 /* The access in the acl entries must be left shifted by *
2155 * three bites, because they will ultimately be compared *
2156 * to S_IRUSR, S_IWUSR, and S_IXUSR. */
2158 switch (acl_entry->ace_type){
2159 case ACC_PERMIT:
2160 case ACC_SPECIFY:
2161 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2162 acl_entry_link->entryp->ace_access <<= 6;
2163 acl_entry_link_head->count++;
2164 break;
2165 case ACC_DENY:
2166 /* Since there is no way to return a DENY acl entry *
2167 * change to PERMIT and then shift. */
2168 DEBUG(10, ("acl_entry->ace_access is %d\n", acl_entry->ace_access));
2169 acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
2170 DEBUG(10, ("acl_entry_link->entryp->ace_access is %d\n", acl_entry_link->entryp->ace_access));
2171 acl_entry_link->entryp->ace_access <<= 6;
2172 acl_entry_link_head->count++;
2173 break;
2174 default:
2175 return 0;
2178 DEBUG(10, ("acl_entry = %d\n", acl_entry));
2179 DEBUG(10, ("The ace_type is %d\n", acl_entry->ace_type));
2181 acl_entry = acl_nxt(acl_entry);
2183 } /* end of if enabled */
2185 /* Since owner, group, other acl entries are not *
2186 * part of the acl entries in an acl, they must *
2187 * be dummied up to become part of the list. */
2189 for (i = 1; i < 4; i++) {
2190 DEBUG(10, ("i is %d\n", i));
2191 if (acl_entry_link_head->count != 0){
2192 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2193 if (acl_entry_link->nextp == NULL) {
2194 errno = ENOMEM;
2195 DEBUG(0, ("Error in sys_acl_get_fd is %d\n", errno));
2196 SAFE_FREE(file_acl);
2197 return NULL;
2200 acl_entry_link->nextp->prevp = acl_entry_link;
2201 acl_entry_link = acl_entry_link->nextp;
2202 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2204 if (acl_entry_link->entryp == NULL) {
2205 SAFE_FREE(file_acl);
2206 errno = ENOMEM;
2207 DEBUG(0, ("Error in sys_acl_get_fd is %d\n", errno));
2208 return NULL;
2212 acl_entry_link->nextp = NULL;
2214 new_acl_entry = acl_entry_link->entryp;
2215 idp = new_acl_entry->ace_id;
2217 new_acl_entry->ace_len = sizeof (struct acl_entry);
2218 new_acl_entry->ace_type = ACC_PERMIT;
2219 idp->id_len = sizeof (struct ace_id);
2220 DEBUG(10, ("idp->id_len = %d\n", idp->id_len));
2221 memset(idp->id_data, 0, sizeof (uid_t));
2223 switch (i) {
2224 case 2:
2225 new_acl_entry->ace_access = file_acl->g_access << 6;
2226 idp->id_type = SMB_ACL_GROUP_OBJ;
2227 break;
2229 case 3:
2230 new_acl_entry->ace_access = file_acl->o_access << 6;
2231 idp->id_type = SMB_ACL_OTHER;
2232 break;
2234 case 1:
2235 new_acl_entry->ace_access = file_acl->u_access << 6;
2236 idp->id_type = SMB_ACL_USER_OBJ;
2237 break;
2239 default:
2240 return NULL;
2243 acl_entry_link_head->count++;
2244 DEBUG(10, ("new_acl_entry->ace_access = %d\n", new_acl_entry->ace_access));
2247 acl_entry_link_head->count = 0;
2248 SAFE_FREE(file_acl);
2250 return acl_entry_link_head;
2252 #endif
2254 int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *bits_p, id_t *u_g_id_p)
2256 uint *permset;
2258 if (sys_acl_get_tag_type(entry, tag_type_p) != 0)
2259 return -1;
2261 if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP)
2262 memcpy(u_g_id_p, entry->ace_id->id_data, sizeof (id_t));
2264 permset = &entry->ace_access;
2266 DEBUG(10, ("*permset is %d\n", *permset));
2267 *bits_p = (*permset & S_IRUSR ? 4 : 0)
2268 | (*permset & S_IWUSR ? 2 : 0)
2269 | (*permset & S_IXUSR ? 1 : 0);
2271 return 0;
2274 SMB_ACL_T sys_acl_init(int count)
2276 struct acl_entry_link *theacl = NULL;
2278 if (count < 0) {
2279 errno = EINVAL;
2280 return NULL;
2283 DEBUG(10, ("Entering sys_acl_init\n"));
2285 theacl = SMB_MALLOC_P(struct acl_entry_link);
2286 if (theacl == NULL) {
2287 errno = ENOMEM;
2288 DEBUG(0, ("Error in sys_acl_init is %d\n", errno));
2289 return NULL;
2292 theacl->count = 0;
2293 theacl->nextp = NULL;
2294 theacl->prevp = NULL;
2295 theacl->entryp = NULL;
2296 DEBUG(10, ("Exiting sys_acl_init\n"));
2297 return theacl;
2300 int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
2302 struct acl_entry_link *theacl;
2303 struct acl_entry_link *acl_entryp;
2304 struct acl_entry_link *temp_entry = NULL;
2305 int counting;
2307 DEBUG(10, ("Entering the sys_acl_create_entry\n"));
2309 theacl = acl_entryp = *pacl;
2311 /* Get to the end of the acl before adding entry */
2313 for (counting = 0; counting < theacl->count; counting++){
2314 DEBUG(10, ("The acl_entryp is %d\n", acl_entryp));
2315 temp_entry = acl_entryp;
2316 acl_entryp = acl_entryp->nextp;
2319 if (theacl->count != 0){
2320 temp_entry->nextp = acl_entryp = SMB_MALLOC_P(struct acl_entry_link);
2321 if (acl_entryp == NULL) {
2322 errno = ENOMEM;
2323 DEBUG(0, ("Error in sys_acl_create_entry is %d\n", errno));
2324 return -1;
2327 DEBUG(10, ("The acl_entryp is %d\n", acl_entryp));
2328 acl_entryp->prevp = temp_entry;
2329 DEBUG(10, ("The acl_entryp->prevp is %d\n", acl_entryp->prevp));
2332 *pentry = acl_entryp->entryp = SMB_MALLOC_P(struct new_acl_entry);
2333 if (*pentry == NULL) {
2334 errno = ENOMEM;
2335 DEBUG(0, ("Error in sys_acl_create_entry is %d\n", errno));
2336 return -1;
2339 memset(*pentry, 0, sizeof (struct new_acl_entry));
2340 acl_entryp->entryp->ace_len = sizeof (struct acl_entry);
2341 acl_entryp->entryp->ace_type = ACC_PERMIT;
2342 acl_entryp->entryp->ace_id->id_len = sizeof (struct ace_id);
2343 acl_entryp->nextp = NULL;
2344 theacl->count++;
2345 DEBUG(10, ("Exiting sys_acl_create_entry\n"));
2346 return 0;
2349 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
2351 entry->ace_id->id_type = tag_type;
2352 DEBUG(10, ("The tag type is %d\n", entry->ace_id->id_type));
2354 if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP)
2355 memcpy(entry->ace_id->id_data, &u_g_id, sizeof (id_t));
2357 entry->ace_access = bits;
2358 DEBUG(10, ("entry->ace_access = %d\n", entry->ace_access));
2360 return 0;
2363 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits)
2365 DEBUG(10, ("Starting AIX sys_acl_set_permset\n"));
2366 entry->ace_access = bits;
2367 DEBUG(10, ("entry->ace_access = %d\n", entry->ace_access));
2368 DEBUG(10, ("Ending AIX sys_acl_set_permset\n"));
2369 return 0;
2372 int sys_acl_valid(SMB_ACL_T theacl)
2374 int user_obj = 0;
2375 int group_obj = 0;
2376 int other_obj = 0;
2377 struct acl_entry_link *acl_entry;
2379 for (acl_entry=theacl; acl_entry != NULL; acl_entry = acl_entry->nextp) {
2380 user_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_USER_OBJ);
2381 group_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_GROUP_OBJ);
2382 other_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_OTHER);
2385 DEBUG(10, ("user_obj=%d, group_obj=%d, other_obj=%d\n", user_obj, group_obj, other_obj));
2387 if (user_obj != 1 || group_obj != 1 || other_obj != 1)
2388 return -1;
2390 return 0;
2393 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
2395 struct acl_entry_link *acl_entry_link = NULL;
2396 struct acl *file_acl = NULL;
2397 struct acl *file_acl_temp = NULL;
2398 struct acl_entry *acl_entry = NULL;
2399 struct ace_id *ace_id = NULL;
2400 uint id_type;
2401 uint user_id;
2402 uint acl_length;
2403 uint rc;
2405 DEBUG(10, ("Entering sys_acl_set_file\n"));
2406 DEBUG(10, ("File name is %s\n", name));
2408 /* AIX has no default ACL */
2409 if (acltype == SMB_ACL_TYPE_DEFAULT)
2410 return 0;
2412 acl_length = BUFSIZ;
2413 file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2415 if (file_acl == NULL) {
2416 errno = ENOMEM;
2417 DEBUG(0, ("Error in sys_acl_set_file is %d\n", errno));
2418 return -1;
2421 memset(file_acl, 0, BUFSIZ);
2423 file_acl->acl_len = ACL_SIZ;
2424 file_acl->acl_mode = S_IXACL;
2426 for (acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
2427 acl_entry_link->entryp->ace_access >>= 6;
2428 id_type = acl_entry_link->entryp->ace_id->id_type;
2430 switch (id_type) {
2431 case SMB_ACL_USER_OBJ:
2432 file_acl->u_access = acl_entry_link->entryp->ace_access;
2433 continue;
2434 case SMB_ACL_GROUP_OBJ:
2435 file_acl->g_access = acl_entry_link->entryp->ace_access;
2436 continue;
2437 case SMB_ACL_OTHER:
2438 file_acl->o_access = acl_entry_link->entryp->ace_access;
2439 continue;
2440 case SMB_ACL_MASK:
2441 continue;
2444 if ((file_acl->acl_len + sizeof (struct acl_entry)) > acl_length) {
2445 acl_length += sizeof (struct acl_entry);
2446 file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
2447 if (file_acl_temp == NULL) {
2448 SAFE_FREE(file_acl);
2449 errno = ENOMEM;
2450 DEBUG(0, ("Error in sys_acl_set_file is %d\n", errno));
2451 return -1;
2454 memcpy(file_acl_temp, file_acl, file_acl->acl_len);
2455 SAFE_FREE(file_acl);
2456 file_acl = file_acl_temp;
2459 acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
2460 file_acl->acl_len += sizeof (struct acl_entry);
2461 acl_entry->ace_len = acl_entry_link->entryp->ace_len;
2462 acl_entry->ace_access = acl_entry_link->entryp->ace_access;
2464 /* In order to use this, we'll need to wait until we can get denies */
2465 /* if (!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
2466 acl_entry->ace_type = ACC_SPECIFY; */
2468 acl_entry->ace_type = ACC_SPECIFY;
2470 ace_id = acl_entry->ace_id;
2472 ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
2473 DEBUG(10, ("The id type is %d\n", ace_id->id_type));
2474 ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
2475 memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof (uid_t));
2476 memcpy(acl_entry->ace_id->id_data, &user_id, sizeof (uid_t));
2479 rc = chacl((char*)name, file_acl, file_acl->acl_len);
2480 DEBUG(10, ("errno is %d\n", errno));
2481 DEBUG(10, ("return code is %d\n", rc));
2482 SAFE_FREE(file_acl);
2483 DEBUG(10, ("Exiting the sys_acl_set_file\n"));
2484 return rc;
2487 #if 0
2488 int sys_acl_set_fd(int fd, SMB_ACL_T theacl)
2490 struct acl_entry_link *acl_entry_link = NULL;
2491 struct acl *file_acl = NULL;
2492 struct acl *file_acl_temp = NULL;
2493 struct acl_entry *acl_entry = NULL;
2494 struct ace_id *ace_id = NULL;
2495 uint id_type;
2496 uint user_id;
2497 uint acl_length;
2498 uint rc;
2500 DEBUG(10, ("Entering sys_acl_set_fd\n"));
2501 acl_length = BUFSIZ;
2502 file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2504 if (file_acl == NULL) {
2505 errno = ENOMEM;
2506 DEBUG(0, ("Error in sys_acl_set_fd is %d\n", errno));
2507 return -1;
2510 memset(file_acl, 0, BUFSIZ);
2512 file_acl->acl_len = ACL_SIZ;
2513 file_acl->acl_mode = S_IXACL;
2515 for (acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
2516 acl_entry_link->entryp->ace_access >>= 6;
2517 id_type = acl_entry_link->entryp->ace_id->id_type;
2518 DEBUG(10, ("The id_type is %d\n", id_type));
2520 switch (id_type) {
2521 case SMB_ACL_USER_OBJ:
2522 file_acl->u_access = acl_entry_link->entryp->ace_access;
2523 continue;
2524 case SMB_ACL_GROUP_OBJ:
2525 file_acl->g_access = acl_entry_link->entryp->ace_access;
2526 continue;
2527 case SMB_ACL_OTHER:
2528 file_acl->o_access = acl_entry_link->entryp->ace_access;
2529 continue;
2530 case SMB_ACL_MASK:
2531 continue;
2534 if ((file_acl->acl_len + sizeof (struct acl_entry)) > acl_length) {
2535 acl_length += sizeof (struct acl_entry);
2536 file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
2537 if (file_acl_temp == NULL) {
2538 SAFE_FREE(file_acl);
2539 errno = ENOMEM;
2540 DEBUG(0, ("Error in sys_acl_set_fd is %d\n", errno));
2541 return -1;
2544 memcpy(file_acl_temp, file_acl, file_acl->acl_len);
2545 SAFE_FREE(file_acl);
2546 file_acl = file_acl_temp;
2549 acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
2550 file_acl->acl_len += sizeof (struct acl_entry);
2551 acl_entry->ace_len = acl_entry_link->entryp->ace_len;
2552 acl_entry->ace_access = acl_entry_link->entryp->ace_access;
2554 /* In order to use this, we'll need to wait until we can get denies */
2555 /* if (!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
2556 acl_entry->ace_type = ACC_SPECIFY; */
2558 acl_entry->ace_type = ACC_SPECIFY;
2560 ace_id = acl_entry->ace_id;
2562 ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
2563 DEBUG(10, ("The id type is %d\n", ace_id->id_type));
2564 ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
2565 memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof (uid_t));
2566 memcpy(ace_id->id_data, &user_id, sizeof (uid_t));
2569 rc = fchacl(fd, file_acl, file_acl->acl_len);
2570 DEBUG(10, ("errno is %d\n", errno));
2571 DEBUG(10, ("return code is %d\n", rc));
2572 SAFE_FREE(file_acl);
2573 DEBUG(10, ("Exiting sys_acl_set_fd\n"));
2574 return rc;
2576 #endif
2578 int sys_acl_delete_def_file(UNUSED(const char *name))
2580 /* AIX has no default ACL */
2581 return 0;
2584 int sys_acl_free_acl(SMB_ACL_T posix_acl)
2586 struct acl_entry_link *acl_entry_link;
2588 for (acl_entry_link = posix_acl->nextp; acl_entry_link->nextp != NULL; acl_entry_link = acl_entry_link->nextp) {
2589 SAFE_FREE(acl_entry_link->prevp->entryp);
2590 SAFE_FREE(acl_entry_link->prevp);
2593 SAFE_FREE(acl_entry_link->prevp->entryp);
2594 SAFE_FREE(acl_entry_link->prevp);
2595 SAFE_FREE(acl_entry_link->entryp);
2596 SAFE_FREE(acl_entry_link);
2598 return 0;
2601 #elif defined(HAVE_OSX_ACLS) /*----------------------------------------------*/
2603 #define OSX_BROKEN_GETENTRY /* returns 0 instead of 1 */
2605 #include <membership.h>
2607 int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
2609 int ret = acl_get_entry(the_acl, entry_id, entry_p);
2610 #ifdef OSX_BROKEN_GETENTRY
2611 if (ret == 0)
2612 ret = 1;
2613 else if (ret == -1 && errno == 22)
2614 ret = 0;
2615 #endif
2616 return ret;
2619 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
2621 if (type == ACL_TYPE_DEFAULT) {
2622 errno = ENOTSUP;
2623 return NULL;
2625 errno = 0;
2626 return acl_get_file(path_p, type);
2629 #if 0
2630 SMB_ACL_T sys_acl_get_fd(int fd)
2632 return acl_get_fd(fd);
2634 #endif
2636 int sys_acl_get_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T *tag_type_p, uint32 *bits_p, id_t *u_g_id_p)
2638 uuid_t *uup;
2639 acl_tag_t tag;
2640 acl_flagset_t flagset;
2641 acl_permset_t permset;
2642 uint32 bits, fb, bb, pb;
2643 int id_type = -1;
2644 int rc;
2646 if (acl_get_tag_type(entry, &tag) != 0
2647 || acl_get_flagset_np(entry, &flagset) != 0
2648 || acl_get_permset(entry, &permset) != 0
2649 || (uup = acl_get_qualifier(entry)) == NULL)
2650 return -1;
2652 rc = mbr_uuid_to_id(*uup, u_g_id_p, &id_type);
2653 acl_free(uup);
2654 if (rc != 0)
2655 return rc;
2657 if (id_type == ID_TYPE_UID)
2658 *tag_type_p = SMB_ACL_USER;
2659 else
2660 *tag_type_p = SMB_ACL_GROUP;
2662 bits = tag == ACL_EXTENDED_ALLOW ? 1 : 0;
2664 for (fb = (1u<<4), bb = (1u<<1); bb < (1u<<12); fb *= 2, bb *= 2) {
2665 if (acl_get_flag_np(flagset, fb) == 1)
2666 bits |= bb;
2669 for (pb = (1u<<1), bb = (1u<<12); bb < (1u<<25); pb *= 2, bb *= 2) {
2670 if (acl_get_perm_np(permset, pb) == 1)
2671 bits |= bb;
2674 *bits_p = bits;
2676 return 0;
2679 SMB_ACL_T sys_acl_init(int count)
2681 return acl_init(count);
2684 int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
2686 return acl_create_entry(pacl, pentry);
2689 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
2691 acl_flagset_t flagset;
2692 acl_permset_t permset;
2693 uint32 fb, bb, pb;
2694 int is_user = tag_type == SMB_ACL_USER;
2695 uuid_t uu;
2696 int rc;
2698 tag_type = bits & 1 ? ACL_EXTENDED_ALLOW : ACL_EXTENDED_DENY;
2700 if (acl_get_flagset_np(entry, &flagset) != 0
2701 || acl_get_permset(entry, &permset) != 0)
2702 return -1;
2704 acl_clear_flags_np(flagset);
2705 acl_clear_perms(permset);
2707 for (fb = (1u<<4), bb = (1u<<1); bb < (1u<<12); fb *= 2, bb *= 2) {
2708 if (bits & bb)
2709 acl_add_flag_np(flagset, fb);
2712 for (pb = (1u<<1), bb = (1u<<12); bb < (1u<<25); pb *= 2, bb *= 2) {
2713 if (bits & bb)
2714 acl_add_perm(permset, pb);
2717 if (is_user)
2718 rc = mbr_uid_to_uuid(u_g_id, uu);
2719 else
2720 rc = mbr_gid_to_uuid(u_g_id, uu);
2721 if (rc != 0)
2722 return rc;
2724 if (acl_set_tag_type(entry, tag_type) != 0
2725 || acl_set_qualifier(entry, &uu) != 0
2726 || acl_set_permset(entry, permset) != 0
2727 || acl_set_flagset_np(entry, flagset) != 0)
2728 return -1;
2730 return 0;
2733 #if 0
2734 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits)
2736 return -1; /* Not needed for OS X. */
2738 #endif
2740 int sys_acl_valid(SMB_ACL_T theacl)
2742 return acl_valid(theacl);
2745 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
2747 return acl_set_file(name, acltype, theacl);
2750 #if 0
2751 int sys_acl_set_fd(int fd, SMB_ACL_T theacl)
2753 return acl_set_fd(fd, theacl);
2755 #endif
2757 int sys_acl_delete_def_file(const char *name)
2759 return acl_delete_def_file(name);
2762 int sys_acl_free_acl(SMB_ACL_T the_acl)
2764 return acl_free(the_acl);
2767 #else /* No ACLs. */
2769 #error No ACL functions defined for this platform!
2771 #endif
2773 /************************************************************************
2774 Deliberately outside the ACL defines. Return 1 if this is a "no acls"
2775 errno, 0 if not.
2776 ************************************************************************/
2778 int no_acl_syscall_error(int err)
2780 #ifdef HAVE_OSX_ACLS
2781 if (err == ENOENT)
2782 return 1; /* Weird problem with directory ACLs. */
2783 #endif
2784 #if defined(ENOSYS)
2785 if (err == ENOSYS) {
2786 return 1;
2788 #endif
2789 #if defined(ENOTSUP)
2790 if (err == ENOTSUP) {
2791 return 1;
2793 #endif
2794 if (err == EINVAL) {
2795 /* If the type of SMB_ACL_TYPE_ACCESS or SMB_ACL_TYPE_DEFAULT
2796 * isn't valid, then the ACLs must be non-POSIX. */
2797 return 1;
2799 return 0;
2802 #endif /* SUPPORT_ACLS */