Fixed get_xattr_acl() -- it needed to zero *len_p.
[rsync.git] / lib / sysacls.c
blobbeb6d0c2f986bd395dff099ac4b4315a20045211
1 /*
2 * Unix SMB/CIFS implementation.
3 * Based on the Samba ACL support code.
4 * Copyright (C) Jeremy Allison 2000.
6 * The permission functions have been changed to get/set all bits via
7 * one call. Some functions that rsync doesn't need were also removed.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * with this program; if not, visit the http://fsf.org website.
23 #include "rsync.h"
24 #include "sysacls.h"
26 #ifdef SUPPORT_ACLS
28 #ifdef DEBUG
29 #undef DEBUG
30 #endif
31 #define DEBUG(x,y)
33 void SAFE_FREE(void *mem)
35 if (mem)
36 free(mem);
40 This file wraps all differing system ACL interfaces into a consistent
41 one based on the POSIX interface. It also returns the correct errors
42 for older UNIX systems that don't support ACLs.
44 The interfaces that each ACL implementation must support are as follows :
46 int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
47 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
48 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)
49 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
50 SMB_ACL_T sys_acl_get_fd(int fd)
51 SMB_ACL_T sys_acl_init( int count)
52 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
53 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
54 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits)
55 int sys_acl_valid( SMB_ACL_T theacl )
56 int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
57 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
58 int sys_acl_delete_def_file(const char *path)
59 int sys_acl_free_acl(SMB_ACL_T posix_acl)
63 #if defined(HAVE_POSIX_ACLS) /*--------------------------------------------*/
65 /* Identity mapping - easy. */
67 int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
69 return acl_get_entry( the_acl, entry_id, entry_p);
72 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
74 return acl_get_tag_type( entry_d, tag_type_p);
77 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
79 return acl_get_file( path_p, type);
82 #if 0
83 SMB_ACL_T sys_acl_get_fd(int fd)
85 return acl_get_fd(fd);
87 #endif
89 #if defined(HAVE_ACL_GET_PERM_NP)
90 #define acl_get_perm(p, b) acl_get_perm_np(p, b)
91 #endif
93 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)
95 acl_permset_t permset;
97 if (acl_get_tag_type(entry, tag_type_p) != 0
98 || acl_get_permset(entry, &permset) != 0)
99 return -1;
101 *bits_p = (acl_get_perm(permset, ACL_READ) ? 4 : 0)
102 | (acl_get_perm(permset, ACL_WRITE) ? 2 : 0)
103 | (acl_get_perm(permset, ACL_EXECUTE) ? 1 : 0);
105 if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP) {
106 void *qual;
107 if ((qual = acl_get_qualifier(entry)) == NULL)
108 return -1;
109 *u_g_id_p = *(id_t*)qual;
110 acl_free(qual);
113 return 0;
116 SMB_ACL_T sys_acl_init( int count)
118 return acl_init(count);
121 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
123 return acl_create_entry(pacl, pentry);
126 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
128 if (acl_set_tag_type(entry, tag_type) != 0)
129 return -1;
131 if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP) {
132 if (acl_set_qualifier(entry, (void*)&u_g_id) != 0)
133 return -1;
136 return sys_acl_set_access_bits(entry, bits);
139 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits)
141 acl_permset_t permset;
142 int rc;
143 if ((rc = acl_get_permset(entry, &permset)) != 0)
144 return rc;
145 acl_clear_perms(permset);
146 if (bits & 4)
147 acl_add_perm(permset, ACL_READ);
148 if (bits & 2)
149 acl_add_perm(permset, ACL_WRITE);
150 if (bits & 1)
151 acl_add_perm(permset, ACL_EXECUTE);
152 return acl_set_permset(entry, permset);
155 int sys_acl_valid( SMB_ACL_T theacl )
157 return acl_valid(theacl);
160 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
162 return acl_set_file(name, acltype, theacl);
165 #if 0
166 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
168 return acl_set_fd(fd, theacl);
170 #endif
172 int sys_acl_delete_def_file(const char *name)
174 return acl_delete_def_file(name);
177 int sys_acl_free_acl(SMB_ACL_T the_acl)
179 return acl_free(the_acl);
182 #elif defined(HAVE_TRU64_ACLS) /*--------------------------------------------*/
184 * The interface to DEC/Compaq Tru64 UNIX ACLs
185 * is based on Draft 13 of the POSIX spec which is
186 * slightly different from the Draft 16 interface.
188 * Also, some of the permset manipulation functions
189 * such as acl_clear_perm() and acl_add_perm() appear
190 * to be broken on Tru64 so we have to manipulate
191 * the permission bits in the permset directly.
193 int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
195 SMB_ACL_ENTRY_T entry;
197 if (entry_id == SMB_ACL_FIRST_ENTRY && acl_first_entry(the_acl) != 0) {
198 return -1;
201 errno = 0;
202 if ((entry = acl_get_entry(the_acl)) != NULL) {
203 *entry_p = entry;
204 return 1;
207 return errno ? -1 : 0;
210 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
212 return acl_get_tag_type( entry_d, tag_type_p);
215 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
217 return acl_get_file((char *)path_p, type);
220 #if 0
221 SMB_ACL_T sys_acl_get_fd(int fd)
223 return acl_get_fd(fd, ACL_TYPE_ACCESS);
225 #endif
227 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)
229 acl_permset_t permset;
231 if (acl_get_tag_type(entry, tag_type_p) != 0
232 || acl_get_permset(entry, &permset) != 0)
233 return -1;
235 *bits_p = *permset & 7; /* Tru64 doesn't have acl_get_perm() */
237 if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP) {
238 void *qual;
239 if ((qual = acl_get_qualifier(entry)) == NULL)
240 return -1;
241 *u_g_id_p = *(id_t*)qual;
242 acl_free_qualifier(qual, *tag_type_p);
245 return 0;
248 SMB_ACL_T sys_acl_init( int count)
250 return acl_init(count);
253 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
255 SMB_ACL_ENTRY_T entry;
257 if ((entry = acl_create_entry(pacl)) == NULL) {
258 return -1;
261 *pentry = entry;
262 return 0;
265 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
267 if (acl_set_tag_type(entry, tag_type) != 0)
268 return -1;
270 if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP) {
271 if (acl_set_qualifier(entry, (void*)&u_g_id) != 0)
272 return -1;
275 return sys_acl_set_access_bits(entry, bits);
278 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits)
280 acl_permset_t permset;
281 int rc;
282 if ((rc = acl_get_permset(entry, &permset)) != 0)
283 return rc;
284 *permset = bits & 7;
285 return acl_set_permset(entry, permset);
288 int sys_acl_valid( SMB_ACL_T theacl )
290 acl_entry_t entry;
292 return acl_valid(theacl, &entry);
295 int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
297 return acl_set_file((char *)name, acltype, theacl);
300 #if 0
301 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
303 return acl_set_fd(fd, ACL_TYPE_ACCESS, theacl);
305 #endif
307 int sys_acl_delete_def_file(const char *name)
309 return acl_delete_def_file((char *)name);
312 int sys_acl_free_acl(SMB_ACL_T the_acl)
314 return acl_free(the_acl);
317 #elif defined(HAVE_UNIXWARE_ACLS) || defined(HAVE_SOLARIS_ACLS) /*-----------*/
320 * Donated by Michael Davidson <md@sco.COM> for UnixWare / OpenUNIX.
321 * Modified by Toomas Soome <tsoome@ut.ee> for Solaris.
325 * Note that while this code implements sufficient functionality
326 * to support the sys_acl_* interfaces it does not provide all
327 * of the semantics of the POSIX ACL interfaces.
329 * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
330 * from a call to sys_acl_get_entry() should not be assumed to be
331 * valid after calling any of the following functions, which may
332 * reorder the entries in the ACL.
334 * sys_acl_valid()
335 * sys_acl_set_file()
336 * sys_acl_set_fd()
340 * The only difference between Solaris and UnixWare / OpenUNIX is
341 * that the #defines for the ACL operations have different names
343 #if defined(HAVE_UNIXWARE_ACLS)
345 #define SETACL ACL_SET
346 #define GETACL ACL_GET
347 #define GETACLCNT ACL_CNT
349 #endif
352 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
354 if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
355 errno = EINVAL;
356 return -1;
359 if (entry_p == NULL) {
360 errno = EINVAL;
361 return -1;
364 if (entry_id == SMB_ACL_FIRST_ENTRY) {
365 acl_d->next = 0;
368 if (acl_d->next < 0) {
369 errno = EINVAL;
370 return -1;
373 if (acl_d->next >= acl_d->count) {
374 return 0;
377 *entry_p = &acl_d->acl[acl_d->next++];
379 return 1;
382 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
384 *type_p = entry_d->a_type;
386 return 0;
390 * There is no way of knowing what size the ACL returned by
391 * GETACL will be unless you first call GETACLCNT which means
392 * making an additional system call.
394 * In the hope of avoiding the cost of the additional system
395 * call in most cases, we initially allocate enough space for
396 * an ACL with INITIAL_ACL_SIZE entries. If this turns out to
397 * be too small then we use GETACLCNT to find out the actual
398 * size, reallocate the ACL buffer, and then call GETACL again.
401 #define INITIAL_ACL_SIZE 16
403 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
405 SMB_ACL_T acl_d;
406 int count; /* # of ACL entries allocated */
407 int naccess; /* # of access ACL entries */
408 int ndefault; /* # of default ACL entries */
410 if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
411 errno = EINVAL;
412 return NULL;
415 count = INITIAL_ACL_SIZE;
416 if ((acl_d = sys_acl_init(count)) == NULL) {
417 return NULL;
421 * If there isn't enough space for the ACL entries we use
422 * GETACLCNT to determine the actual number of ACL entries
423 * reallocate and try again. This is in a loop because it
424 * is possible that someone else could modify the ACL and
425 * increase the number of entries between the call to
426 * GETACLCNT and the call to GETACL.
428 while ((count = acl(path_p, GETACL, count, &acl_d->acl[0])) < 0
429 && errno == ENOSPC) {
431 sys_acl_free_acl(acl_d);
433 if ((count = acl(path_p, GETACLCNT, 0, NULL)) < 0) {
434 return NULL;
437 if ((acl_d = sys_acl_init(count)) == NULL) {
438 return NULL;
442 if (count < 0) {
443 sys_acl_free_acl(acl_d);
444 return NULL;
448 * calculate the number of access and default ACL entries
450 * Note: we assume that the acl() system call returned a
451 * well formed ACL which is sorted so that all of the
452 * access ACL entries preceed any default ACL entries
454 for (naccess = 0; naccess < count; naccess++) {
455 if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
456 break;
458 ndefault = count - naccess;
461 * if the caller wants the default ACL we have to copy
462 * the entries down to the start of the acl[] buffer
463 * and mask out the ACL_DEFAULT flag from the type field
465 if (type == SMB_ACL_TYPE_DEFAULT) {
466 int i, j;
468 for (i = 0, j = naccess; i < ndefault; i++, j++) {
469 acl_d->acl[i] = acl_d->acl[j];
470 acl_d->acl[i].a_type &= ~ACL_DEFAULT;
473 acl_d->count = ndefault;
474 } else {
475 acl_d->count = naccess;
478 return acl_d;
481 #if 0
482 SMB_ACL_T sys_acl_get_fd(int fd)
484 SMB_ACL_T acl_d;
485 int count; /* # of ACL entries allocated */
486 int naccess; /* # of access ACL entries */
488 count = INITIAL_ACL_SIZE;
489 if ((acl_d = sys_acl_init(count)) == NULL) {
490 return NULL;
493 while ((count = facl(fd, GETACL, count, &acl_d->acl[0])) < 0
494 && errno == ENOSPC) {
496 sys_acl_free_acl(acl_d);
498 if ((count = facl(fd, GETACLCNT, 0, NULL)) < 0) {
499 return NULL;
502 if ((acl_d = sys_acl_init(count)) == NULL) {
503 return NULL;
507 if (count < 0) {
508 sys_acl_free_acl(acl_d);
509 return NULL;
513 * calculate the number of access ACL entries
515 for (naccess = 0; naccess < count; naccess++) {
516 if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
517 break;
520 acl_d->count = naccess;
522 return acl_d;
524 #endif
526 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)
528 *tag_type_p = entry->a_type;
530 *bits_p = entry->a_perm;
532 if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP)
533 *u_g_id_p = entry->a_id;
535 return 0;
538 SMB_ACL_T sys_acl_init(int count)
540 SMB_ACL_T a;
542 if (count < 0) {
543 errno = EINVAL;
544 return NULL;
548 * note that since the definition of the structure pointed
549 * to by the SMB_ACL_T includes the first element of the
550 * acl[] array, this actually allocates an ACL with room
551 * for (count+1) entries
553 if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof(struct SMB_ACL_T) + count * sizeof(struct acl))) == NULL) {
554 errno = ENOMEM;
555 return NULL;
558 a->size = count + 1;
559 a->count = 0;
560 a->next = -1;
562 return a;
566 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
568 SMB_ACL_T acl_d;
569 SMB_ACL_ENTRY_T entry_d;
571 if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
572 errno = EINVAL;
573 return -1;
576 if (acl_d->count >= acl_d->size) {
577 errno = ENOSPC;
578 return -1;
581 entry_d = &acl_d->acl[acl_d->count++];
582 entry_d->a_type = 0;
583 entry_d->a_id = -1;
584 entry_d->a_perm = 0;
585 *entry_p = entry_d;
587 return 0;
590 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
592 entry->a_type = tag_type;
594 if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP)
595 entry->a_id = u_g_id;
597 entry->a_perm = bits;
599 return 0;
602 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry_d, uint32 bits)
604 entry_d->a_perm = bits;
605 return 0;
609 * sort the ACL and check it for validity
611 * if it's a minimal ACL with only 4 entries then we
612 * need to recalculate the mask permissions to make
613 * sure that they are the same as the GROUP_OBJ
614 * permissions as required by the UnixWare acl() system call.
616 * (note: since POSIX allows minimal ACLs which only contain
617 * 3 entries - ie there is no mask entry - we should, in theory,
618 * check for this and add a mask entry if necessary - however
619 * we "know" that the caller of this interface always specifies
620 * a mask so, in practice "this never happens" (tm) - if it *does*
621 * happen aclsort() will fail and return an error and someone will
622 * have to fix it ...)
625 static int acl_sort(SMB_ACL_T acl_d)
627 int fixmask = (acl_d->count <= 4);
629 if (aclsort(acl_d->count, fixmask, acl_d->acl) != 0) {
630 errno = EINVAL;
631 return -1;
633 return 0;
636 int sys_acl_valid(SMB_ACL_T acl_d)
638 return acl_sort(acl_d);
641 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
643 struct stat s;
644 struct acl *acl_p;
645 int acl_count;
646 struct acl *acl_buf = NULL;
647 int ret;
649 if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
650 errno = EINVAL;
651 return -1;
654 if (acl_sort(acl_d) != 0) {
655 return -1;
658 acl_p = &acl_d->acl[0];
659 acl_count = acl_d->count;
662 * if it's a directory there is extra work to do
663 * since the acl() system call will replace both
664 * the access ACLs and the default ACLs (if any)
666 if (stat(name, &s) != 0) {
667 return -1;
669 if (S_ISDIR(s.st_mode)) {
670 SMB_ACL_T acc_acl;
671 SMB_ACL_T def_acl;
672 SMB_ACL_T tmp_acl;
673 int i;
675 if (type == SMB_ACL_TYPE_ACCESS) {
676 acc_acl = acl_d;
677 def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
679 } else {
680 def_acl = acl_d;
681 acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
684 if (tmp_acl == NULL) {
685 return -1;
689 * allocate a temporary buffer for the complete ACL
691 acl_count = acc_acl->count + def_acl->count;
692 acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count);
694 if (acl_buf == NULL) {
695 sys_acl_free_acl(tmp_acl);
696 errno = ENOMEM;
697 return -1;
701 * copy the access control and default entries into the buffer
703 memcpy(&acl_buf[0], &acc_acl->acl[0],
704 acc_acl->count * sizeof(acl_buf[0]));
706 memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
707 def_acl->count * sizeof(acl_buf[0]));
710 * set the ACL_DEFAULT flag on the default entries
712 for (i = acc_acl->count; i < acl_count; i++) {
713 acl_buf[i].a_type |= ACL_DEFAULT;
716 sys_acl_free_acl(tmp_acl);
718 } else if (type != SMB_ACL_TYPE_ACCESS) {
719 errno = EINVAL;
720 return -1;
723 ret = acl(name, SETACL, acl_count, acl_p);
725 SAFE_FREE(acl_buf);
727 return ret;
730 #if 0
731 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
733 if (acl_sort(acl_d) != 0) {
734 return -1;
737 return facl(fd, SETACL, acl_d->count, &acl_d->acl[0]);
739 #endif
741 int sys_acl_delete_def_file(const char *path)
743 SMB_ACL_T acl_d;
744 int ret;
747 * fetching the access ACL and rewriting it has
748 * the effect of deleting the default ACL
750 if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
751 return -1;
754 ret = acl(path, SETACL, acl_d->count, acl_d->acl);
756 sys_acl_free_acl(acl_d);
758 return ret;
761 int sys_acl_free_acl(SMB_ACL_T acl_d)
763 SAFE_FREE(acl_d);
764 return 0;
767 #elif defined(HAVE_HPUX_ACLS) /*---------------------------------------------*/
769 #include <dl.h>
772 * Based on the Solaris/SCO code - with modifications.
776 * Note that while this code implements sufficient functionality
777 * to support the sys_acl_* interfaces it does not provide all
778 * of the semantics of the POSIX ACL interfaces.
780 * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
781 * from a call to sys_acl_get_entry() should not be assumed to be
782 * valid after calling any of the following functions, which may
783 * reorder the entries in the ACL.
785 * sys_acl_valid()
786 * sys_acl_set_file()
787 * sys_acl_set_fd()
790 /* This checks if the POSIX ACL system call is defined */
791 /* which basically corresponds to whether JFS 3.3 or */
792 /* higher is installed. If acl() was called when it */
793 /* isn't defined, it causes the process to core dump */
794 /* so it is important to check this and avoid acl() */
795 /* calls if it isn't there. */
797 static BOOL hpux_acl_call_presence(void)
800 shl_t handle = NULL;
801 void *value;
802 int ret_val=0;
803 static BOOL already_checked=0;
805 if(already_checked)
806 return True;
809 ret_val = shl_findsym(&handle, "acl", TYPE_PROCEDURE, &value);
811 if(ret_val != 0) {
812 DEBUG(5, ("hpux_acl_call_presence: shl_findsym() returned %d, errno = %d, error %s\n",
813 ret_val, errno, strerror(errno)));
814 DEBUG(5,("hpux_acl_call_presence: acl() system call is not present. Check if you have JFS 3.3 and above?\n"));
815 return False;
818 DEBUG(10,("hpux_acl_call_presence: acl() system call is present. We have JFS 3.3 or above \n"));
820 already_checked = True;
821 return True;
824 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
826 if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
827 errno = EINVAL;
828 return -1;
831 if (entry_p == NULL) {
832 errno = EINVAL;
833 return -1;
836 if (entry_id == SMB_ACL_FIRST_ENTRY) {
837 acl_d->next = 0;
840 if (acl_d->next < 0) {
841 errno = EINVAL;
842 return -1;
845 if (acl_d->next >= acl_d->count) {
846 return 0;
849 *entry_p = &acl_d->acl[acl_d->next++];
851 return 1;
854 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
856 *type_p = entry_d->a_type;
858 return 0;
862 * There is no way of knowing what size the ACL returned by
863 * ACL_GET will be unless you first call ACL_CNT which means
864 * making an additional system call.
866 * In the hope of avoiding the cost of the additional system
867 * call in most cases, we initially allocate enough space for
868 * an ACL with INITIAL_ACL_SIZE entries. If this turns out to
869 * be too small then we use ACL_CNT to find out the actual
870 * size, reallocate the ACL buffer, and then call ACL_GET again.
873 #define INITIAL_ACL_SIZE 16
875 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
877 SMB_ACL_T acl_d;
878 int count; /* # of ACL entries allocated */
879 int naccess; /* # of access ACL entries */
880 int ndefault; /* # of default ACL entries */
882 if(hpux_acl_call_presence() == False) {
883 /* Looks like we don't have the acl() system call on HPUX.
884 * May be the system doesn't have the latest version of JFS.
886 return NULL;
889 if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
890 errno = EINVAL;
891 return NULL;
894 count = INITIAL_ACL_SIZE;
895 if ((acl_d = sys_acl_init(count)) == NULL) {
896 return NULL;
900 * If there isn't enough space for the ACL entries we use
901 * ACL_CNT to determine the actual number of ACL entries
902 * reallocate and try again. This is in a loop because it
903 * is possible that someone else could modify the ACL and
904 * increase the number of entries between the call to
905 * ACL_CNT and the call to ACL_GET.
907 while ((count = acl(path_p, ACL_GET, count, &acl_d->acl[0])) < 0 && errno == ENOSPC) {
909 sys_acl_free_acl(acl_d);
911 if ((count = acl(path_p, ACL_CNT, 0, NULL)) < 0) {
912 return NULL;
915 if ((acl_d = sys_acl_init(count)) == NULL) {
916 return NULL;
920 if (count < 0) {
921 sys_acl_free_acl(acl_d);
922 return NULL;
926 * calculate the number of access and default ACL entries
928 * Note: we assume that the acl() system call returned a
929 * well formed ACL which is sorted so that all of the
930 * access ACL entries preceed any default ACL entries
932 for (naccess = 0; naccess < count; naccess++) {
933 if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
934 break;
936 ndefault = count - naccess;
939 * if the caller wants the default ACL we have to copy
940 * the entries down to the start of the acl[] buffer
941 * and mask out the ACL_DEFAULT flag from the type field
943 if (type == SMB_ACL_TYPE_DEFAULT) {
944 int i, j;
946 for (i = 0, j = naccess; i < ndefault; i++, j++) {
947 acl_d->acl[i] = acl_d->acl[j];
948 acl_d->acl[i].a_type &= ~ACL_DEFAULT;
951 acl_d->count = ndefault;
952 } else {
953 acl_d->count = naccess;
956 return acl_d;
959 #if 0
960 SMB_ACL_T sys_acl_get_fd(int fd)
963 * HPUX doesn't have the facl call. Fake it using the path.... JRA.
966 files_struct *fsp = file_find_fd(fd);
968 if (fsp == NULL) {
969 errno = EBADF;
970 return NULL;
974 * We know we're in the same conn context. So we
975 * can use the relative path.
978 return sys_acl_get_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
980 #endif
982 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)
984 *tag_type_p = entry->a_type;
986 *bits_p = entry->a_perm;
988 if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP)
989 *u_g_id_p = entry->a_id;
991 return 0;
994 SMB_ACL_T sys_acl_init(int count)
996 SMB_ACL_T a;
998 if (count < 0) {
999 errno = EINVAL;
1000 return NULL;
1004 * note that since the definition of the structure pointed
1005 * to by the SMB_ACL_T includes the first element of the
1006 * acl[] array, this actually allocates an ACL with room
1007 * for (count+1) entries
1009 if ((a = SMB_MALLOC(sizeof(struct SMB_ACL_T) + count * sizeof(struct acl))) == NULL) {
1010 errno = ENOMEM;
1011 return NULL;
1014 a->size = count + 1;
1015 a->count = 0;
1016 a->next = -1;
1018 return a;
1022 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
1024 SMB_ACL_T acl_d;
1025 SMB_ACL_ENTRY_T entry_d;
1027 if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
1028 errno = EINVAL;
1029 return -1;
1032 if (acl_d->count >= acl_d->size) {
1033 errno = ENOSPC;
1034 return -1;
1037 entry_d = &acl_d->acl[acl_d->count++];
1038 entry_d->a_type = 0;
1039 entry_d->a_id = -1;
1040 entry_d->a_perm = 0;
1041 *entry_p = entry_d;
1043 return 0;
1046 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
1048 entry->a_type = tag_type;
1050 if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP)
1051 entry->a_id = u_g_id;
1053 entry->a_perm = bits;
1055 return 0;
1058 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry_d, uint32 bits)
1060 entry_d->a_perm = bits;
1062 return 0;
1065 /* Structure to capture the count for each type of ACE. */
1067 struct hpux_acl_types {
1068 int n_user;
1069 int n_def_user;
1070 int n_user_obj;
1071 int n_def_user_obj;
1073 int n_group;
1074 int n_def_group;
1075 int n_group_obj;
1076 int n_def_group_obj;
1078 int n_other;
1079 int n_other_obj;
1080 int n_def_other_obj;
1082 int n_class_obj;
1083 int n_def_class_obj;
1085 int n_illegal_obj;
1088 /* count_obj:
1089 * Counts the different number of objects in a given array of ACL
1090 * structures.
1091 * Inputs:
1093 * acl_count - Count of ACLs in the array of ACL strucutres.
1094 * aclp - Array of ACL structures.
1095 * acl_type_count - Pointer to acl_types structure. Should already be
1096 * allocated.
1097 * Output:
1099 * acl_type_count - This structure is filled up with counts of various
1100 * acl types.
1103 static void hpux_count_obj(int acl_count, struct acl *aclp, struct hpux_acl_types *acl_type_count)
1105 int i;
1107 memset(acl_type_count, 0, sizeof(struct hpux_acl_types));
1109 for(i=0;i<acl_count;i++) {
1110 switch(aclp[i].a_type) {
1111 case USER:
1112 acl_type_count->n_user++;
1113 break;
1114 case USER_OBJ:
1115 acl_type_count->n_user_obj++;
1116 break;
1117 case DEF_USER_OBJ:
1118 acl_type_count->n_def_user_obj++;
1119 break;
1120 case GROUP:
1121 acl_type_count->n_group++;
1122 break;
1123 case GROUP_OBJ:
1124 acl_type_count->n_group_obj++;
1125 break;
1126 case DEF_GROUP_OBJ:
1127 acl_type_count->n_def_group_obj++;
1128 break;
1129 case OTHER_OBJ:
1130 acl_type_count->n_other_obj++;
1131 break;
1132 case DEF_OTHER_OBJ:
1133 acl_type_count->n_def_other_obj++;
1134 break;
1135 case CLASS_OBJ:
1136 acl_type_count->n_class_obj++;
1137 break;
1138 case DEF_CLASS_OBJ:
1139 acl_type_count->n_def_class_obj++;
1140 break;
1141 case DEF_USER:
1142 acl_type_count->n_def_user++;
1143 break;
1144 case DEF_GROUP:
1145 acl_type_count->n_def_group++;
1146 break;
1147 default:
1148 acl_type_count->n_illegal_obj++;
1149 break;
1154 /* swap_acl_entries: Swaps two ACL entries.
1156 * Inputs: aclp0, aclp1 - ACL entries to be swapped.
1159 static void hpux_swap_acl_entries(struct acl *aclp0, struct acl *aclp1)
1161 struct acl temp_acl;
1163 temp_acl.a_type = aclp0->a_type;
1164 temp_acl.a_id = aclp0->a_id;
1165 temp_acl.a_perm = aclp0->a_perm;
1167 aclp0->a_type = aclp1->a_type;
1168 aclp0->a_id = aclp1->a_id;
1169 aclp0->a_perm = aclp1->a_perm;
1171 aclp1->a_type = temp_acl.a_type;
1172 aclp1->a_id = temp_acl.a_id;
1173 aclp1->a_perm = temp_acl.a_perm;
1176 /* prohibited_duplicate_type
1177 * Identifies if given ACL type can have duplicate entries or
1178 * not.
1180 * Inputs: acl_type - ACL Type.
1182 * Outputs:
1184 * Return..
1186 * True - If the ACL type matches any of the prohibited types.
1187 * False - If the ACL type doesn't match any of the prohibited types.
1190 static BOOL hpux_prohibited_duplicate_type(int acl_type)
1192 switch(acl_type) {
1193 case USER:
1194 case GROUP:
1195 case DEF_USER:
1196 case DEF_GROUP:
1197 return True;
1198 default:
1199 return False;
1203 /* get_needed_class_perm
1204 * Returns the permissions of a ACL structure only if the ACL
1205 * type matches one of the pre-determined types for computing
1206 * CLASS_OBJ permissions.
1208 * Inputs: aclp - Pointer to ACL structure.
1211 static int hpux_get_needed_class_perm(struct acl *aclp)
1213 switch(aclp->a_type) {
1214 case USER:
1215 case GROUP_OBJ:
1216 case GROUP:
1217 case DEF_USER_OBJ:
1218 case DEF_USER:
1219 case DEF_GROUP_OBJ:
1220 case DEF_GROUP:
1221 case DEF_CLASS_OBJ:
1222 case DEF_OTHER_OBJ:
1223 return aclp->a_perm;
1224 default:
1225 return 0;
1229 /* acl_sort for HPUX.
1230 * Sorts the array of ACL structures as per the description in
1231 * aclsort man page. Refer to aclsort man page for more details
1233 * Inputs:
1235 * acl_count - Count of ACLs in the array of ACL structures.
1236 * calclass - If this is not zero, then we compute the CLASS_OBJ
1237 * permissions.
1238 * aclp - Array of ACL structures.
1240 * Outputs:
1242 * aclp - Sorted array of ACL structures.
1244 * Outputs:
1246 * Returns 0 for success -1 for failure. Prints a message to the Samba
1247 * debug log in case of failure.
1250 static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp)
1252 #if !defined(HAVE_HPUX_ACLSORT)
1254 * The aclsort() system call is availabe on the latest HPUX General
1255 * Patch Bundles. So for HPUX, we developed our version of acl_sort
1256 * function. Because, we don't want to update to a new
1257 * HPUX GR bundle just for aclsort() call.
1260 struct hpux_acl_types acl_obj_count;
1261 int n_class_obj_perm = 0;
1262 int i, j;
1264 if(!acl_count) {
1265 DEBUG(10,("Zero acl count passed. Returning Success\n"));
1266 return 0;
1269 if(aclp == NULL) {
1270 DEBUG(0,("Null ACL pointer in hpux_acl_sort. Returning Failure. \n"));
1271 return -1;
1274 /* Count different types of ACLs in the ACLs array */
1276 hpux_count_obj(acl_count, aclp, &acl_obj_count);
1278 /* There should be only one entry each of type USER_OBJ, GROUP_OBJ,
1279 * CLASS_OBJ and OTHER_OBJ
1282 if( (acl_obj_count.n_user_obj != 1) ||
1283 (acl_obj_count.n_group_obj != 1) ||
1284 (acl_obj_count.n_class_obj != 1) ||
1285 (acl_obj_count.n_other_obj != 1)
1287 DEBUG(0,("hpux_acl_sort: More than one entry or no entries for \
1288 USER OBJ or GROUP_OBJ or OTHER_OBJ or CLASS_OBJ\n"));
1289 return -1;
1292 /* If any of the default objects are present, there should be only
1293 * one of them each.
1296 if( (acl_obj_count.n_def_user_obj > 1) || (acl_obj_count.n_def_group_obj > 1) ||
1297 (acl_obj_count.n_def_other_obj > 1) || (acl_obj_count.n_def_class_obj > 1) ) {
1298 DEBUG(0,("hpux_acl_sort: More than one entry for DEF_CLASS_OBJ \
1299 or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n"));
1300 return -1;
1303 /* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl
1304 * structures.
1306 * Sorting crieteria - First sort by ACL type. If there are multiple entries of
1307 * same ACL type, sort by ACL id.
1309 * I am using the trival kind of sorting method here because, performance isn't
1310 * really effected by the ACLs feature. More over there aren't going to be more
1311 * than 17 entries on HPUX.
1314 for(i=0; i<acl_count;i++) {
1315 for (j=i+1; j<acl_count; j++) {
1316 if( aclp[i].a_type > aclp[j].a_type ) {
1317 /* ACL entries out of order, swap them */
1319 hpux_swap_acl_entries((aclp+i), (aclp+j));
1321 } else if ( aclp[i].a_type == aclp[j].a_type ) {
1323 /* ACL entries of same type, sort by id */
1325 if(aclp[i].a_id > aclp[j].a_id) {
1326 hpux_swap_acl_entries((aclp+i), (aclp+j));
1327 } else if (aclp[i].a_id == aclp[j].a_id) {
1328 /* We have a duplicate entry. */
1329 if(hpux_prohibited_duplicate_type(aclp[i].a_type)) {
1330 DEBUG(0, ("hpux_acl_sort: Duplicate entry: Type(hex): %x Id: %d\n",
1331 aclp[i].a_type, aclp[i].a_id));
1332 return -1;
1340 /* set the class obj permissions to the computed one. */
1341 if(calclass) {
1342 int n_class_obj_index = -1;
1344 for(i=0;i<acl_count;i++) {
1345 n_class_obj_perm |= hpux_get_needed_class_perm((aclp+i));
1347 if(aclp[i].a_type == CLASS_OBJ)
1348 n_class_obj_index = i;
1350 aclp[n_class_obj_index].a_perm = n_class_obj_perm;
1353 return 0;
1354 #else
1355 return aclsort(acl_count, calclass, aclp);
1356 #endif
1360 * sort the ACL and check it for validity
1362 * if it's a minimal ACL with only 4 entries then we
1363 * need to recalculate the mask permissions to make
1364 * sure that they are the same as the GROUP_OBJ
1365 * permissions as required by the UnixWare acl() system call.
1367 * (note: since POSIX allows minimal ACLs which only contain
1368 * 3 entries - ie there is no mask entry - we should, in theory,
1369 * check for this and add a mask entry if necessary - however
1370 * we "know" that the caller of this interface always specifies
1371 * a mask so, in practice "this never happens" (tm) - if it *does*
1372 * happen aclsort() will fail and return an error and someone will
1373 * have to fix it ...)
1376 static int acl_sort(SMB_ACL_T acl_d)
1378 int fixmask = (acl_d->count <= 4);
1380 if (hpux_acl_sort(acl_d->count, fixmask, acl_d->acl) != 0) {
1381 errno = EINVAL;
1382 return -1;
1384 return 0;
1387 int sys_acl_valid(SMB_ACL_T acl_d)
1389 return acl_sort(acl_d);
1392 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
1394 struct stat s;
1395 struct acl *acl_p;
1396 int acl_count;
1397 struct acl *acl_buf = NULL;
1398 int ret;
1400 if(hpux_acl_call_presence() == False) {
1401 /* Looks like we don't have the acl() system call on HPUX.
1402 * May be the system doesn't have the latest version of JFS.
1404 errno=ENOSYS;
1405 return -1;
1408 if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
1409 errno = EINVAL;
1410 return -1;
1413 if (acl_sort(acl_d) != 0) {
1414 return -1;
1417 acl_p = &acl_d->acl[0];
1418 acl_count = acl_d->count;
1421 * if it's a directory there is extra work to do
1422 * since the acl() system call will replace both
1423 * the access ACLs and the default ACLs (if any)
1425 if (stat(name, &s) != 0) {
1426 return -1;
1428 if (S_ISDIR(s.st_mode)) {
1429 SMB_ACL_T acc_acl;
1430 SMB_ACL_T def_acl;
1431 SMB_ACL_T tmp_acl;
1432 int i;
1434 if (type == SMB_ACL_TYPE_ACCESS) {
1435 acc_acl = acl_d;
1436 def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
1438 } else {
1439 def_acl = acl_d;
1440 acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
1443 if (tmp_acl == NULL) {
1444 return -1;
1448 * allocate a temporary buffer for the complete ACL
1450 acl_count = acc_acl->count + def_acl->count;
1451 acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count);
1453 if (acl_buf == NULL) {
1454 sys_acl_free_acl(tmp_acl);
1455 errno = ENOMEM;
1456 return -1;
1460 * copy the access control and default entries into the buffer
1462 memcpy(&acl_buf[0], &acc_acl->acl[0],
1463 acc_acl->count * sizeof(acl_buf[0]));
1465 memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
1466 def_acl->count * sizeof(acl_buf[0]));
1469 * set the ACL_DEFAULT flag on the default entries
1471 for (i = acc_acl->count; i < acl_count; i++) {
1472 acl_buf[i].a_type |= ACL_DEFAULT;
1475 sys_acl_free_acl(tmp_acl);
1477 } else if (type != SMB_ACL_TYPE_ACCESS) {
1478 errno = EINVAL;
1479 return -1;
1482 ret = acl(name, ACL_SET, acl_count, acl_p);
1484 if (acl_buf) {
1485 free(acl_buf);
1488 return ret;
1491 #if 0
1492 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
1495 * HPUX doesn't have the facl call. Fake it using the path.... JRA.
1498 files_struct *fsp = file_find_fd(fd);
1500 if (fsp == NULL) {
1501 errno = EBADF;
1502 return NULL;
1505 if (acl_sort(acl_d) != 0) {
1506 return -1;
1510 * We know we're in the same conn context. So we
1511 * can use the relative path.
1514 return sys_acl_set_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS, acl_d);
1516 #endif
1518 int sys_acl_delete_def_file(const char *path)
1520 SMB_ACL_T acl_d;
1521 int ret;
1524 * fetching the access ACL and rewriting it has
1525 * the effect of deleting the default ACL
1527 if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
1528 return -1;
1531 ret = acl(path, ACL_SET, acl_d->count, acl_d->acl);
1533 sys_acl_free_acl(acl_d);
1535 return ret;
1538 int sys_acl_free_acl(SMB_ACL_T acl_d)
1540 free(acl_d);
1541 return 0;
1544 #elif defined(HAVE_IRIX_ACLS) /*---------------------------------------------*/
1546 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
1548 if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
1549 errno = EINVAL;
1550 return -1;
1553 if (entry_p == NULL) {
1554 errno = EINVAL;
1555 return -1;
1558 if (entry_id == SMB_ACL_FIRST_ENTRY) {
1559 acl_d->next = 0;
1562 if (acl_d->next < 0) {
1563 errno = EINVAL;
1564 return -1;
1567 if (acl_d->next >= acl_d->aclp->acl_cnt) {
1568 return 0;
1571 *entry_p = &acl_d->aclp->acl_entry[acl_d->next++];
1573 return 1;
1576 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
1578 *type_p = entry_d->ae_tag;
1580 return 0;
1583 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
1585 SMB_ACL_T a;
1587 if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) {
1588 errno = ENOMEM;
1589 return NULL;
1591 if ((a->aclp = acl_get_file(path_p, type)) == NULL) {
1592 SAFE_FREE(a);
1593 return NULL;
1595 a->next = -1;
1596 a->freeaclp = True;
1597 return a;
1600 #if 0
1601 SMB_ACL_T sys_acl_get_fd(int fd)
1603 SMB_ACL_T a;
1605 if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) {
1606 errno = ENOMEM;
1607 return NULL;
1609 if ((a->aclp = acl_get_fd(fd)) == NULL) {
1610 SAFE_FREE(a);
1611 return NULL;
1613 a->next = -1;
1614 a->freeaclp = True;
1615 return a;
1617 #endif
1619 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)
1621 *tag_type_p = entry->ae_tag;
1623 *bits_p = entry->ae_perm;
1625 if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP)
1626 *u_g_id_p = entry->ae_id;
1628 return 0;
1631 SMB_ACL_T sys_acl_init(int count)
1633 SMB_ACL_T a;
1635 if (count < 0) {
1636 errno = EINVAL;
1637 return NULL;
1640 if ((a = SMB_MALLOC(sizeof(struct SMB_ACL_T) + sizeof(struct acl))) == NULL) {
1641 errno = ENOMEM;
1642 return NULL;
1645 a->next = -1;
1646 a->freeaclp = False;
1647 a->aclp = (struct acl *)(&a->aclp + sizeof(struct acl *));
1648 a->aclp->acl_cnt = 0;
1650 return a;
1654 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
1656 SMB_ACL_T acl_d;
1657 SMB_ACL_ENTRY_T entry_d;
1659 if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
1660 errno = EINVAL;
1661 return -1;
1664 if (acl_d->aclp->acl_cnt >= ACL_MAX_ENTRIES) {
1665 errno = ENOSPC;
1666 return -1;
1669 entry_d = &acl_d->aclp->acl_entry[acl_d->aclp->acl_cnt++];
1670 entry_d->ae_tag = 0;
1671 entry_d->ae_id = 0;
1672 entry_d->ae_perm = 0;
1673 *entry_p = entry_d;
1675 return 0;
1678 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
1680 entry->ae_tag = tag_type;
1682 if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP)
1683 entry->ae_id = u_g_id;
1685 entry->ae_perm = bits;
1687 return 0;
1690 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry_d, uint32 bits)
1692 entry_d->ae_perm = bits;
1694 return 0;
1697 int sys_acl_valid(SMB_ACL_T acl_d)
1699 return acl_valid(acl_d->aclp);
1702 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
1704 return acl_set_file(name, type, acl_d->aclp);
1707 #if 0
1708 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
1710 return acl_set_fd(fd, acl_d->aclp);
1712 #endif
1714 int sys_acl_delete_def_file(const char *name)
1716 return acl_delete_def_file(name);
1719 int sys_acl_free_acl(SMB_ACL_T acl_d)
1721 if (acl_d->freeaclp) {
1722 acl_free(acl_d->aclp);
1724 acl_free(acl_d);
1725 return 0;
1728 #elif defined(HAVE_AIX_ACLS) /*----------------------------------------------*/
1730 /* Donated by Medha Date, mdate@austin.ibm.com, for IBM */
1732 int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
1734 struct acl_entry_link *link;
1735 struct new_acl_entry *entry;
1736 int keep_going;
1738 DEBUG(10,("This is the count: %d\n",theacl->count));
1740 /* Check if count was previously set to -1. *
1741 * If it was, that means we reached the end *
1742 * of the acl last time. */
1743 if(theacl->count == -1)
1744 return(0);
1746 link = theacl;
1747 /* To get to the next acl, traverse linked list until index *
1748 * of acl matches the count we are keeping. This count is *
1749 * incremented each time we return an acl entry. */
1751 for(keep_going = 0; keep_going < theacl->count; keep_going++)
1752 link = link->nextp;
1754 entry = *entry_p = link->entryp;
1756 DEBUG(10,("*entry_p is %d\n",entry_p));
1757 DEBUG(10,("*entry_p->ace_access is %d\n",entry->ace_access));
1759 /* Increment count */
1760 theacl->count++;
1761 if(link->nextp == NULL)
1762 theacl->count = -1;
1764 return(1);
1767 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
1769 /* Initialize tag type */
1771 *tag_type_p = -1;
1772 DEBUG(10,("the tagtype is %d\n",entry_d->ace_id->id_type));
1774 /* Depending on what type of entry we have, *
1775 * return tag type. */
1776 switch(entry_d->ace_id->id_type) {
1777 case ACEID_USER:
1778 *tag_type_p = SMB_ACL_USER;
1779 break;
1780 case ACEID_GROUP:
1781 *tag_type_p = SMB_ACL_GROUP;
1782 break;
1784 case SMB_ACL_USER_OBJ:
1785 case SMB_ACL_GROUP_OBJ:
1786 case SMB_ACL_OTHER:
1787 *tag_type_p = entry_d->ace_id->id_type;
1788 break;
1790 default:
1791 return(-1);
1794 return(0);
1797 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
1799 struct acl *file_acl = (struct acl *)NULL;
1800 struct acl_entry *acl_entry;
1801 struct new_acl_entry *new_acl_entry;
1802 struct ace_id *idp;
1803 struct acl_entry_link *acl_entry_link;
1804 struct acl_entry_link *acl_entry_link_head;
1805 int i;
1806 int rc = 0;
1807 uid_t user_id;
1809 /* AIX has no DEFAULT */
1810 if ( type == SMB_ACL_TYPE_DEFAULT ) {
1811 errno = ENOTSUP;
1812 return NULL;
1815 /* Get the acl using statacl */
1817 DEBUG(10,("Entering sys_acl_get_file\n"));
1818 DEBUG(10,("path_p is %s\n",path_p));
1820 file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
1822 if(file_acl == NULL) {
1823 errno=ENOMEM;
1824 DEBUG(0,("Error in AIX sys_acl_get_file: %d\n",errno));
1825 return(NULL);
1828 memset(file_acl,0,BUFSIZ);
1830 rc = statacl((char *)path_p,0,file_acl,BUFSIZ);
1831 if(rc == -1) {
1832 DEBUG(0,("statacl returned %d with errno %d\n",rc,errno));
1833 SAFE_FREE(file_acl);
1834 return(NULL);
1837 DEBUG(10,("Got facl and returned it\n"));
1839 /* Point to the first acl entry in the acl */
1840 acl_entry = file_acl->acl_ext;
1842 /* Begin setting up the head of the linked list *
1843 * that will be used for the storing the acl *
1844 * in a way that is useful for the posix_acls.c *
1845 * code. */
1847 acl_entry_link_head = acl_entry_link = sys_acl_init(0);
1848 if(acl_entry_link_head == NULL)
1849 return(NULL);
1851 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
1852 if(acl_entry_link->entryp == NULL) {
1853 SAFE_FREE(file_acl);
1854 errno = ENOMEM;
1855 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
1856 return(NULL);
1859 DEBUG(10,("acl_entry is %d\n",acl_entry));
1860 DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
1862 /* Check if the extended acl bit is on. *
1863 * If it isn't, do not show the *
1864 * contents of the acl since AIX intends *
1865 * the extended info to remain unused */
1867 if(file_acl->acl_mode & S_IXACL){
1868 /* while we are not pointing to the very end */
1869 while(acl_entry < acl_last(file_acl)) {
1870 /* before we malloc anything, make sure this is */
1871 /* a valid acl entry and one that we want to map */
1872 idp = id_nxt(acl_entry->ace_id);
1873 if((acl_entry->ace_type == ACC_SPECIFY ||
1874 (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
1875 acl_entry = acl_nxt(acl_entry);
1876 continue;
1879 idp = acl_entry->ace_id;
1881 /* Check if this is the first entry in the linked list. *
1882 * The first entry needs to keep prevp pointing to NULL *
1883 * and already has entryp allocated. */
1885 if(acl_entry_link_head->count != 0) {
1886 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
1888 if(acl_entry_link->nextp == NULL) {
1889 SAFE_FREE(file_acl);
1890 errno = ENOMEM;
1891 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
1892 return(NULL);
1895 acl_entry_link->nextp->prevp = acl_entry_link;
1896 acl_entry_link = acl_entry_link->nextp;
1897 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
1898 if(acl_entry_link->entryp == NULL) {
1899 SAFE_FREE(file_acl);
1900 errno = ENOMEM;
1901 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
1902 return(NULL);
1904 acl_entry_link->nextp = NULL;
1907 acl_entry_link->entryp->ace_len = acl_entry->ace_len;
1909 /* Don't really need this since all types are going *
1910 * to be specified but, it's better than leaving it 0 */
1912 acl_entry_link->entryp->ace_type = acl_entry->ace_type;
1914 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
1916 memcpy(acl_entry_link->entryp->ace_id,idp,sizeof(struct ace_id));
1918 /* The access in the acl entries must be left shifted by *
1919 * three bites, because they will ultimately be compared *
1920 * to S_IRUSR, S_IWUSR, and S_IXUSR. */
1922 switch(acl_entry->ace_type){
1923 case ACC_PERMIT:
1924 case ACC_SPECIFY:
1925 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
1926 acl_entry_link->entryp->ace_access <<= 6;
1927 acl_entry_link_head->count++;
1928 break;
1929 case ACC_DENY:
1930 /* Since there is no way to return a DENY acl entry *
1931 * change to PERMIT and then shift. */
1932 DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
1933 acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
1934 DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
1935 acl_entry_link->entryp->ace_access <<= 6;
1936 acl_entry_link_head->count++;
1937 break;
1938 default:
1939 return(0);
1942 DEBUG(10,("acl_entry = %d\n",acl_entry));
1943 DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
1945 acl_entry = acl_nxt(acl_entry);
1947 } /* end of if enabled */
1949 /* Since owner, group, other acl entries are not *
1950 * part of the acl entries in an acl, they must *
1951 * be dummied up to become part of the list. */
1953 for( i = 1; i < 4; i++) {
1954 DEBUG(10,("i is %d\n",i));
1955 if(acl_entry_link_head->count != 0) {
1956 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
1957 if(acl_entry_link->nextp == NULL) {
1958 SAFE_FREE(file_acl);
1959 errno = ENOMEM;
1960 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
1961 return(NULL);
1964 acl_entry_link->nextp->prevp = acl_entry_link;
1965 acl_entry_link = acl_entry_link->nextp;
1966 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
1967 if(acl_entry_link->entryp == NULL) {
1968 SAFE_FREE(file_acl);
1969 errno = ENOMEM;
1970 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
1971 return(NULL);
1975 acl_entry_link->nextp = NULL;
1977 new_acl_entry = acl_entry_link->entryp;
1978 idp = new_acl_entry->ace_id;
1980 new_acl_entry->ace_len = sizeof(struct acl_entry);
1981 new_acl_entry->ace_type = ACC_PERMIT;
1982 idp->id_len = sizeof(struct ace_id);
1983 DEBUG(10,("idp->id_len = %d\n",idp->id_len));
1984 memset(idp->id_data,0,sizeof(uid_t));
1986 switch(i) {
1987 case 2:
1988 new_acl_entry->ace_access = file_acl->g_access << 6;
1989 idp->id_type = SMB_ACL_GROUP_OBJ;
1990 break;
1992 case 3:
1993 new_acl_entry->ace_access = file_acl->o_access << 6;
1994 idp->id_type = SMB_ACL_OTHER;
1995 break;
1997 case 1:
1998 new_acl_entry->ace_access = file_acl->u_access << 6;
1999 idp->id_type = SMB_ACL_USER_OBJ;
2000 break;
2002 default:
2003 return(NULL);
2007 acl_entry_link_head->count++;
2008 DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
2011 acl_entry_link_head->count = 0;
2012 SAFE_FREE(file_acl);
2014 return(acl_entry_link_head);
2017 #if 0
2018 SMB_ACL_T sys_acl_get_fd(int fd)
2020 struct acl *file_acl = (struct acl *)NULL;
2021 struct acl_entry *acl_entry;
2022 struct new_acl_entry *new_acl_entry;
2023 struct ace_id *idp;
2024 struct acl_entry_link *acl_entry_link;
2025 struct acl_entry_link *acl_entry_link_head;
2026 int i;
2027 int rc = 0;
2028 uid_t user_id;
2030 /* Get the acl using fstatacl */
2032 DEBUG(10,("Entering sys_acl_get_fd\n"));
2033 DEBUG(10,("fd is %d\n",fd));
2034 file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2036 if(file_acl == NULL) {
2037 errno=ENOMEM;
2038 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2039 return(NULL);
2042 memset(file_acl,0,BUFSIZ);
2044 rc = fstatacl(fd,0,file_acl,BUFSIZ);
2045 if(rc == -1) {
2046 DEBUG(0,("The fstatacl call returned %d with errno %d\n",rc,errno));
2047 SAFE_FREE(file_acl);
2048 return(NULL);
2051 DEBUG(10,("Got facl and returned it\n"));
2053 /* Point to the first acl entry in the acl */
2055 acl_entry = file_acl->acl_ext;
2056 /* Begin setting up the head of the linked list *
2057 * that will be used for the storing the acl *
2058 * in a way that is useful for the posix_acls.c *
2059 * code. */
2061 acl_entry_link_head = acl_entry_link = sys_acl_init(0);
2062 if(acl_entry_link_head == NULL){
2063 SAFE_FREE(file_acl);
2064 return(NULL);
2067 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2069 if(acl_entry_link->entryp == NULL) {
2070 errno = ENOMEM;
2071 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2072 SAFE_FREE(file_acl);
2073 return(NULL);
2076 DEBUG(10,("acl_entry is %d\n",acl_entry));
2077 DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
2079 /* Check if the extended acl bit is on. *
2080 * If it isn't, do not show the *
2081 * contents of the acl since AIX intends *
2082 * the extended info to remain unused */
2084 if(file_acl->acl_mode & S_IXACL){
2085 /* while we are not pointing to the very end */
2086 while(acl_entry < acl_last(file_acl)) {
2087 /* before we malloc anything, make sure this is */
2088 /* a valid acl entry and one that we want to map */
2090 idp = id_nxt(acl_entry->ace_id);
2091 if((acl_entry->ace_type == ACC_SPECIFY ||
2092 (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
2093 acl_entry = acl_nxt(acl_entry);
2094 continue;
2097 idp = acl_entry->ace_id;
2099 /* Check if this is the first entry in the linked list. *
2100 * The first entry needs to keep prevp pointing to NULL *
2101 * and already has entryp allocated. */
2103 if(acl_entry_link_head->count != 0) {
2104 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2105 if(acl_entry_link->nextp == NULL) {
2106 errno = ENOMEM;
2107 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2108 SAFE_FREE(file_acl);
2109 return(NULL);
2111 acl_entry_link->nextp->prevp = acl_entry_link;
2112 acl_entry_link = acl_entry_link->nextp;
2113 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2114 if(acl_entry_link->entryp == NULL) {
2115 errno = ENOMEM;
2116 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2117 SAFE_FREE(file_acl);
2118 return(NULL);
2121 acl_entry_link->nextp = NULL;
2124 acl_entry_link->entryp->ace_len = acl_entry->ace_len;
2126 /* Don't really need this since all types are going *
2127 * to be specified but, it's better than leaving it 0 */
2129 acl_entry_link->entryp->ace_type = acl_entry->ace_type;
2130 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2132 memcpy(acl_entry_link->entryp->ace_id, idp, sizeof(struct ace_id));
2134 /* The access in the acl entries must be left shifted by *
2135 * three bites, because they will ultimately be compared *
2136 * to S_IRUSR, S_IWUSR, and S_IXUSR. */
2138 switch(acl_entry->ace_type){
2139 case ACC_PERMIT:
2140 case ACC_SPECIFY:
2141 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2142 acl_entry_link->entryp->ace_access <<= 6;
2143 acl_entry_link_head->count++;
2144 break;
2145 case ACC_DENY:
2146 /* Since there is no way to return a DENY acl entry *
2147 * change to PERMIT and then shift. */
2148 DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
2149 acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
2150 DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
2151 acl_entry_link->entryp->ace_access <<= 6;
2152 acl_entry_link_head->count++;
2153 break;
2154 default:
2155 return(0);
2158 DEBUG(10,("acl_entry = %d\n",acl_entry));
2159 DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
2161 acl_entry = acl_nxt(acl_entry);
2163 } /* end of if enabled */
2165 /* Since owner, group, other acl entries are not *
2166 * part of the acl entries in an acl, they must *
2167 * be dummied up to become part of the list. */
2169 for( i = 1; i < 4; i++) {
2170 DEBUG(10,("i is %d\n",i));
2171 if(acl_entry_link_head->count != 0){
2172 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2173 if(acl_entry_link->nextp == NULL) {
2174 errno = ENOMEM;
2175 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2176 SAFE_FREE(file_acl);
2177 return(NULL);
2180 acl_entry_link->nextp->prevp = acl_entry_link;
2181 acl_entry_link = acl_entry_link->nextp;
2182 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2184 if(acl_entry_link->entryp == NULL) {
2185 SAFE_FREE(file_acl);
2186 errno = ENOMEM;
2187 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2188 return(NULL);
2192 acl_entry_link->nextp = NULL;
2194 new_acl_entry = acl_entry_link->entryp;
2195 idp = new_acl_entry->ace_id;
2197 new_acl_entry->ace_len = sizeof(struct acl_entry);
2198 new_acl_entry->ace_type = ACC_PERMIT;
2199 idp->id_len = sizeof(struct ace_id);
2200 DEBUG(10,("idp->id_len = %d\n",idp->id_len));
2201 memset(idp->id_data,0,sizeof(uid_t));
2203 switch(i) {
2204 case 2:
2205 new_acl_entry->ace_access = file_acl->g_access << 6;
2206 idp->id_type = SMB_ACL_GROUP_OBJ;
2207 break;
2209 case 3:
2210 new_acl_entry->ace_access = file_acl->o_access << 6;
2211 idp->id_type = SMB_ACL_OTHER;
2212 break;
2214 case 1:
2215 new_acl_entry->ace_access = file_acl->u_access << 6;
2216 idp->id_type = SMB_ACL_USER_OBJ;
2217 break;
2219 default:
2220 return(NULL);
2223 acl_entry_link_head->count++;
2224 DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
2227 acl_entry_link_head->count = 0;
2228 SAFE_FREE(file_acl);
2230 return(acl_entry_link_head);
2232 #endif
2234 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)
2236 uint *permset;
2238 if (sys_acl_get_tag_type(entry, tag_type_p) != 0)
2239 return -1;
2241 if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP)
2242 memcpy(u_g_id_p, entry->ace_id->id_data, sizeof (id_t));
2244 permset = &entry->ace_access;
2246 DEBUG(10,("*permset is %d\n",*permset));
2247 *bits_p = (*permset & S_IRUSR ? 4 : 0)
2248 | (*permset & S_IWUSR ? 2 : 0)
2249 | (*permset & S_IXUSR ? 1 : 0);
2251 return 0;
2254 SMB_ACL_T sys_acl_init( int count)
2256 struct acl_entry_link *theacl = NULL;
2258 DEBUG(10,("Entering sys_acl_init\n"));
2260 theacl = SMB_MALLOC_P(struct acl_entry_link);
2261 if(theacl == NULL) {
2262 errno = ENOMEM;
2263 DEBUG(0,("Error in sys_acl_init is %d\n",errno));
2264 return(NULL);
2267 theacl->count = 0;
2268 theacl->nextp = NULL;
2269 theacl->prevp = NULL;
2270 theacl->entryp = NULL;
2271 DEBUG(10,("Exiting sys_acl_init\n"));
2272 return(theacl);
2275 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
2277 struct acl_entry_link *theacl;
2278 struct acl_entry_link *acl_entryp;
2279 struct acl_entry_link *temp_entry;
2280 int counting;
2282 DEBUG(10,("Entering the sys_acl_create_entry\n"));
2284 theacl = acl_entryp = *pacl;
2286 /* Get to the end of the acl before adding entry */
2288 for(counting=0; counting < theacl->count; counting++){
2289 DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
2290 temp_entry = acl_entryp;
2291 acl_entryp = acl_entryp->nextp;
2294 if(theacl->count != 0){
2295 temp_entry->nextp = acl_entryp = SMB_MALLOC_P(struct acl_entry_link);
2296 if(acl_entryp == NULL) {
2297 errno = ENOMEM;
2298 DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
2299 return(-1);
2302 DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
2303 acl_entryp->prevp = temp_entry;
2304 DEBUG(10,("The acl_entryp->prevp is %d\n",acl_entryp->prevp));
2307 *pentry = acl_entryp->entryp = SMB_MALLOC_P(struct new_acl_entry);
2308 if(*pentry == NULL) {
2309 errno = ENOMEM;
2310 DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
2311 return(-1);
2314 memset(*pentry,0,sizeof(struct new_acl_entry));
2315 acl_entryp->entryp->ace_len = sizeof(struct acl_entry);
2316 acl_entryp->entryp->ace_type = ACC_PERMIT;
2317 acl_entryp->entryp->ace_id->id_len = sizeof(struct ace_id);
2318 acl_entryp->nextp = NULL;
2319 theacl->count++;
2320 DEBUG(10,("Exiting sys_acl_create_entry\n"));
2321 return(0);
2324 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
2326 entry->ace_id->id_type = tag_type;
2327 DEBUG(10,("The tag type is %d\n",entry->ace_id->id_type));
2329 if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP)
2330 memcpy(entry->ace_id->id_data, &u_g_id, sizeof (id_t));
2332 entry->ace_access = bits;
2333 DEBUG(10,("entry->ace_access = %d\n",entry->ace_access));
2335 return 0;
2338 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits)
2340 DEBUG(10,("Starting AIX sys_acl_set_permset\n"));
2341 entry->ace_access = bits;
2342 DEBUG(10,("entry->ace_access = %d\n",entry->ace_access));
2343 DEBUG(10,("Ending AIX sys_acl_set_permset\n"));
2344 return(0);
2347 int sys_acl_valid( SMB_ACL_T theacl )
2349 int user_obj = 0;
2350 int group_obj = 0;
2351 int other_obj = 0;
2352 struct acl_entry_link *acl_entry;
2354 for(acl_entry=theacl; acl_entry != NULL; acl_entry = acl_entry->nextp) {
2355 user_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_USER_OBJ);
2356 group_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_GROUP_OBJ);
2357 other_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_OTHER);
2360 DEBUG(10,("user_obj=%d, group_obj=%d, other_obj=%d\n",user_obj,group_obj,other_obj));
2362 if(user_obj != 1 || group_obj != 1 || other_obj != 1)
2363 return(-1);
2365 return(0);
2368 int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
2370 struct acl_entry_link *acl_entry_link = NULL;
2371 struct acl *file_acl = NULL;
2372 struct acl *file_acl_temp = NULL;
2373 struct acl_entry *acl_entry = NULL;
2374 struct ace_id *ace_id = NULL;
2375 uint id_type;
2376 uint ace_access;
2377 uint user_id;
2378 uint acl_length;
2379 uint rc;
2381 DEBUG(10,("Entering sys_acl_set_file\n"));
2382 DEBUG(10,("File name is %s\n",name));
2384 /* AIX has no default ACL */
2385 if(acltype == SMB_ACL_TYPE_DEFAULT)
2386 return(0);
2388 acl_length = BUFSIZ;
2389 file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2391 if(file_acl == NULL) {
2392 errno = ENOMEM;
2393 DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
2394 return(-1);
2397 memset(file_acl,0,BUFSIZ);
2399 file_acl->acl_len = ACL_SIZ;
2400 file_acl->acl_mode = S_IXACL;
2402 for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
2403 acl_entry_link->entryp->ace_access >>= 6;
2404 id_type = acl_entry_link->entryp->ace_id->id_type;
2406 switch(id_type) {
2407 case SMB_ACL_USER_OBJ:
2408 file_acl->u_access = acl_entry_link->entryp->ace_access;
2409 continue;
2410 case SMB_ACL_GROUP_OBJ:
2411 file_acl->g_access = acl_entry_link->entryp->ace_access;
2412 continue;
2413 case SMB_ACL_OTHER:
2414 file_acl->o_access = acl_entry_link->entryp->ace_access;
2415 continue;
2416 case SMB_ACL_MASK:
2417 continue;
2420 if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
2421 acl_length += sizeof(struct acl_entry);
2422 file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
2423 if(file_acl_temp == NULL) {
2424 SAFE_FREE(file_acl);
2425 errno = ENOMEM;
2426 DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
2427 return(-1);
2430 memcpy(file_acl_temp,file_acl,file_acl->acl_len);
2431 SAFE_FREE(file_acl);
2432 file_acl = file_acl_temp;
2435 acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
2436 file_acl->acl_len += sizeof(struct acl_entry);
2437 acl_entry->ace_len = acl_entry_link->entryp->ace_len;
2438 acl_entry->ace_access = acl_entry_link->entryp->ace_access;
2440 /* In order to use this, we'll need to wait until we can get denies */
2441 /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
2442 acl_entry->ace_type = ACC_SPECIFY; */
2444 acl_entry->ace_type = ACC_SPECIFY;
2446 ace_id = acl_entry->ace_id;
2448 ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
2449 DEBUG(10,("The id type is %d\n",ace_id->id_type));
2450 ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
2451 memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
2452 memcpy(acl_entry->ace_id->id_data, &user_id, sizeof(uid_t));
2455 rc = chacl((char*)name,file_acl,file_acl->acl_len);
2456 DEBUG(10,("errno is %d\n",errno));
2457 DEBUG(10,("return code is %d\n",rc));
2458 SAFE_FREE(file_acl);
2459 DEBUG(10,("Exiting the sys_acl_set_file\n"));
2460 return(rc);
2463 #if 0
2464 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
2466 struct acl_entry_link *acl_entry_link = NULL;
2467 struct acl *file_acl = NULL;
2468 struct acl *file_acl_temp = NULL;
2469 struct acl_entry *acl_entry = NULL;
2470 struct ace_id *ace_id = NULL;
2471 uint id_type;
2472 uint user_id;
2473 uint acl_length;
2474 uint rc;
2476 DEBUG(10,("Entering sys_acl_set_fd\n"));
2477 acl_length = BUFSIZ;
2478 file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2480 if(file_acl == NULL) {
2481 errno = ENOMEM;
2482 DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
2483 return(-1);
2486 memset(file_acl,0,BUFSIZ);
2488 file_acl->acl_len = ACL_SIZ;
2489 file_acl->acl_mode = S_IXACL;
2491 for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
2492 acl_entry_link->entryp->ace_access >>= 6;
2493 id_type = acl_entry_link->entryp->ace_id->id_type;
2494 DEBUG(10,("The id_type is %d\n",id_type));
2496 switch(id_type) {
2497 case SMB_ACL_USER_OBJ:
2498 file_acl->u_access = acl_entry_link->entryp->ace_access;
2499 continue;
2500 case SMB_ACL_GROUP_OBJ:
2501 file_acl->g_access = acl_entry_link->entryp->ace_access;
2502 continue;
2503 case SMB_ACL_OTHER:
2504 file_acl->o_access = acl_entry_link->entryp->ace_access;
2505 continue;
2506 case SMB_ACL_MASK:
2507 continue;
2510 if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
2511 acl_length += sizeof(struct acl_entry);
2512 file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
2513 if(file_acl_temp == NULL) {
2514 SAFE_FREE(file_acl);
2515 errno = ENOMEM;
2516 DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
2517 return(-1);
2520 memcpy(file_acl_temp,file_acl,file_acl->acl_len);
2521 SAFE_FREE(file_acl);
2522 file_acl = file_acl_temp;
2525 acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
2526 file_acl->acl_len += sizeof(struct acl_entry);
2527 acl_entry->ace_len = acl_entry_link->entryp->ace_len;
2528 acl_entry->ace_access = acl_entry_link->entryp->ace_access;
2530 /* In order to use this, we'll need to wait until we can get denies */
2531 /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
2532 acl_entry->ace_type = ACC_SPECIFY; */
2534 acl_entry->ace_type = ACC_SPECIFY;
2536 ace_id = acl_entry->ace_id;
2538 ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
2539 DEBUG(10,("The id type is %d\n",ace_id->id_type));
2540 ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
2541 memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
2542 memcpy(ace_id->id_data, &user_id, sizeof(uid_t));
2545 rc = fchacl(fd,file_acl,file_acl->acl_len);
2546 DEBUG(10,("errno is %d\n",errno));
2547 DEBUG(10,("return code is %d\n",rc));
2548 SAFE_FREE(file_acl);
2549 DEBUG(10,("Exiting sys_acl_set_fd\n"));
2550 return(rc);
2552 #endif
2554 int sys_acl_delete_def_file(const char *name)
2556 /* AIX has no default ACL */
2557 return 0;
2560 int sys_acl_free_acl(SMB_ACL_T posix_acl)
2562 struct acl_entry_link *acl_entry_link;
2564 for(acl_entry_link = posix_acl->nextp; acl_entry_link->nextp != NULL; acl_entry_link = acl_entry_link->nextp) {
2565 SAFE_FREE(acl_entry_link->prevp->entryp);
2566 SAFE_FREE(acl_entry_link->prevp);
2569 SAFE_FREE(acl_entry_link->prevp->entryp);
2570 SAFE_FREE(acl_entry_link->prevp);
2571 SAFE_FREE(acl_entry_link->entryp);
2572 SAFE_FREE(acl_entry_link);
2574 return(0);
2577 #elif defined(HAVE_OSX_ACLS) /*----------------------------------------------*/
2579 #define OSX_BROKEN_GETENTRY /* returns 0 instead of 1 */
2581 #include <membership.h>
2583 int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
2585 int ret = acl_get_entry(the_acl, entry_id, entry_p);
2586 #ifdef OSX_BROKEN_GETENTRY
2587 if (ret == 0)
2588 ret = 1;
2589 else if (ret == -1 && errno == 22)
2590 ret = 0;
2591 #endif
2592 return ret;
2595 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
2597 if (type == ACL_TYPE_DEFAULT) {
2598 errno = ENOTSUP;
2599 return NULL;
2601 errno = 0;
2602 return acl_get_file(path_p, type);
2605 #if 0
2606 SMB_ACL_T sys_acl_get_fd(int fd)
2608 return acl_get_fd(fd);
2610 #endif
2612 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)
2614 uuid_t *uup;
2615 acl_tag_t tag;
2616 acl_flagset_t flagset;
2617 acl_permset_t permset;
2618 uint32 bits, fb, bb, pb;
2619 int id_type = -1;
2620 int rc;
2622 if (acl_get_tag_type(entry, &tag) != 0
2623 || acl_get_flagset_np(entry, &flagset) != 0
2624 || acl_get_permset(entry, &permset) != 0
2625 || (uup = acl_get_qualifier(entry)) == NULL)
2626 return -1;
2628 rc = mbr_uuid_to_id(*uup, u_g_id_p, &id_type);
2629 acl_free(uup);
2630 if (rc != 0)
2631 return rc;
2633 if (id_type == ID_TYPE_UID)
2634 *tag_type_p = SMB_ACL_USER;
2635 else
2636 *tag_type_p = SMB_ACL_GROUP;
2638 bits = tag == ACL_EXTENDED_ALLOW ? 1 : 0;
2640 for (fb = (1u<<4), bb = (1u<<1); bb < (1u<<12); fb *= 2, bb *= 2) {
2641 if (acl_get_flag_np(flagset, fb) == 1)
2642 bits |= bb;
2645 for (pb = (1u<<1), bb = (1u<<12); bb < (1u<<25); pb *= 2, bb *= 2) {
2646 if (acl_get_perm_np(permset, pb) == 1)
2647 bits |= bb;
2650 *bits_p = bits;
2652 return 0;
2655 SMB_ACL_T sys_acl_init(int count)
2657 return acl_init(count);
2660 int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
2662 return acl_create_entry(pacl, pentry);
2665 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
2667 acl_flagset_t flagset;
2668 acl_permset_t permset;
2669 uint32 fb, bb, pb;
2670 int is_user = tag_type == SMB_ACL_USER;
2671 uuid_t uu;
2672 int rc;
2674 tag_type = bits & 1 ? ACL_EXTENDED_ALLOW : ACL_EXTENDED_DENY;
2676 if (acl_get_flagset_np(entry, &flagset) != 0
2677 || acl_get_permset(entry, &permset) != 0)
2678 return -1;
2680 acl_clear_flags_np(flagset);
2681 acl_clear_perms(permset);
2683 for (fb = (1u<<4), bb = (1u<<1); bb < (1u<<12); fb *= 2, bb *= 2) {
2684 if (bits & bb)
2685 acl_add_flag_np(flagset, fb);
2688 for (pb = (1u<<1), bb = (1u<<12); bb < (1u<<25); pb *= 2, bb *= 2) {
2689 if (bits & bb)
2690 acl_add_perm(permset, pb);
2693 if (is_user)
2694 rc = mbr_uid_to_uuid(u_g_id, uu);
2695 else
2696 rc = mbr_gid_to_uuid(u_g_id, uu);
2698 if (acl_set_tag_type(entry, tag_type) != 0
2699 || acl_set_qualifier(entry, &uu) != 0
2700 || acl_set_permset(entry, permset) != 0
2701 || acl_set_flagset_np(entry, flagset) != 0)
2702 return -1;
2704 return 0;
2707 #if 0
2708 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits)
2710 return -1; /* Not needed for OS X. */
2712 #endif
2714 int sys_acl_valid(SMB_ACL_T theacl)
2716 return acl_valid(theacl);
2719 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
2721 return acl_set_file(name, acltype, theacl);
2724 #if 0
2725 int sys_acl_set_fd(int fd, SMB_ACL_T theacl)
2727 return acl_set_fd(fd, theacl);
2729 #endif
2731 int sys_acl_delete_def_file(const char *name)
2733 return acl_delete_def_file(name);
2736 int sys_acl_free_acl(SMB_ACL_T the_acl)
2738 return acl_free(the_acl);
2741 #else /* No ACLs. */
2743 #error No ACL functions defined for this platform!
2745 #endif
2747 /************************************************************************
2748 Deliberately outside the ACL defines. Return 1 if this is a "no acls"
2749 errno, 0 if not.
2750 ************************************************************************/
2752 int no_acl_syscall_error(int err)
2754 #ifdef HAVE_OSX_ACLS
2755 if (err == ENOENT)
2756 return 1; /* Weird problem with directory ACLs. */
2757 #endif
2758 #if defined(ENOSYS)
2759 if (err == ENOSYS) {
2760 return 1;
2762 #endif
2763 #if defined(ENOTSUP)
2764 if (err == ENOTSUP) {
2765 return 1;
2767 #endif
2768 return 0;
2771 #endif /* SUPPORT_ACLS */