Some README and man page tweaks.
[rsync.git] / lib / sysacls.c
blob3eb903cf335738cb193603433aa848dfa118acfa
1 /*
2 * Unix SMB/CIFS implementation.
3 * Based on the Samba ACL support code.
4 * Copyright (C) Jeremy Allison 2000.
5 * Copyright (C) 2007-2020 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 #include <dl.h>
773 * Based on the Solaris/SCO code - with modifications.
777 * Note that while this code implements sufficient functionality
778 * to support the sys_acl_* interfaces it does not provide all
779 * of the semantics of the POSIX ACL interfaces.
781 * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
782 * from a call to sys_acl_get_entry() should not be assumed to be
783 * valid after calling any of the following functions, which may
784 * reorder the entries in the ACL.
786 * sys_acl_valid()
787 * sys_acl_set_file()
788 * sys_acl_set_fd()
791 /* This checks if the POSIX ACL system call is defined */
792 /* which basically corresponds to whether JFS 3.3 or */
793 /* higher is installed. If acl() was called when it */
794 /* isn't defined, it causes the process to core dump */
795 /* so it is important to check this and avoid acl() */
796 /* calls if it isn't there. */
798 static BOOL hpux_acl_call_presence(void)
801 shl_t handle = NULL;
802 void *value;
803 int ret_val=0;
804 static BOOL already_checked=0;
806 if(already_checked)
807 return True;
810 ret_val = shl_findsym(&handle, "acl", TYPE_PROCEDURE, &value);
812 if(ret_val != 0) {
813 DEBUG(5, ("hpux_acl_call_presence: shl_findsym() returned %d, errno = %d, error %s\n",
814 ret_val, errno, strerror(errno)));
815 DEBUG(5,("hpux_acl_call_presence: acl() system call is not present. Check if you have JFS 3.3 and above?\n"));
816 return False;
819 DEBUG(10,("hpux_acl_call_presence: acl() system call is present. We have JFS 3.3 or above \n"));
821 already_checked = True;
822 return True;
825 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
827 if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
828 errno = EINVAL;
829 return -1;
832 if (entry_p == NULL) {
833 errno = EINVAL;
834 return -1;
837 if (entry_id == SMB_ACL_FIRST_ENTRY) {
838 acl_d->next = 0;
841 if (acl_d->next < 0) {
842 errno = EINVAL;
843 return -1;
846 if (acl_d->next >= acl_d->count) {
847 return 0;
850 *entry_p = &acl_d->acl[acl_d->next++];
852 return 1;
855 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
857 *type_p = entry_d->a_type;
859 return 0;
863 * There is no way of knowing what size the ACL returned by
864 * ACL_GET will be unless you first call ACL_CNT which means
865 * making an additional system call.
867 * In the hope of avoiding the cost of the additional system
868 * call in most cases, we initially allocate enough space for
869 * an ACL with INITIAL_ACL_SIZE entries. If this turns out to
870 * be too small then we use ACL_CNT to find out the actual
871 * size, reallocate the ACL buffer, and then call ACL_GET again.
874 #define INITIAL_ACL_SIZE 16
876 #ifndef NACLENTRIES
877 #define NACLENTRIES 0
878 #endif
880 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
882 SMB_ACL_T acl_d;
883 int count; /* # of ACL entries allocated */
884 int naccess; /* # of access ACL entries */
885 int ndefault; /* # of default ACL entries */
887 if(hpux_acl_call_presence() == False) {
888 /* Looks like we don't have the acl() system call on HPUX.
889 * May be the system doesn't have the latest version of JFS.
891 return NULL;
894 if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
895 errno = EINVAL;
896 return NULL;
899 count = INITIAL_ACL_SIZE;
900 if ((acl_d = sys_acl_init(count)) == NULL) {
901 return NULL;
905 * If there isn't enough space for the ACL entries we use
906 * ACL_CNT to determine the actual number of ACL entries
907 * reallocate and try again. This is in a loop because it
908 * is possible that someone else could modify the ACL and
909 * increase the number of entries between the call to
910 * ACL_CNT and the call to ACL_GET.
912 while ((count = acl(path_p, ACL_GET, count, &acl_d->acl[0])) < 0 && errno == ENOSPC) {
914 sys_acl_free_acl(acl_d);
916 if ((count = acl(path_p, ACL_CNT, NACLENTRIES, NULL)) < 0) {
917 return NULL;
920 if ((acl_d = sys_acl_init(count)) == NULL) {
921 return NULL;
925 if (count < 0) {
926 sys_acl_free_acl(acl_d);
927 return NULL;
931 * calculate the number of access and default ACL entries
933 * Note: we assume that the acl() system call returned a
934 * well formed ACL which is sorted so that all of the
935 * access ACL entries precede any default ACL entries
937 for (naccess = 0; naccess < count; naccess++) {
938 if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
939 break;
941 ndefault = count - naccess;
944 * if the caller wants the default ACL we have to copy
945 * the entries down to the start of the acl[] buffer
946 * and mask out the ACL_DEFAULT flag from the type field
948 if (type == SMB_ACL_TYPE_DEFAULT) {
949 int i, j;
951 for (i = 0, j = naccess; i < ndefault; i++, j++) {
952 acl_d->acl[i] = acl_d->acl[j];
953 acl_d->acl[i].a_type &= ~ACL_DEFAULT;
956 acl_d->count = ndefault;
957 } else {
958 acl_d->count = naccess;
961 return acl_d;
964 #if 0
965 SMB_ACL_T sys_acl_get_fd(int fd)
968 * HPUX doesn't have the facl call. Fake it using the path.... JRA.
971 files_struct *fsp = file_find_fd(fd);
973 if (fsp == NULL) {
974 errno = EBADF;
975 return NULL;
979 * We know we're in the same conn context. So we
980 * can use the relative path.
983 return sys_acl_get_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
985 #endif
987 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)
989 *tag_type_p = entry->a_type;
991 *bits_p = entry->a_perm;
993 if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP)
994 *u_g_id_p = entry->a_id;
996 return 0;
999 SMB_ACL_T sys_acl_init(int count)
1001 SMB_ACL_T a;
1003 if (count < 0) {
1004 errno = EINVAL;
1005 return NULL;
1009 * note that since the definition of the structure pointed
1010 * to by the SMB_ACL_T includes the first element of the
1011 * acl[] array, this actually allocates an ACL with room
1012 * for (count+1) entries
1014 if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof a[0] + count * sizeof(struct acl))) == NULL) {
1015 errno = ENOMEM;
1016 return NULL;
1019 a->size = count + 1;
1020 a->count = 0;
1021 a->next = -1;
1023 return a;
1027 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
1029 SMB_ACL_T acl_d;
1030 SMB_ACL_ENTRY_T entry_d;
1032 if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
1033 errno = EINVAL;
1034 return -1;
1037 if (acl_d->count >= acl_d->size) {
1038 errno = ENOSPC;
1039 return -1;
1042 entry_d = &acl_d->acl[acl_d->count++];
1043 entry_d->a_type = 0;
1044 entry_d->a_id = -1;
1045 entry_d->a_perm = 0;
1046 *entry_p = entry_d;
1048 return 0;
1051 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
1053 entry->a_type = tag_type;
1055 if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP)
1056 entry->a_id = u_g_id;
1058 entry->a_perm = bits;
1060 return 0;
1063 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry_d, uint32 bits)
1065 entry_d->a_perm = bits;
1067 return 0;
1070 /* Structure to capture the count for each type of ACE. */
1072 struct hpux_acl_types {
1073 int n_user;
1074 int n_def_user;
1075 int n_user_obj;
1076 int n_def_user_obj;
1078 int n_group;
1079 int n_def_group;
1080 int n_group_obj;
1081 int n_def_group_obj;
1083 int n_other;
1084 int n_other_obj;
1085 int n_def_other_obj;
1087 int n_class_obj;
1088 int n_def_class_obj;
1090 int n_illegal_obj;
1093 /* count_obj:
1094 * Counts the different number of objects in a given array of ACL
1095 * structures.
1096 * Inputs:
1098 * acl_count - Count of ACLs in the array of ACL structures.
1099 * aclp - Array of ACL structures.
1100 * acl_type_count - Pointer to acl_types structure. Should already be
1101 * allocated.
1102 * Output:
1104 * acl_type_count - This structure is filled up with counts of various
1105 * acl types.
1108 static void hpux_count_obj(int acl_count, struct acl *aclp, struct hpux_acl_types *acl_type_count)
1110 int i;
1112 memset(acl_type_count, 0, sizeof(struct hpux_acl_types));
1114 for(i=0;i<acl_count;i++) {
1115 switch(aclp[i].a_type) {
1116 case USER:
1117 acl_type_count->n_user++;
1118 break;
1119 case USER_OBJ:
1120 acl_type_count->n_user_obj++;
1121 break;
1122 case DEF_USER_OBJ:
1123 acl_type_count->n_def_user_obj++;
1124 break;
1125 case GROUP:
1126 acl_type_count->n_group++;
1127 break;
1128 case GROUP_OBJ:
1129 acl_type_count->n_group_obj++;
1130 break;
1131 case DEF_GROUP_OBJ:
1132 acl_type_count->n_def_group_obj++;
1133 break;
1134 case OTHER_OBJ:
1135 acl_type_count->n_other_obj++;
1136 break;
1137 case DEF_OTHER_OBJ:
1138 acl_type_count->n_def_other_obj++;
1139 break;
1140 case CLASS_OBJ:
1141 acl_type_count->n_class_obj++;
1142 break;
1143 case DEF_CLASS_OBJ:
1144 acl_type_count->n_def_class_obj++;
1145 break;
1146 case DEF_USER:
1147 acl_type_count->n_def_user++;
1148 break;
1149 case DEF_GROUP:
1150 acl_type_count->n_def_group++;
1151 break;
1152 default:
1153 acl_type_count->n_illegal_obj++;
1154 break;
1159 /* swap_acl_entries: Swaps two ACL entries.
1161 * Inputs: aclp0, aclp1 - ACL entries to be swapped.
1164 static void hpux_swap_acl_entries(struct acl *aclp0, struct acl *aclp1)
1166 struct acl temp_acl;
1168 temp_acl.a_type = aclp0->a_type;
1169 temp_acl.a_id = aclp0->a_id;
1170 temp_acl.a_perm = aclp0->a_perm;
1172 aclp0->a_type = aclp1->a_type;
1173 aclp0->a_id = aclp1->a_id;
1174 aclp0->a_perm = aclp1->a_perm;
1176 aclp1->a_type = temp_acl.a_type;
1177 aclp1->a_id = temp_acl.a_id;
1178 aclp1->a_perm = temp_acl.a_perm;
1181 /* prohibited_duplicate_type
1182 * Identifies if given ACL type can have duplicate entries or
1183 * not.
1185 * Inputs: acl_type - ACL Type.
1187 * Outputs:
1189 * Return..
1191 * True - If the ACL type matches any of the prohibited types.
1192 * False - If the ACL type doesn't match any of the prohibited types.
1195 static BOOL hpux_prohibited_duplicate_type(int acl_type)
1197 switch(acl_type) {
1198 case USER:
1199 case GROUP:
1200 case DEF_USER:
1201 case DEF_GROUP:
1202 return True;
1203 default:
1204 return False;
1208 /* get_needed_class_perm
1209 * Returns the permissions of a ACL structure only if the ACL
1210 * type matches one of the pre-determined types for computing
1211 * CLASS_OBJ permissions.
1213 * Inputs: aclp - Pointer to ACL structure.
1216 static int hpux_get_needed_class_perm(struct acl *aclp)
1218 switch(aclp->a_type) {
1219 case USER:
1220 case GROUP_OBJ:
1221 case GROUP:
1222 case DEF_USER_OBJ:
1223 case DEF_USER:
1224 case DEF_GROUP_OBJ:
1225 case DEF_GROUP:
1226 case DEF_CLASS_OBJ:
1227 case DEF_OTHER_OBJ:
1228 return aclp->a_perm;
1229 default:
1230 return 0;
1234 /* acl_sort for HPUX.
1235 * Sorts the array of ACL structures as per the description in
1236 * aclsort man page. Refer to aclsort man page for more details
1238 * Inputs:
1240 * acl_count - Count of ACLs in the array of ACL structures.
1241 * calclass - If this is not zero, then we compute the CLASS_OBJ
1242 * permissions.
1243 * aclp - Array of ACL structures.
1245 * Outputs:
1247 * aclp - Sorted array of ACL structures.
1249 * Outputs:
1251 * Returns 0 for success -1 for failure. Prints a message to the Samba
1252 * debug log in case of failure.
1255 static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp)
1257 #if !defined(HAVE_HPUX_ACLSORT)
1259 * The aclsort() system call is available on the latest HPUX General
1260 * Patch Bundles. So for HPUX, we developed our version of acl_sort
1261 * function. Because, we don't want to update to a new
1262 * HPUX GR bundle just for aclsort() call.
1265 struct hpux_acl_types acl_obj_count;
1266 int n_class_obj_perm = 0;
1267 int i, j;
1269 if(!acl_count) {
1270 DEBUG(10,("Zero acl count passed. Returning Success\n"));
1271 return 0;
1274 if(aclp == NULL) {
1275 DEBUG(0,("Null ACL pointer in hpux_acl_sort. Returning Failure. \n"));
1276 return -1;
1279 /* Count different types of ACLs in the ACLs array */
1281 hpux_count_obj(acl_count, aclp, &acl_obj_count);
1283 /* There should be only one entry each of type USER_OBJ, GROUP_OBJ,
1284 * CLASS_OBJ and OTHER_OBJ
1287 if( (acl_obj_count.n_user_obj != 1) ||
1288 (acl_obj_count.n_group_obj != 1) ||
1289 (acl_obj_count.n_class_obj != 1) ||
1290 (acl_obj_count.n_other_obj != 1)
1292 DEBUG(0,("hpux_acl_sort: More than one entry or no entries for \
1293 USER OBJ or GROUP_OBJ or OTHER_OBJ or CLASS_OBJ\n"));
1294 return -1;
1297 /* If any of the default objects are present, there should be only
1298 * one of them each.
1301 if( (acl_obj_count.n_def_user_obj > 1) || (acl_obj_count.n_def_group_obj > 1) ||
1302 (acl_obj_count.n_def_other_obj > 1) || (acl_obj_count.n_def_class_obj > 1) ) {
1303 DEBUG(0,("hpux_acl_sort: More than one entry for DEF_CLASS_OBJ \
1304 or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n"));
1305 return -1;
1308 /* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl
1309 * structures.
1311 * Sorting crieteria - First sort by ACL type. If there are multiple entries of
1312 * same ACL type, sort by ACL id.
1314 * I am using the trivial kind of sorting method here because, performance isn't
1315 * really effected by the ACLs feature. More over there aren't going to be more
1316 * than 17 entries on HPUX.
1319 for(i=0; i<acl_count;i++) {
1320 for (j=i+1; j<acl_count; j++) {
1321 if( aclp[i].a_type > aclp[j].a_type ) {
1322 /* ACL entries out of order, swap them */
1324 hpux_swap_acl_entries((aclp+i), (aclp+j));
1326 } else if ( aclp[i].a_type == aclp[j].a_type ) {
1328 /* ACL entries of same type, sort by id */
1330 if(aclp[i].a_id > aclp[j].a_id) {
1331 hpux_swap_acl_entries((aclp+i), (aclp+j));
1332 } else if (aclp[i].a_id == aclp[j].a_id) {
1333 /* We have a duplicate entry. */
1334 if(hpux_prohibited_duplicate_type(aclp[i].a_type)) {
1335 DEBUG(0, ("hpux_acl_sort: Duplicate entry: Type(hex): %x Id: %d\n",
1336 aclp[i].a_type, aclp[i].a_id));
1337 return -1;
1345 /* set the class obj permissions to the computed one. */
1346 if(calclass) {
1347 int n_class_obj_index = -1;
1349 for(i=0;i<acl_count;i++) {
1350 n_class_obj_perm |= hpux_get_needed_class_perm((aclp+i));
1352 if(aclp[i].a_type == CLASS_OBJ)
1353 n_class_obj_index = i;
1355 aclp[n_class_obj_index].a_perm = n_class_obj_perm;
1358 return 0;
1359 #else
1360 return aclsort(acl_count, calclass, aclp);
1361 #endif
1365 * sort the ACL and check it for validity
1367 * if it's a minimal ACL with only 4 entries then we
1368 * need to recalculate the mask permissions to make
1369 * sure that they are the same as the GROUP_OBJ
1370 * permissions as required by the UnixWare acl() system call.
1372 * (note: since POSIX allows minimal ACLs which only contain
1373 * 3 entries - ie there is no mask entry - we should, in theory,
1374 * check for this and add a mask entry if necessary - however
1375 * we "know" that the caller of this interface always specifies
1376 * a mask so, in practice "this never happens" (tm) - if it *does*
1377 * happen aclsort() will fail and return an error and someone will
1378 * have to fix it ...)
1381 static int acl_sort(SMB_ACL_T acl_d)
1383 int fixmask = (acl_d->count <= 4);
1385 if (hpux_acl_sort(acl_d->count, fixmask, acl_d->acl) != 0) {
1386 errno = EINVAL;
1387 return -1;
1389 return 0;
1392 int sys_acl_valid(SMB_ACL_T acl_d)
1394 return acl_sort(acl_d);
1397 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
1399 struct stat s;
1400 struct acl *acl_p;
1401 int acl_count;
1402 struct acl *acl_buf = NULL;
1403 int ret;
1405 if(hpux_acl_call_presence() == False) {
1406 /* Looks like we don't have the acl() system call on HPUX.
1407 * May be the system doesn't have the latest version of JFS.
1409 errno=ENOSYS;
1410 return -1;
1413 if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
1414 errno = EINVAL;
1415 return -1;
1418 if (acl_sort(acl_d) != 0) {
1419 return -1;
1422 acl_p = &acl_d->acl[0];
1423 acl_count = acl_d->count;
1426 * if it's a directory there is extra work to do
1427 * since the acl() system call will replace both
1428 * the access ACLs and the default ACLs (if any)
1430 if (stat(name, &s) != 0) {
1431 return -1;
1433 if (S_ISDIR(s.st_mode)) {
1434 SMB_ACL_T acc_acl;
1435 SMB_ACL_T def_acl;
1436 SMB_ACL_T tmp_acl;
1437 int i;
1439 if (type == SMB_ACL_TYPE_ACCESS) {
1440 acc_acl = acl_d;
1441 def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
1443 } else {
1444 def_acl = acl_d;
1445 acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
1448 if (tmp_acl == NULL) {
1449 return -1;
1453 * allocate a temporary buffer for the complete ACL
1455 acl_count = acc_acl->count + def_acl->count;
1456 acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count);
1458 if (acl_buf == NULL) {
1459 sys_acl_free_acl(tmp_acl);
1460 errno = ENOMEM;
1461 return -1;
1465 * copy the access control and default entries into the buffer
1467 memcpy(&acl_buf[0], &acc_acl->acl[0],
1468 acc_acl->count * sizeof(acl_buf[0]));
1470 memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
1471 def_acl->count * sizeof(acl_buf[0]));
1474 * set the ACL_DEFAULT flag on the default entries
1476 for (i = acc_acl->count; i < acl_count; i++) {
1477 acl_buf[i].a_type |= ACL_DEFAULT;
1480 sys_acl_free_acl(tmp_acl);
1482 } else if (type != SMB_ACL_TYPE_ACCESS) {
1483 errno = EINVAL;
1484 return -1;
1487 ret = acl(name, ACL_SET, acl_count, acl_p);
1489 if (acl_buf) {
1490 free(acl_buf);
1493 return ret;
1496 #if 0
1497 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
1500 * HPUX doesn't have the facl call. Fake it using the path.... JRA.
1503 files_struct *fsp = file_find_fd(fd);
1505 if (fsp == NULL) {
1506 errno = EBADF;
1507 return NULL;
1510 if (acl_sort(acl_d) != 0) {
1511 return -1;
1515 * We know we're in the same conn context. So we
1516 * can use the relative path.
1519 return sys_acl_set_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS, acl_d);
1521 #endif
1523 int sys_acl_delete_def_file(const char *path)
1525 SMB_ACL_T acl_d;
1526 int ret;
1529 * fetching the access ACL and rewriting it has
1530 * the effect of deleting the default ACL
1532 if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
1533 return -1;
1536 ret = acl(path, ACL_SET, acl_d->count, acl_d->acl);
1538 sys_acl_free_acl(acl_d);
1540 return ret;
1543 int sys_acl_free_acl(SMB_ACL_T acl_d)
1545 free(acl_d);
1546 return 0;
1549 #elif defined(HAVE_IRIX_ACLS) /*---------------------------------------------*/
1551 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
1553 if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
1554 errno = EINVAL;
1555 return -1;
1558 if (entry_p == NULL) {
1559 errno = EINVAL;
1560 return -1;
1563 if (entry_id == SMB_ACL_FIRST_ENTRY) {
1564 acl_d->next = 0;
1567 if (acl_d->next < 0) {
1568 errno = EINVAL;
1569 return -1;
1572 if (acl_d->next >= acl_d->aclp->acl_cnt) {
1573 return 0;
1576 *entry_p = &acl_d->aclp->acl_entry[acl_d->next++];
1578 return 1;
1581 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
1583 *type_p = entry_d->ae_tag;
1585 return 0;
1588 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
1590 SMB_ACL_T a;
1592 if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) {
1593 errno = ENOMEM;
1594 return NULL;
1596 if ((a->aclp = acl_get_file(path_p, type)) == NULL) {
1597 SAFE_FREE(a);
1598 return NULL;
1600 a->next = -1;
1601 a->freeaclp = True;
1602 return a;
1605 #if 0
1606 SMB_ACL_T sys_acl_get_fd(int fd)
1608 SMB_ACL_T a;
1610 if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) {
1611 errno = ENOMEM;
1612 return NULL;
1614 if ((a->aclp = acl_get_fd(fd)) == NULL) {
1615 SAFE_FREE(a);
1616 return NULL;
1618 a->next = -1;
1619 a->freeaclp = True;
1620 return a;
1622 #endif
1624 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)
1626 *tag_type_p = entry->ae_tag;
1628 *bits_p = entry->ae_perm;
1630 if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP)
1631 *u_g_id_p = entry->ae_id;
1633 return 0;
1636 SMB_ACL_T sys_acl_init(int count)
1638 SMB_ACL_T a;
1640 if (count < 0) {
1641 errno = EINVAL;
1642 return NULL;
1645 if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof a[0] + sizeof (struct acl))) == NULL) {
1646 errno = ENOMEM;
1647 return NULL;
1650 a->next = -1;
1651 a->freeaclp = False;
1652 a->aclp = (struct acl *)((char *)a + sizeof a[0]);
1653 a->aclp->acl_cnt = 0;
1655 return a;
1659 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
1661 SMB_ACL_T acl_d;
1662 SMB_ACL_ENTRY_T entry_d;
1664 if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
1665 errno = EINVAL;
1666 return -1;
1669 if (acl_d->aclp->acl_cnt >= ACL_MAX_ENTRIES) {
1670 errno = ENOSPC;
1671 return -1;
1674 entry_d = &acl_d->aclp->acl_entry[acl_d->aclp->acl_cnt++];
1675 entry_d->ae_tag = 0;
1676 entry_d->ae_id = 0;
1677 entry_d->ae_perm = 0;
1678 *entry_p = entry_d;
1680 return 0;
1683 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
1685 entry->ae_tag = tag_type;
1687 if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP)
1688 entry->ae_id = u_g_id;
1690 entry->ae_perm = bits;
1692 return 0;
1695 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry_d, uint32 bits)
1697 entry_d->ae_perm = bits;
1699 return 0;
1702 int sys_acl_valid(SMB_ACL_T acl_d)
1704 return acl_valid(acl_d->aclp);
1707 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
1709 return acl_set_file(name, type, acl_d->aclp);
1712 #if 0
1713 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
1715 return acl_set_fd(fd, acl_d->aclp);
1717 #endif
1719 int sys_acl_delete_def_file(const char *name)
1721 return acl_delete_def_file(name);
1724 int sys_acl_free_acl(SMB_ACL_T acl_d)
1726 if (acl_d->freeaclp) {
1727 acl_free(acl_d->aclp);
1729 acl_free(acl_d);
1730 return 0;
1733 #elif defined(HAVE_AIX_ACLS) /*----------------------------------------------*/
1735 /* Donated by Medha Date, mdate@austin.ibm.com, for IBM */
1737 int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
1739 struct acl_entry_link *link;
1740 struct new_acl_entry *entry;
1741 int keep_going;
1743 if (entry_id == SMB_ACL_FIRST_ENTRY)
1744 theacl->count = 0;
1745 else if (entry_id != SMB_ACL_NEXT_ENTRY) {
1746 errno = EINVAL;
1747 return -1;
1750 DEBUG(10,("This is the count: %d\n",theacl->count));
1752 /* Check if count was previously set to -1. *
1753 * If it was, that means we reached the end *
1754 * of the acl last time. */
1755 if(theacl->count == -1)
1756 return(0);
1758 link = theacl;
1759 /* To get to the next acl, traverse linked list until index *
1760 * of acl matches the count we are keeping. This count is *
1761 * incremented each time we return an acl entry. */
1763 for(keep_going = 0; keep_going < theacl->count; keep_going++)
1764 link = link->nextp;
1766 entry = *entry_p = link->entryp;
1768 DEBUG(10,("*entry_p is %d\n",entry_p));
1769 DEBUG(10,("*entry_p->ace_access is %d\n",entry->ace_access));
1771 /* Increment count */
1772 theacl->count++;
1773 if(link->nextp == NULL)
1774 theacl->count = -1;
1776 return(1);
1779 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
1781 /* Initialize tag type */
1783 *tag_type_p = -1;
1784 DEBUG(10,("the tagtype is %d\n",entry_d->ace_id->id_type));
1786 /* Depending on what type of entry we have, *
1787 * return tag type. */
1788 switch(entry_d->ace_id->id_type) {
1789 case ACEID_USER:
1790 *tag_type_p = SMB_ACL_USER;
1791 break;
1792 case ACEID_GROUP:
1793 *tag_type_p = SMB_ACL_GROUP;
1794 break;
1796 case SMB_ACL_USER_OBJ:
1797 case SMB_ACL_GROUP_OBJ:
1798 case SMB_ACL_OTHER:
1799 *tag_type_p = entry_d->ace_id->id_type;
1800 break;
1802 default:
1803 return(-1);
1806 return(0);
1809 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
1811 struct acl *file_acl = (struct acl *)NULL;
1812 struct acl_entry *acl_entry;
1813 struct new_acl_entry *new_acl_entry;
1814 struct ace_id *idp;
1815 struct acl_entry_link *acl_entry_link;
1816 struct acl_entry_link *acl_entry_link_head;
1817 int i;
1818 int rc = 0;
1820 /* AIX has no DEFAULT */
1821 if ( type == SMB_ACL_TYPE_DEFAULT ) {
1822 #ifdef ENOTSUP
1823 errno = ENOTSUP;
1824 #else
1825 errno = ENOSYS;
1826 #endif
1827 return NULL;
1830 /* Get the acl using statacl */
1832 DEBUG(10,("Entering sys_acl_get_file\n"));
1833 DEBUG(10,("path_p is %s\n",path_p));
1835 file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
1837 if(file_acl == NULL) {
1838 errno=ENOMEM;
1839 DEBUG(0,("Error in AIX sys_acl_get_file: %d\n",errno));
1840 return(NULL);
1843 memset(file_acl,0,BUFSIZ);
1845 rc = statacl((char *)path_p,0,file_acl,BUFSIZ);
1846 if(rc == -1) {
1847 DEBUG(0,("statacl returned %d with errno %d\n",rc,errno));
1848 SAFE_FREE(file_acl);
1849 return(NULL);
1852 DEBUG(10,("Got facl and returned it\n"));
1854 /* Point to the first acl entry in the acl */
1855 acl_entry = file_acl->acl_ext;
1857 /* Begin setting up the head of the linked list *
1858 * that will be used for the storing the acl *
1859 * in a way that is useful for the posix_acls.c *
1860 * code. */
1862 acl_entry_link_head = acl_entry_link = sys_acl_init(0);
1863 if(acl_entry_link_head == NULL)
1864 return(NULL);
1866 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
1867 if(acl_entry_link->entryp == NULL) {
1868 SAFE_FREE(file_acl);
1869 errno = ENOMEM;
1870 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
1871 return(NULL);
1874 DEBUG(10,("acl_entry is %d\n",acl_entry));
1875 DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
1877 /* Check if the extended acl bit is on. *
1878 * If it isn't, do not show the *
1879 * contents of the acl since AIX intends *
1880 * the extended info to remain unused */
1882 if(file_acl->acl_mode & S_IXACL){
1883 /* while we are not pointing to the very end */
1884 while(acl_entry < acl_last(file_acl)) {
1885 /* before we malloc anything, make sure this is */
1886 /* a valid acl entry and one that we want to map */
1887 idp = id_nxt(acl_entry->ace_id);
1888 if((acl_entry->ace_type == ACC_SPECIFY ||
1889 (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
1890 acl_entry = acl_nxt(acl_entry);
1891 continue;
1894 idp = acl_entry->ace_id;
1896 /* Check if this is the first entry in the linked list. *
1897 * The first entry needs to keep prevp pointing to NULL *
1898 * and already has entryp allocated. */
1900 if(acl_entry_link_head->count != 0) {
1901 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
1903 if(acl_entry_link->nextp == NULL) {
1904 SAFE_FREE(file_acl);
1905 errno = ENOMEM;
1906 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
1907 return(NULL);
1910 acl_entry_link->nextp->prevp = acl_entry_link;
1911 acl_entry_link = acl_entry_link->nextp;
1912 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
1913 if(acl_entry_link->entryp == NULL) {
1914 SAFE_FREE(file_acl);
1915 errno = ENOMEM;
1916 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
1917 return(NULL);
1919 acl_entry_link->nextp = NULL;
1922 acl_entry_link->entryp->ace_len = acl_entry->ace_len;
1924 /* Don't really need this since all types are going *
1925 * to be specified but, it's better than leaving it 0 */
1927 acl_entry_link->entryp->ace_type = acl_entry->ace_type;
1929 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
1931 memcpy(acl_entry_link->entryp->ace_id,idp,sizeof(struct ace_id));
1933 /* The access in the acl entries must be left shifted by *
1934 * three bites, because they will ultimately be compared *
1935 * to S_IRUSR, S_IWUSR, and S_IXUSR. */
1937 switch(acl_entry->ace_type){
1938 case ACC_PERMIT:
1939 case ACC_SPECIFY:
1940 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
1941 acl_entry_link->entryp->ace_access <<= 6;
1942 acl_entry_link_head->count++;
1943 break;
1944 case ACC_DENY:
1945 /* Since there is no way to return a DENY acl entry *
1946 * change to PERMIT and then shift. */
1947 DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
1948 acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
1949 DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
1950 acl_entry_link->entryp->ace_access <<= 6;
1951 acl_entry_link_head->count++;
1952 break;
1953 default:
1954 return(0);
1957 DEBUG(10,("acl_entry = %d\n",acl_entry));
1958 DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
1960 acl_entry = acl_nxt(acl_entry);
1962 } /* end of if enabled */
1964 /* Since owner, group, other acl entries are not *
1965 * part of the acl entries in an acl, they must *
1966 * be dummied up to become part of the list. */
1968 for( i = 1; i < 4; i++) {
1969 DEBUG(10,("i is %d\n",i));
1970 if(acl_entry_link_head->count != 0) {
1971 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
1972 if(acl_entry_link->nextp == NULL) {
1973 SAFE_FREE(file_acl);
1974 errno = ENOMEM;
1975 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
1976 return(NULL);
1979 acl_entry_link->nextp->prevp = acl_entry_link;
1980 acl_entry_link = acl_entry_link->nextp;
1981 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
1982 if(acl_entry_link->entryp == NULL) {
1983 SAFE_FREE(file_acl);
1984 errno = ENOMEM;
1985 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
1986 return(NULL);
1990 acl_entry_link->nextp = NULL;
1992 new_acl_entry = acl_entry_link->entryp;
1993 idp = new_acl_entry->ace_id;
1995 new_acl_entry->ace_len = sizeof(struct acl_entry);
1996 new_acl_entry->ace_type = ACC_PERMIT;
1997 idp->id_len = sizeof(struct ace_id);
1998 DEBUG(10,("idp->id_len = %d\n",idp->id_len));
1999 memset(idp->id_data,0,sizeof(uid_t));
2001 switch(i) {
2002 case 2:
2003 new_acl_entry->ace_access = file_acl->g_access << 6;
2004 idp->id_type = SMB_ACL_GROUP_OBJ;
2005 break;
2007 case 3:
2008 new_acl_entry->ace_access = file_acl->o_access << 6;
2009 idp->id_type = SMB_ACL_OTHER;
2010 break;
2012 case 1:
2013 new_acl_entry->ace_access = file_acl->u_access << 6;
2014 idp->id_type = SMB_ACL_USER_OBJ;
2015 break;
2017 default:
2018 return(NULL);
2022 acl_entry_link_head->count++;
2023 DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
2026 acl_entry_link_head->count = 0;
2027 SAFE_FREE(file_acl);
2029 return(acl_entry_link_head);
2032 #if 0
2033 SMB_ACL_T sys_acl_get_fd(int fd)
2035 struct acl *file_acl = (struct acl *)NULL;
2036 struct acl_entry *acl_entry;
2037 struct new_acl_entry *new_acl_entry;
2038 struct ace_id *idp;
2039 struct acl_entry_link *acl_entry_link;
2040 struct acl_entry_link *acl_entry_link_head;
2041 int i;
2042 int rc = 0;
2044 /* Get the acl using fstatacl */
2046 DEBUG(10,("Entering sys_acl_get_fd\n"));
2047 DEBUG(10,("fd is %d\n",fd));
2048 file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2050 if(file_acl == NULL) {
2051 errno=ENOMEM;
2052 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2053 return(NULL);
2056 memset(file_acl,0,BUFSIZ);
2058 rc = fstatacl(fd,0,file_acl,BUFSIZ);
2059 if(rc == -1) {
2060 DEBUG(0,("The fstatacl call returned %d with errno %d\n",rc,errno));
2061 SAFE_FREE(file_acl);
2062 return(NULL);
2065 DEBUG(10,("Got facl and returned it\n"));
2067 /* Point to the first acl entry in the acl */
2069 acl_entry = file_acl->acl_ext;
2070 /* Begin setting up the head of the linked list *
2071 * that will be used for the storing the acl *
2072 * in a way that is useful for the posix_acls.c *
2073 * code. */
2075 acl_entry_link_head = acl_entry_link = sys_acl_init(0);
2076 if(acl_entry_link_head == NULL){
2077 SAFE_FREE(file_acl);
2078 return(NULL);
2081 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2083 if(acl_entry_link->entryp == NULL) {
2084 errno = ENOMEM;
2085 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2086 SAFE_FREE(file_acl);
2087 return(NULL);
2090 DEBUG(10,("acl_entry is %d\n",acl_entry));
2091 DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
2093 /* Check if the extended acl bit is on. *
2094 * If it isn't, do not show the *
2095 * contents of the acl since AIX intends *
2096 * the extended info to remain unused */
2098 if(file_acl->acl_mode & S_IXACL){
2099 /* while we are not pointing to the very end */
2100 while(acl_entry < acl_last(file_acl)) {
2101 /* before we malloc anything, make sure this is */
2102 /* a valid acl entry and one that we want to map */
2104 idp = id_nxt(acl_entry->ace_id);
2105 if((acl_entry->ace_type == ACC_SPECIFY ||
2106 (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
2107 acl_entry = acl_nxt(acl_entry);
2108 continue;
2111 idp = acl_entry->ace_id;
2113 /* Check if this is the first entry in the linked list. *
2114 * The first entry needs to keep prevp pointing to NULL *
2115 * and already has entryp allocated. */
2117 if(acl_entry_link_head->count != 0) {
2118 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2119 if(acl_entry_link->nextp == NULL) {
2120 errno = ENOMEM;
2121 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2122 SAFE_FREE(file_acl);
2123 return(NULL);
2125 acl_entry_link->nextp->prevp = acl_entry_link;
2126 acl_entry_link = acl_entry_link->nextp;
2127 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2128 if(acl_entry_link->entryp == NULL) {
2129 errno = ENOMEM;
2130 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2131 SAFE_FREE(file_acl);
2132 return(NULL);
2135 acl_entry_link->nextp = NULL;
2138 acl_entry_link->entryp->ace_len = acl_entry->ace_len;
2140 /* Don't really need this since all types are going *
2141 * to be specified but, it's better than leaving it 0 */
2143 acl_entry_link->entryp->ace_type = acl_entry->ace_type;
2144 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2146 memcpy(acl_entry_link->entryp->ace_id, idp, sizeof(struct ace_id));
2148 /* The access in the acl entries must be left shifted by *
2149 * three bites, because they will ultimately be compared *
2150 * to S_IRUSR, S_IWUSR, and S_IXUSR. */
2152 switch(acl_entry->ace_type){
2153 case ACC_PERMIT:
2154 case ACC_SPECIFY:
2155 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2156 acl_entry_link->entryp->ace_access <<= 6;
2157 acl_entry_link_head->count++;
2158 break;
2159 case ACC_DENY:
2160 /* Since there is no way to return a DENY acl entry *
2161 * change to PERMIT and then shift. */
2162 DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
2163 acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
2164 DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
2165 acl_entry_link->entryp->ace_access <<= 6;
2166 acl_entry_link_head->count++;
2167 break;
2168 default:
2169 return(0);
2172 DEBUG(10,("acl_entry = %d\n",acl_entry));
2173 DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
2175 acl_entry = acl_nxt(acl_entry);
2177 } /* end of if enabled */
2179 /* Since owner, group, other acl entries are not *
2180 * part of the acl entries in an acl, they must *
2181 * be dummied up to become part of the list. */
2183 for( i = 1; i < 4; i++) {
2184 DEBUG(10,("i is %d\n",i));
2185 if(acl_entry_link_head->count != 0){
2186 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2187 if(acl_entry_link->nextp == NULL) {
2188 errno = ENOMEM;
2189 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2190 SAFE_FREE(file_acl);
2191 return(NULL);
2194 acl_entry_link->nextp->prevp = acl_entry_link;
2195 acl_entry_link = acl_entry_link->nextp;
2196 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2198 if(acl_entry_link->entryp == NULL) {
2199 SAFE_FREE(file_acl);
2200 errno = ENOMEM;
2201 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2202 return(NULL);
2206 acl_entry_link->nextp = NULL;
2208 new_acl_entry = acl_entry_link->entryp;
2209 idp = new_acl_entry->ace_id;
2211 new_acl_entry->ace_len = sizeof(struct acl_entry);
2212 new_acl_entry->ace_type = ACC_PERMIT;
2213 idp->id_len = sizeof(struct ace_id);
2214 DEBUG(10,("idp->id_len = %d\n",idp->id_len));
2215 memset(idp->id_data,0,sizeof(uid_t));
2217 switch(i) {
2218 case 2:
2219 new_acl_entry->ace_access = file_acl->g_access << 6;
2220 idp->id_type = SMB_ACL_GROUP_OBJ;
2221 break;
2223 case 3:
2224 new_acl_entry->ace_access = file_acl->o_access << 6;
2225 idp->id_type = SMB_ACL_OTHER;
2226 break;
2228 case 1:
2229 new_acl_entry->ace_access = file_acl->u_access << 6;
2230 idp->id_type = SMB_ACL_USER_OBJ;
2231 break;
2233 default:
2234 return(NULL);
2237 acl_entry_link_head->count++;
2238 DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
2241 acl_entry_link_head->count = 0;
2242 SAFE_FREE(file_acl);
2244 return(acl_entry_link_head);
2246 #endif
2248 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)
2250 uint *permset;
2252 if (sys_acl_get_tag_type(entry, tag_type_p) != 0)
2253 return -1;
2255 if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP)
2256 memcpy(u_g_id_p, entry->ace_id->id_data, sizeof (id_t));
2258 permset = &entry->ace_access;
2260 DEBUG(10,("*permset is %d\n",*permset));
2261 *bits_p = (*permset & S_IRUSR ? 4 : 0)
2262 | (*permset & S_IWUSR ? 2 : 0)
2263 | (*permset & S_IXUSR ? 1 : 0);
2265 return 0;
2268 SMB_ACL_T sys_acl_init( int count)
2270 struct acl_entry_link *theacl = NULL;
2272 if (count < 0) {
2273 errno = EINVAL;
2274 return NULL;
2277 DEBUG(10,("Entering sys_acl_init\n"));
2279 theacl = SMB_MALLOC_P(struct acl_entry_link);
2280 if(theacl == NULL) {
2281 errno = ENOMEM;
2282 DEBUG(0,("Error in sys_acl_init is %d\n",errno));
2283 return(NULL);
2286 theacl->count = 0;
2287 theacl->nextp = NULL;
2288 theacl->prevp = NULL;
2289 theacl->entryp = NULL;
2290 DEBUG(10,("Exiting sys_acl_init\n"));
2291 return(theacl);
2294 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
2296 struct acl_entry_link *theacl;
2297 struct acl_entry_link *acl_entryp;
2298 struct acl_entry_link *temp_entry;
2299 int counting;
2301 DEBUG(10,("Entering the sys_acl_create_entry\n"));
2303 theacl = acl_entryp = *pacl;
2305 /* Get to the end of the acl before adding entry */
2307 for(counting=0; counting < theacl->count; counting++){
2308 DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
2309 temp_entry = acl_entryp;
2310 acl_entryp = acl_entryp->nextp;
2313 if(theacl->count != 0){
2314 temp_entry->nextp = acl_entryp = SMB_MALLOC_P(struct acl_entry_link);
2315 if(acl_entryp == NULL) {
2316 errno = ENOMEM;
2317 DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
2318 return(-1);
2321 DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
2322 acl_entryp->prevp = temp_entry;
2323 DEBUG(10,("The acl_entryp->prevp is %d\n",acl_entryp->prevp));
2326 *pentry = acl_entryp->entryp = SMB_MALLOC_P(struct new_acl_entry);
2327 if(*pentry == NULL) {
2328 errno = ENOMEM;
2329 DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
2330 return(-1);
2333 memset(*pentry,0,sizeof(struct new_acl_entry));
2334 acl_entryp->entryp->ace_len = sizeof(struct acl_entry);
2335 acl_entryp->entryp->ace_type = ACC_PERMIT;
2336 acl_entryp->entryp->ace_id->id_len = sizeof(struct ace_id);
2337 acl_entryp->nextp = NULL;
2338 theacl->count++;
2339 DEBUG(10,("Exiting sys_acl_create_entry\n"));
2340 return(0);
2343 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
2345 entry->ace_id->id_type = tag_type;
2346 DEBUG(10,("The tag type is %d\n",entry->ace_id->id_type));
2348 if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP)
2349 memcpy(entry->ace_id->id_data, &u_g_id, sizeof (id_t));
2351 entry->ace_access = bits;
2352 DEBUG(10,("entry->ace_access = %d\n",entry->ace_access));
2354 return 0;
2357 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits)
2359 DEBUG(10,("Starting AIX sys_acl_set_permset\n"));
2360 entry->ace_access = bits;
2361 DEBUG(10,("entry->ace_access = %d\n",entry->ace_access));
2362 DEBUG(10,("Ending AIX sys_acl_set_permset\n"));
2363 return(0);
2366 int sys_acl_valid( SMB_ACL_T theacl )
2368 int user_obj = 0;
2369 int group_obj = 0;
2370 int other_obj = 0;
2371 struct acl_entry_link *acl_entry;
2373 for(acl_entry=theacl; acl_entry != NULL; acl_entry = acl_entry->nextp) {
2374 user_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_USER_OBJ);
2375 group_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_GROUP_OBJ);
2376 other_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_OTHER);
2379 DEBUG(10,("user_obj=%d, group_obj=%d, other_obj=%d\n",user_obj,group_obj,other_obj));
2381 if(user_obj != 1 || group_obj != 1 || other_obj != 1)
2382 return(-1);
2384 return(0);
2387 int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
2389 struct acl_entry_link *acl_entry_link = NULL;
2390 struct acl *file_acl = NULL;
2391 struct acl *file_acl_temp = NULL;
2392 struct acl_entry *acl_entry = NULL;
2393 struct ace_id *ace_id = NULL;
2394 uint id_type;
2395 uint user_id;
2396 uint acl_length;
2397 uint rc;
2399 DEBUG(10,("Entering sys_acl_set_file\n"));
2400 DEBUG(10,("File name is %s\n",name));
2402 /* AIX has no default ACL */
2403 if(acltype == SMB_ACL_TYPE_DEFAULT)
2404 return(0);
2406 acl_length = BUFSIZ;
2407 file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2409 if(file_acl == NULL) {
2410 errno = ENOMEM;
2411 DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
2412 return(-1);
2415 memset(file_acl,0,BUFSIZ);
2417 file_acl->acl_len = ACL_SIZ;
2418 file_acl->acl_mode = S_IXACL;
2420 for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
2421 acl_entry_link->entryp->ace_access >>= 6;
2422 id_type = acl_entry_link->entryp->ace_id->id_type;
2424 switch(id_type) {
2425 case SMB_ACL_USER_OBJ:
2426 file_acl->u_access = acl_entry_link->entryp->ace_access;
2427 continue;
2428 case SMB_ACL_GROUP_OBJ:
2429 file_acl->g_access = acl_entry_link->entryp->ace_access;
2430 continue;
2431 case SMB_ACL_OTHER:
2432 file_acl->o_access = acl_entry_link->entryp->ace_access;
2433 continue;
2434 case SMB_ACL_MASK:
2435 continue;
2438 if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
2439 acl_length += sizeof(struct acl_entry);
2440 file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
2441 if(file_acl_temp == NULL) {
2442 SAFE_FREE(file_acl);
2443 errno = ENOMEM;
2444 DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
2445 return(-1);
2448 memcpy(file_acl_temp,file_acl,file_acl->acl_len);
2449 SAFE_FREE(file_acl);
2450 file_acl = file_acl_temp;
2453 acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
2454 file_acl->acl_len += sizeof(struct acl_entry);
2455 acl_entry->ace_len = acl_entry_link->entryp->ace_len;
2456 acl_entry->ace_access = acl_entry_link->entryp->ace_access;
2458 /* In order to use this, we'll need to wait until we can get denies */
2459 /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
2460 acl_entry->ace_type = ACC_SPECIFY; */
2462 acl_entry->ace_type = ACC_SPECIFY;
2464 ace_id = acl_entry->ace_id;
2466 ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
2467 DEBUG(10,("The id type is %d\n",ace_id->id_type));
2468 ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
2469 memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
2470 memcpy(acl_entry->ace_id->id_data, &user_id, sizeof(uid_t));
2473 rc = chacl((char*)name,file_acl,file_acl->acl_len);
2474 DEBUG(10,("errno is %d\n",errno));
2475 DEBUG(10,("return code is %d\n",rc));
2476 SAFE_FREE(file_acl);
2477 DEBUG(10,("Exiting the sys_acl_set_file\n"));
2478 return(rc);
2481 #if 0
2482 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
2484 struct acl_entry_link *acl_entry_link = NULL;
2485 struct acl *file_acl = NULL;
2486 struct acl *file_acl_temp = NULL;
2487 struct acl_entry *acl_entry = NULL;
2488 struct ace_id *ace_id = NULL;
2489 uint id_type;
2490 uint user_id;
2491 uint acl_length;
2492 uint rc;
2494 DEBUG(10,("Entering sys_acl_set_fd\n"));
2495 acl_length = BUFSIZ;
2496 file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2498 if(file_acl == NULL) {
2499 errno = ENOMEM;
2500 DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
2501 return(-1);
2504 memset(file_acl,0,BUFSIZ);
2506 file_acl->acl_len = ACL_SIZ;
2507 file_acl->acl_mode = S_IXACL;
2509 for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
2510 acl_entry_link->entryp->ace_access >>= 6;
2511 id_type = acl_entry_link->entryp->ace_id->id_type;
2512 DEBUG(10,("The id_type is %d\n",id_type));
2514 switch(id_type) {
2515 case SMB_ACL_USER_OBJ:
2516 file_acl->u_access = acl_entry_link->entryp->ace_access;
2517 continue;
2518 case SMB_ACL_GROUP_OBJ:
2519 file_acl->g_access = acl_entry_link->entryp->ace_access;
2520 continue;
2521 case SMB_ACL_OTHER:
2522 file_acl->o_access = acl_entry_link->entryp->ace_access;
2523 continue;
2524 case SMB_ACL_MASK:
2525 continue;
2528 if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
2529 acl_length += sizeof(struct acl_entry);
2530 file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
2531 if(file_acl_temp == NULL) {
2532 SAFE_FREE(file_acl);
2533 errno = ENOMEM;
2534 DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
2535 return(-1);
2538 memcpy(file_acl_temp,file_acl,file_acl->acl_len);
2539 SAFE_FREE(file_acl);
2540 file_acl = file_acl_temp;
2543 acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
2544 file_acl->acl_len += sizeof(struct acl_entry);
2545 acl_entry->ace_len = acl_entry_link->entryp->ace_len;
2546 acl_entry->ace_access = acl_entry_link->entryp->ace_access;
2548 /* In order to use this, we'll need to wait until we can get denies */
2549 /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
2550 acl_entry->ace_type = ACC_SPECIFY; */
2552 acl_entry->ace_type = ACC_SPECIFY;
2554 ace_id = acl_entry->ace_id;
2556 ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
2557 DEBUG(10,("The id type is %d\n",ace_id->id_type));
2558 ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
2559 memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
2560 memcpy(ace_id->id_data, &user_id, sizeof(uid_t));
2563 rc = fchacl(fd,file_acl,file_acl->acl_len);
2564 DEBUG(10,("errno is %d\n",errno));
2565 DEBUG(10,("return code is %d\n",rc));
2566 SAFE_FREE(file_acl);
2567 DEBUG(10,("Exiting sys_acl_set_fd\n"));
2568 return(rc);
2570 #endif
2572 int sys_acl_delete_def_file(UNUSED(const char *name))
2574 /* AIX has no default ACL */
2575 return 0;
2578 int sys_acl_free_acl(SMB_ACL_T posix_acl)
2580 struct acl_entry_link *acl_entry_link;
2582 for(acl_entry_link = posix_acl->nextp; acl_entry_link->nextp != NULL; acl_entry_link = acl_entry_link->nextp) {
2583 SAFE_FREE(acl_entry_link->prevp->entryp);
2584 SAFE_FREE(acl_entry_link->prevp);
2587 SAFE_FREE(acl_entry_link->prevp->entryp);
2588 SAFE_FREE(acl_entry_link->prevp);
2589 SAFE_FREE(acl_entry_link->entryp);
2590 SAFE_FREE(acl_entry_link);
2592 return(0);
2595 #elif defined(HAVE_OSX_ACLS) /*----------------------------------------------*/
2597 #define OSX_BROKEN_GETENTRY /* returns 0 instead of 1 */
2599 #include <membership.h>
2601 int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
2603 int ret = acl_get_entry(the_acl, entry_id, entry_p);
2604 #ifdef OSX_BROKEN_GETENTRY
2605 if (ret == 0)
2606 ret = 1;
2607 else if (ret == -1 && errno == 22)
2608 ret = 0;
2609 #endif
2610 return ret;
2613 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
2615 if (type == ACL_TYPE_DEFAULT) {
2616 errno = ENOTSUP;
2617 return NULL;
2619 errno = 0;
2620 return acl_get_file(path_p, type);
2623 #if 0
2624 SMB_ACL_T sys_acl_get_fd(int fd)
2626 return acl_get_fd(fd);
2628 #endif
2630 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)
2632 uuid_t *uup;
2633 acl_tag_t tag;
2634 acl_flagset_t flagset;
2635 acl_permset_t permset;
2636 uint32 bits, fb, bb, pb;
2637 int id_type = -1;
2638 int rc;
2640 if (acl_get_tag_type(entry, &tag) != 0
2641 || acl_get_flagset_np(entry, &flagset) != 0
2642 || acl_get_permset(entry, &permset) != 0
2643 || (uup = acl_get_qualifier(entry)) == NULL)
2644 return -1;
2646 rc = mbr_uuid_to_id(*uup, u_g_id_p, &id_type);
2647 acl_free(uup);
2648 if (rc != 0)
2649 return rc;
2651 if (id_type == ID_TYPE_UID)
2652 *tag_type_p = SMB_ACL_USER;
2653 else
2654 *tag_type_p = SMB_ACL_GROUP;
2656 bits = tag == ACL_EXTENDED_ALLOW ? 1 : 0;
2658 for (fb = (1u<<4), bb = (1u<<1); bb < (1u<<12); fb *= 2, bb *= 2) {
2659 if (acl_get_flag_np(flagset, fb) == 1)
2660 bits |= bb;
2663 for (pb = (1u<<1), bb = (1u<<12); bb < (1u<<25); pb *= 2, bb *= 2) {
2664 if (acl_get_perm_np(permset, pb) == 1)
2665 bits |= bb;
2668 *bits_p = bits;
2670 return 0;
2673 SMB_ACL_T sys_acl_init(int count)
2675 return acl_init(count);
2678 int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
2680 return acl_create_entry(pacl, pentry);
2683 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
2685 acl_flagset_t flagset;
2686 acl_permset_t permset;
2687 uint32 fb, bb, pb;
2688 int is_user = tag_type == SMB_ACL_USER;
2689 uuid_t uu;
2690 int rc;
2692 tag_type = bits & 1 ? ACL_EXTENDED_ALLOW : ACL_EXTENDED_DENY;
2694 if (acl_get_flagset_np(entry, &flagset) != 0
2695 || acl_get_permset(entry, &permset) != 0)
2696 return -1;
2698 acl_clear_flags_np(flagset);
2699 acl_clear_perms(permset);
2701 for (fb = (1u<<4), bb = (1u<<1); bb < (1u<<12); fb *= 2, bb *= 2) {
2702 if (bits & bb)
2703 acl_add_flag_np(flagset, fb);
2706 for (pb = (1u<<1), bb = (1u<<12); bb < (1u<<25); pb *= 2, bb *= 2) {
2707 if (bits & bb)
2708 acl_add_perm(permset, pb);
2711 if (is_user)
2712 rc = mbr_uid_to_uuid(u_g_id, uu);
2713 else
2714 rc = mbr_gid_to_uuid(u_g_id, uu);
2715 if (rc != 0)
2716 return rc;
2718 if (acl_set_tag_type(entry, tag_type) != 0
2719 || acl_set_qualifier(entry, &uu) != 0
2720 || acl_set_permset(entry, permset) != 0
2721 || acl_set_flagset_np(entry, flagset) != 0)
2722 return -1;
2724 return 0;
2727 #if 0
2728 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits)
2730 return -1; /* Not needed for OS X. */
2732 #endif
2734 int sys_acl_valid(SMB_ACL_T theacl)
2736 return acl_valid(theacl);
2739 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
2741 return acl_set_file(name, acltype, theacl);
2744 #if 0
2745 int sys_acl_set_fd(int fd, SMB_ACL_T theacl)
2747 return acl_set_fd(fd, theacl);
2749 #endif
2751 int sys_acl_delete_def_file(const char *name)
2753 return acl_delete_def_file(name);
2756 int sys_acl_free_acl(SMB_ACL_T the_acl)
2758 return acl_free(the_acl);
2761 #else /* No ACLs. */
2763 #error No ACL functions defined for this platform!
2765 #endif
2767 /************************************************************************
2768 Deliberately outside the ACL defines. Return 1 if this is a "no acls"
2769 errno, 0 if not.
2770 ************************************************************************/
2772 int no_acl_syscall_error(int err)
2774 #ifdef HAVE_OSX_ACLS
2775 if (err == ENOENT)
2776 return 1; /* Weird problem with directory ACLs. */
2777 #endif
2778 #if defined(ENOSYS)
2779 if (err == ENOSYS) {
2780 return 1;
2782 #endif
2783 #if defined(ENOTSUP)
2784 if (err == ENOTSUP) {
2785 return 1;
2787 #endif
2788 if (err == EINVAL) {
2789 /* If the type of SMB_ACL_TYPE_ACCESS or SMB_ACL_TYPE_DEFAULT
2790 * isn't valid, then the ACLs must be non-POSIX. */
2791 return 1;
2793 return 0;
2796 #endif /* SUPPORT_ACLS */