Set NO_SYMLINK_USER_XATTRS on linux. Fixes bug 7109.
[rsync/qnx.git] / lib / sysacls.c
blob52314bc1ee05eed0881ac30f344449174d212bec
1 /*
2 * Unix SMB/CIFS implementation.
3 * Based on the Samba ACL support code.
4 * Copyright (C) Jeremy Allison 2000.
5 * Copyright (C) 2007-2008 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 preceed 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 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
878 SMB_ACL_T acl_d;
879 int count; /* # of ACL entries allocated */
880 int naccess; /* # of access ACL entries */
881 int ndefault; /* # of default ACL entries */
883 if(hpux_acl_call_presence() == False) {
884 /* Looks like we don't have the acl() system call on HPUX.
885 * May be the system doesn't have the latest version of JFS.
887 return NULL;
890 if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
891 errno = EINVAL;
892 return NULL;
895 count = INITIAL_ACL_SIZE;
896 if ((acl_d = sys_acl_init(count)) == NULL) {
897 return NULL;
901 * If there isn't enough space for the ACL entries we use
902 * ACL_CNT to determine the actual number of ACL entries
903 * reallocate and try again. This is in a loop because it
904 * is possible that someone else could modify the ACL and
905 * increase the number of entries between the call to
906 * ACL_CNT and the call to ACL_GET.
908 while ((count = acl(path_p, ACL_GET, count, &acl_d->acl[0])) < 0 && errno == ENOSPC) {
910 sys_acl_free_acl(acl_d);
912 if ((count = acl(path_p, ACL_CNT, 0, NULL)) < 0) {
913 return NULL;
916 if ((acl_d = sys_acl_init(count)) == NULL) {
917 return NULL;
921 if (count < 0) {
922 sys_acl_free_acl(acl_d);
923 return NULL;
927 * calculate the number of access and default ACL entries
929 * Note: we assume that the acl() system call returned a
930 * well formed ACL which is sorted so that all of the
931 * access ACL entries preceed any default ACL entries
933 for (naccess = 0; naccess < count; naccess++) {
934 if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
935 break;
937 ndefault = count - naccess;
940 * if the caller wants the default ACL we have to copy
941 * the entries down to the start of the acl[] buffer
942 * and mask out the ACL_DEFAULT flag from the type field
944 if (type == SMB_ACL_TYPE_DEFAULT) {
945 int i, j;
947 for (i = 0, j = naccess; i < ndefault; i++, j++) {
948 acl_d->acl[i] = acl_d->acl[j];
949 acl_d->acl[i].a_type &= ~ACL_DEFAULT;
952 acl_d->count = ndefault;
953 } else {
954 acl_d->count = naccess;
957 return acl_d;
960 #if 0
961 SMB_ACL_T sys_acl_get_fd(int fd)
964 * HPUX doesn't have the facl call. Fake it using the path.... JRA.
967 files_struct *fsp = file_find_fd(fd);
969 if (fsp == NULL) {
970 errno = EBADF;
971 return NULL;
975 * We know we're in the same conn context. So we
976 * can use the relative path.
979 return sys_acl_get_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
981 #endif
983 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)
985 *tag_type_p = entry->a_type;
987 *bits_p = entry->a_perm;
989 if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP)
990 *u_g_id_p = entry->a_id;
992 return 0;
995 SMB_ACL_T sys_acl_init(int count)
997 SMB_ACL_T a;
999 if (count < 0) {
1000 errno = EINVAL;
1001 return NULL;
1005 * note that since the definition of the structure pointed
1006 * to by the SMB_ACL_T includes the first element of the
1007 * acl[] array, this actually allocates an ACL with room
1008 * for (count+1) entries
1010 if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof a[0] + count * sizeof(struct acl))) == NULL) {
1011 errno = ENOMEM;
1012 return NULL;
1015 a->size = count + 1;
1016 a->count = 0;
1017 a->next = -1;
1019 return a;
1023 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
1025 SMB_ACL_T acl_d;
1026 SMB_ACL_ENTRY_T entry_d;
1028 if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
1029 errno = EINVAL;
1030 return -1;
1033 if (acl_d->count >= acl_d->size) {
1034 errno = ENOSPC;
1035 return -1;
1038 entry_d = &acl_d->acl[acl_d->count++];
1039 entry_d->a_type = 0;
1040 entry_d->a_id = -1;
1041 entry_d->a_perm = 0;
1042 *entry_p = entry_d;
1044 return 0;
1047 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
1049 entry->a_type = tag_type;
1051 if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP)
1052 entry->a_id = u_g_id;
1054 entry->a_perm = bits;
1056 return 0;
1059 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry_d, uint32 bits)
1061 entry_d->a_perm = bits;
1063 return 0;
1066 /* Structure to capture the count for each type of ACE. */
1068 struct hpux_acl_types {
1069 int n_user;
1070 int n_def_user;
1071 int n_user_obj;
1072 int n_def_user_obj;
1074 int n_group;
1075 int n_def_group;
1076 int n_group_obj;
1077 int n_def_group_obj;
1079 int n_other;
1080 int n_other_obj;
1081 int n_def_other_obj;
1083 int n_class_obj;
1084 int n_def_class_obj;
1086 int n_illegal_obj;
1089 /* count_obj:
1090 * Counts the different number of objects in a given array of ACL
1091 * structures.
1092 * Inputs:
1094 * acl_count - Count of ACLs in the array of ACL strucutres.
1095 * aclp - Array of ACL structures.
1096 * acl_type_count - Pointer to acl_types structure. Should already be
1097 * allocated.
1098 * Output:
1100 * acl_type_count - This structure is filled up with counts of various
1101 * acl types.
1104 static void hpux_count_obj(int acl_count, struct acl *aclp, struct hpux_acl_types *acl_type_count)
1106 int i;
1108 memset(acl_type_count, 0, sizeof(struct hpux_acl_types));
1110 for(i=0;i<acl_count;i++) {
1111 switch(aclp[i].a_type) {
1112 case USER:
1113 acl_type_count->n_user++;
1114 break;
1115 case USER_OBJ:
1116 acl_type_count->n_user_obj++;
1117 break;
1118 case DEF_USER_OBJ:
1119 acl_type_count->n_def_user_obj++;
1120 break;
1121 case GROUP:
1122 acl_type_count->n_group++;
1123 break;
1124 case GROUP_OBJ:
1125 acl_type_count->n_group_obj++;
1126 break;
1127 case DEF_GROUP_OBJ:
1128 acl_type_count->n_def_group_obj++;
1129 break;
1130 case OTHER_OBJ:
1131 acl_type_count->n_other_obj++;
1132 break;
1133 case DEF_OTHER_OBJ:
1134 acl_type_count->n_def_other_obj++;
1135 break;
1136 case CLASS_OBJ:
1137 acl_type_count->n_class_obj++;
1138 break;
1139 case DEF_CLASS_OBJ:
1140 acl_type_count->n_def_class_obj++;
1141 break;
1142 case DEF_USER:
1143 acl_type_count->n_def_user++;
1144 break;
1145 case DEF_GROUP:
1146 acl_type_count->n_def_group++;
1147 break;
1148 default:
1149 acl_type_count->n_illegal_obj++;
1150 break;
1155 /* swap_acl_entries: Swaps two ACL entries.
1157 * Inputs: aclp0, aclp1 - ACL entries to be swapped.
1160 static void hpux_swap_acl_entries(struct acl *aclp0, struct acl *aclp1)
1162 struct acl temp_acl;
1164 temp_acl.a_type = aclp0->a_type;
1165 temp_acl.a_id = aclp0->a_id;
1166 temp_acl.a_perm = aclp0->a_perm;
1168 aclp0->a_type = aclp1->a_type;
1169 aclp0->a_id = aclp1->a_id;
1170 aclp0->a_perm = aclp1->a_perm;
1172 aclp1->a_type = temp_acl.a_type;
1173 aclp1->a_id = temp_acl.a_id;
1174 aclp1->a_perm = temp_acl.a_perm;
1177 /* prohibited_duplicate_type
1178 * Identifies if given ACL type can have duplicate entries or
1179 * not.
1181 * Inputs: acl_type - ACL Type.
1183 * Outputs:
1185 * Return..
1187 * True - If the ACL type matches any of the prohibited types.
1188 * False - If the ACL type doesn't match any of the prohibited types.
1191 static BOOL hpux_prohibited_duplicate_type(int acl_type)
1193 switch(acl_type) {
1194 case USER:
1195 case GROUP:
1196 case DEF_USER:
1197 case DEF_GROUP:
1198 return True;
1199 default:
1200 return False;
1204 /* get_needed_class_perm
1205 * Returns the permissions of a ACL structure only if the ACL
1206 * type matches one of the pre-determined types for computing
1207 * CLASS_OBJ permissions.
1209 * Inputs: aclp - Pointer to ACL structure.
1212 static int hpux_get_needed_class_perm(struct acl *aclp)
1214 switch(aclp->a_type) {
1215 case USER:
1216 case GROUP_OBJ:
1217 case GROUP:
1218 case DEF_USER_OBJ:
1219 case DEF_USER:
1220 case DEF_GROUP_OBJ:
1221 case DEF_GROUP:
1222 case DEF_CLASS_OBJ:
1223 case DEF_OTHER_OBJ:
1224 return aclp->a_perm;
1225 default:
1226 return 0;
1230 /* acl_sort for HPUX.
1231 * Sorts the array of ACL structures as per the description in
1232 * aclsort man page. Refer to aclsort man page for more details
1234 * Inputs:
1236 * acl_count - Count of ACLs in the array of ACL structures.
1237 * calclass - If this is not zero, then we compute the CLASS_OBJ
1238 * permissions.
1239 * aclp - Array of ACL structures.
1241 * Outputs:
1243 * aclp - Sorted array of ACL structures.
1245 * Outputs:
1247 * Returns 0 for success -1 for failure. Prints a message to the Samba
1248 * debug log in case of failure.
1251 static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp)
1253 #if !defined(HAVE_HPUX_ACLSORT)
1255 * The aclsort() system call is availabe on the latest HPUX General
1256 * Patch Bundles. So for HPUX, we developed our version of acl_sort
1257 * function. Because, we don't want to update to a new
1258 * HPUX GR bundle just for aclsort() call.
1261 struct hpux_acl_types acl_obj_count;
1262 int n_class_obj_perm = 0;
1263 int i, j;
1265 if(!acl_count) {
1266 DEBUG(10,("Zero acl count passed. Returning Success\n"));
1267 return 0;
1270 if(aclp == NULL) {
1271 DEBUG(0,("Null ACL pointer in hpux_acl_sort. Returning Failure. \n"));
1272 return -1;
1275 /* Count different types of ACLs in the ACLs array */
1277 hpux_count_obj(acl_count, aclp, &acl_obj_count);
1279 /* There should be only one entry each of type USER_OBJ, GROUP_OBJ,
1280 * CLASS_OBJ and OTHER_OBJ
1283 if( (acl_obj_count.n_user_obj != 1) ||
1284 (acl_obj_count.n_group_obj != 1) ||
1285 (acl_obj_count.n_class_obj != 1) ||
1286 (acl_obj_count.n_other_obj != 1)
1288 DEBUG(0,("hpux_acl_sort: More than one entry or no entries for \
1289 USER OBJ or GROUP_OBJ or OTHER_OBJ or CLASS_OBJ\n"));
1290 return -1;
1293 /* If any of the default objects are present, there should be only
1294 * one of them each.
1297 if( (acl_obj_count.n_def_user_obj > 1) || (acl_obj_count.n_def_group_obj > 1) ||
1298 (acl_obj_count.n_def_other_obj > 1) || (acl_obj_count.n_def_class_obj > 1) ) {
1299 DEBUG(0,("hpux_acl_sort: More than one entry for DEF_CLASS_OBJ \
1300 or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n"));
1301 return -1;
1304 /* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl
1305 * structures.
1307 * Sorting crieteria - First sort by ACL type. If there are multiple entries of
1308 * same ACL type, sort by ACL id.
1310 * I am using the trival kind of sorting method here because, performance isn't
1311 * really effected by the ACLs feature. More over there aren't going to be more
1312 * than 17 entries on HPUX.
1315 for(i=0; i<acl_count;i++) {
1316 for (j=i+1; j<acl_count; j++) {
1317 if( aclp[i].a_type > aclp[j].a_type ) {
1318 /* ACL entries out of order, swap them */
1320 hpux_swap_acl_entries((aclp+i), (aclp+j));
1322 } else if ( aclp[i].a_type == aclp[j].a_type ) {
1324 /* ACL entries of same type, sort by id */
1326 if(aclp[i].a_id > aclp[j].a_id) {
1327 hpux_swap_acl_entries((aclp+i), (aclp+j));
1328 } else if (aclp[i].a_id == aclp[j].a_id) {
1329 /* We have a duplicate entry. */
1330 if(hpux_prohibited_duplicate_type(aclp[i].a_type)) {
1331 DEBUG(0, ("hpux_acl_sort: Duplicate entry: Type(hex): %x Id: %d\n",
1332 aclp[i].a_type, aclp[i].a_id));
1333 return -1;
1341 /* set the class obj permissions to the computed one. */
1342 if(calclass) {
1343 int n_class_obj_index = -1;
1345 for(i=0;i<acl_count;i++) {
1346 n_class_obj_perm |= hpux_get_needed_class_perm((aclp+i));
1348 if(aclp[i].a_type == CLASS_OBJ)
1349 n_class_obj_index = i;
1351 aclp[n_class_obj_index].a_perm = n_class_obj_perm;
1354 return 0;
1355 #else
1356 return aclsort(acl_count, calclass, aclp);
1357 #endif
1361 * sort the ACL and check it for validity
1363 * if it's a minimal ACL with only 4 entries then we
1364 * need to recalculate the mask permissions to make
1365 * sure that they are the same as the GROUP_OBJ
1366 * permissions as required by the UnixWare acl() system call.
1368 * (note: since POSIX allows minimal ACLs which only contain
1369 * 3 entries - ie there is no mask entry - we should, in theory,
1370 * check for this and add a mask entry if necessary - however
1371 * we "know" that the caller of this interface always specifies
1372 * a mask so, in practice "this never happens" (tm) - if it *does*
1373 * happen aclsort() will fail and return an error and someone will
1374 * have to fix it ...)
1377 static int acl_sort(SMB_ACL_T acl_d)
1379 int fixmask = (acl_d->count <= 4);
1381 if (hpux_acl_sort(acl_d->count, fixmask, acl_d->acl) != 0) {
1382 errno = EINVAL;
1383 return -1;
1385 return 0;
1388 int sys_acl_valid(SMB_ACL_T acl_d)
1390 return acl_sort(acl_d);
1393 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
1395 struct stat s;
1396 struct acl *acl_p;
1397 int acl_count;
1398 struct acl *acl_buf = NULL;
1399 int ret;
1401 if(hpux_acl_call_presence() == False) {
1402 /* Looks like we don't have the acl() system call on HPUX.
1403 * May be the system doesn't have the latest version of JFS.
1405 errno=ENOSYS;
1406 return -1;
1409 if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
1410 errno = EINVAL;
1411 return -1;
1414 if (acl_sort(acl_d) != 0) {
1415 return -1;
1418 acl_p = &acl_d->acl[0];
1419 acl_count = acl_d->count;
1422 * if it's a directory there is extra work to do
1423 * since the acl() system call will replace both
1424 * the access ACLs and the default ACLs (if any)
1426 if (stat(name, &s) != 0) {
1427 return -1;
1429 if (S_ISDIR(s.st_mode)) {
1430 SMB_ACL_T acc_acl;
1431 SMB_ACL_T def_acl;
1432 SMB_ACL_T tmp_acl;
1433 int i;
1435 if (type == SMB_ACL_TYPE_ACCESS) {
1436 acc_acl = acl_d;
1437 def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
1439 } else {
1440 def_acl = acl_d;
1441 acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
1444 if (tmp_acl == NULL) {
1445 return -1;
1449 * allocate a temporary buffer for the complete ACL
1451 acl_count = acc_acl->count + def_acl->count;
1452 acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count);
1454 if (acl_buf == NULL) {
1455 sys_acl_free_acl(tmp_acl);
1456 errno = ENOMEM;
1457 return -1;
1461 * copy the access control and default entries into the buffer
1463 memcpy(&acl_buf[0], &acc_acl->acl[0],
1464 acc_acl->count * sizeof(acl_buf[0]));
1466 memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
1467 def_acl->count * sizeof(acl_buf[0]));
1470 * set the ACL_DEFAULT flag on the default entries
1472 for (i = acc_acl->count; i < acl_count; i++) {
1473 acl_buf[i].a_type |= ACL_DEFAULT;
1476 sys_acl_free_acl(tmp_acl);
1478 } else if (type != SMB_ACL_TYPE_ACCESS) {
1479 errno = EINVAL;
1480 return -1;
1483 ret = acl(name, ACL_SET, acl_count, acl_p);
1485 if (acl_buf) {
1486 free(acl_buf);
1489 return ret;
1492 #if 0
1493 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
1496 * HPUX doesn't have the facl call. Fake it using the path.... JRA.
1499 files_struct *fsp = file_find_fd(fd);
1501 if (fsp == NULL) {
1502 errno = EBADF;
1503 return NULL;
1506 if (acl_sort(acl_d) != 0) {
1507 return -1;
1511 * We know we're in the same conn context. So we
1512 * can use the relative path.
1515 return sys_acl_set_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS, acl_d);
1517 #endif
1519 int sys_acl_delete_def_file(const char *path)
1521 SMB_ACL_T acl_d;
1522 int ret;
1525 * fetching the access ACL and rewriting it has
1526 * the effect of deleting the default ACL
1528 if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
1529 return -1;
1532 ret = acl(path, ACL_SET, acl_d->count, acl_d->acl);
1534 sys_acl_free_acl(acl_d);
1536 return ret;
1539 int sys_acl_free_acl(SMB_ACL_T acl_d)
1541 free(acl_d);
1542 return 0;
1545 #elif defined(HAVE_IRIX_ACLS) /*---------------------------------------------*/
1547 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
1549 if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
1550 errno = EINVAL;
1551 return -1;
1554 if (entry_p == NULL) {
1555 errno = EINVAL;
1556 return -1;
1559 if (entry_id == SMB_ACL_FIRST_ENTRY) {
1560 acl_d->next = 0;
1563 if (acl_d->next < 0) {
1564 errno = EINVAL;
1565 return -1;
1568 if (acl_d->next >= acl_d->aclp->acl_cnt) {
1569 return 0;
1572 *entry_p = &acl_d->aclp->acl_entry[acl_d->next++];
1574 return 1;
1577 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
1579 *type_p = entry_d->ae_tag;
1581 return 0;
1584 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
1586 SMB_ACL_T a;
1588 if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) {
1589 errno = ENOMEM;
1590 return NULL;
1592 if ((a->aclp = acl_get_file(path_p, type)) == NULL) {
1593 SAFE_FREE(a);
1594 return NULL;
1596 a->next = -1;
1597 a->freeaclp = True;
1598 return a;
1601 #if 0
1602 SMB_ACL_T sys_acl_get_fd(int fd)
1604 SMB_ACL_T a;
1606 if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) {
1607 errno = ENOMEM;
1608 return NULL;
1610 if ((a->aclp = acl_get_fd(fd)) == NULL) {
1611 SAFE_FREE(a);
1612 return NULL;
1614 a->next = -1;
1615 a->freeaclp = True;
1616 return a;
1618 #endif
1620 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)
1622 *tag_type_p = entry->ae_tag;
1624 *bits_p = entry->ae_perm;
1626 if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP)
1627 *u_g_id_p = entry->ae_id;
1629 return 0;
1632 SMB_ACL_T sys_acl_init(int count)
1634 SMB_ACL_T a;
1636 if (count < 0) {
1637 errno = EINVAL;
1638 return NULL;
1641 if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof a[0] + sizeof (struct acl))) == NULL) {
1642 errno = ENOMEM;
1643 return NULL;
1646 a->next = -1;
1647 a->freeaclp = False;
1648 a->aclp = (struct acl *)((char *)a + sizeof a[0]);
1649 a->aclp->acl_cnt = 0;
1651 return a;
1655 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
1657 SMB_ACL_T acl_d;
1658 SMB_ACL_ENTRY_T entry_d;
1660 if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
1661 errno = EINVAL;
1662 return -1;
1665 if (acl_d->aclp->acl_cnt >= ACL_MAX_ENTRIES) {
1666 errno = ENOSPC;
1667 return -1;
1670 entry_d = &acl_d->aclp->acl_entry[acl_d->aclp->acl_cnt++];
1671 entry_d->ae_tag = 0;
1672 entry_d->ae_id = 0;
1673 entry_d->ae_perm = 0;
1674 *entry_p = entry_d;
1676 return 0;
1679 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
1681 entry->ae_tag = tag_type;
1683 if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP)
1684 entry->ae_id = u_g_id;
1686 entry->ae_perm = bits;
1688 return 0;
1691 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry_d, uint32 bits)
1693 entry_d->ae_perm = bits;
1695 return 0;
1698 int sys_acl_valid(SMB_ACL_T acl_d)
1700 return acl_valid(acl_d->aclp);
1703 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
1705 return acl_set_file(name, type, acl_d->aclp);
1708 #if 0
1709 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
1711 return acl_set_fd(fd, acl_d->aclp);
1713 #endif
1715 int sys_acl_delete_def_file(const char *name)
1717 return acl_delete_def_file(name);
1720 int sys_acl_free_acl(SMB_ACL_T acl_d)
1722 if (acl_d->freeaclp) {
1723 acl_free(acl_d->aclp);
1725 acl_free(acl_d);
1726 return 0;
1729 #elif defined(HAVE_AIX_ACLS) /*----------------------------------------------*/
1731 /* Donated by Medha Date, mdate@austin.ibm.com, for IBM */
1733 int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
1735 struct acl_entry_link *link;
1736 struct new_acl_entry *entry;
1737 int keep_going;
1739 if (entry_id == SMB_ACL_FIRST_ENTRY)
1740 theacl->count = 0;
1741 else if (entry_id != SMB_ACL_NEXT_ENTRY) {
1742 errno = EINVAL;
1743 return -1;
1746 DEBUG(10,("This is the count: %d\n",theacl->count));
1748 /* Check if count was previously set to -1. *
1749 * If it was, that means we reached the end *
1750 * of the acl last time. */
1751 if(theacl->count == -1)
1752 return(0);
1754 link = theacl;
1755 /* To get to the next acl, traverse linked list until index *
1756 * of acl matches the count we are keeping. This count is *
1757 * incremented each time we return an acl entry. */
1759 for(keep_going = 0; keep_going < theacl->count; keep_going++)
1760 link = link->nextp;
1762 entry = *entry_p = link->entryp;
1764 DEBUG(10,("*entry_p is %d\n",entry_p));
1765 DEBUG(10,("*entry_p->ace_access is %d\n",entry->ace_access));
1767 /* Increment count */
1768 theacl->count++;
1769 if(link->nextp == NULL)
1770 theacl->count = -1;
1772 return(1);
1775 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
1777 /* Initialize tag type */
1779 *tag_type_p = -1;
1780 DEBUG(10,("the tagtype is %d\n",entry_d->ace_id->id_type));
1782 /* Depending on what type of entry we have, *
1783 * return tag type. */
1784 switch(entry_d->ace_id->id_type) {
1785 case ACEID_USER:
1786 *tag_type_p = SMB_ACL_USER;
1787 break;
1788 case ACEID_GROUP:
1789 *tag_type_p = SMB_ACL_GROUP;
1790 break;
1792 case SMB_ACL_USER_OBJ:
1793 case SMB_ACL_GROUP_OBJ:
1794 case SMB_ACL_OTHER:
1795 *tag_type_p = entry_d->ace_id->id_type;
1796 break;
1798 default:
1799 return(-1);
1802 return(0);
1805 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
1807 struct acl *file_acl = (struct acl *)NULL;
1808 struct acl_entry *acl_entry;
1809 struct new_acl_entry *new_acl_entry;
1810 struct ace_id *idp;
1811 struct acl_entry_link *acl_entry_link;
1812 struct acl_entry_link *acl_entry_link_head;
1813 int i;
1814 int rc = 0;
1816 /* AIX has no DEFAULT */
1817 if ( type == SMB_ACL_TYPE_DEFAULT ) {
1818 #ifdef ENOTSUP
1819 errno = ENOTSUP;
1820 #else
1821 errno = ENOSYS;
1822 #endif
1823 return NULL;
1826 /* Get the acl using statacl */
1828 DEBUG(10,("Entering sys_acl_get_file\n"));
1829 DEBUG(10,("path_p is %s\n",path_p));
1831 file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
1833 if(file_acl == NULL) {
1834 errno=ENOMEM;
1835 DEBUG(0,("Error in AIX sys_acl_get_file: %d\n",errno));
1836 return(NULL);
1839 memset(file_acl,0,BUFSIZ);
1841 rc = statacl((char *)path_p,0,file_acl,BUFSIZ);
1842 if(rc == -1) {
1843 DEBUG(0,("statacl returned %d with errno %d\n",rc,errno));
1844 SAFE_FREE(file_acl);
1845 return(NULL);
1848 DEBUG(10,("Got facl and returned it\n"));
1850 /* Point to the first acl entry in the acl */
1851 acl_entry = file_acl->acl_ext;
1853 /* Begin setting up the head of the linked list *
1854 * that will be used for the storing the acl *
1855 * in a way that is useful for the posix_acls.c *
1856 * code. */
1858 acl_entry_link_head = acl_entry_link = sys_acl_init(0);
1859 if(acl_entry_link_head == NULL)
1860 return(NULL);
1862 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
1863 if(acl_entry_link->entryp == NULL) {
1864 SAFE_FREE(file_acl);
1865 errno = ENOMEM;
1866 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
1867 return(NULL);
1870 DEBUG(10,("acl_entry is %d\n",acl_entry));
1871 DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
1873 /* Check if the extended acl bit is on. *
1874 * If it isn't, do not show the *
1875 * contents of the acl since AIX intends *
1876 * the extended info to remain unused */
1878 if(file_acl->acl_mode & S_IXACL){
1879 /* while we are not pointing to the very end */
1880 while(acl_entry < acl_last(file_acl)) {
1881 /* before we malloc anything, make sure this is */
1882 /* a valid acl entry and one that we want to map */
1883 idp = id_nxt(acl_entry->ace_id);
1884 if((acl_entry->ace_type == ACC_SPECIFY ||
1885 (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
1886 acl_entry = acl_nxt(acl_entry);
1887 continue;
1890 idp = acl_entry->ace_id;
1892 /* Check if this is the first entry in the linked list. *
1893 * The first entry needs to keep prevp pointing to NULL *
1894 * and already has entryp allocated. */
1896 if(acl_entry_link_head->count != 0) {
1897 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
1899 if(acl_entry_link->nextp == NULL) {
1900 SAFE_FREE(file_acl);
1901 errno = ENOMEM;
1902 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
1903 return(NULL);
1906 acl_entry_link->nextp->prevp = acl_entry_link;
1907 acl_entry_link = acl_entry_link->nextp;
1908 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
1909 if(acl_entry_link->entryp == NULL) {
1910 SAFE_FREE(file_acl);
1911 errno = ENOMEM;
1912 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
1913 return(NULL);
1915 acl_entry_link->nextp = NULL;
1918 acl_entry_link->entryp->ace_len = acl_entry->ace_len;
1920 /* Don't really need this since all types are going *
1921 * to be specified but, it's better than leaving it 0 */
1923 acl_entry_link->entryp->ace_type = acl_entry->ace_type;
1925 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
1927 memcpy(acl_entry_link->entryp->ace_id,idp,sizeof(struct ace_id));
1929 /* The access in the acl entries must be left shifted by *
1930 * three bites, because they will ultimately be compared *
1931 * to S_IRUSR, S_IWUSR, and S_IXUSR. */
1933 switch(acl_entry->ace_type){
1934 case ACC_PERMIT:
1935 case ACC_SPECIFY:
1936 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
1937 acl_entry_link->entryp->ace_access <<= 6;
1938 acl_entry_link_head->count++;
1939 break;
1940 case ACC_DENY:
1941 /* Since there is no way to return a DENY acl entry *
1942 * change to PERMIT and then shift. */
1943 DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
1944 acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
1945 DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
1946 acl_entry_link->entryp->ace_access <<= 6;
1947 acl_entry_link_head->count++;
1948 break;
1949 default:
1950 return(0);
1953 DEBUG(10,("acl_entry = %d\n",acl_entry));
1954 DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
1956 acl_entry = acl_nxt(acl_entry);
1958 } /* end of if enabled */
1960 /* Since owner, group, other acl entries are not *
1961 * part of the acl entries in an acl, they must *
1962 * be dummied up to become part of the list. */
1964 for( i = 1; i < 4; i++) {
1965 DEBUG(10,("i is %d\n",i));
1966 if(acl_entry_link_head->count != 0) {
1967 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
1968 if(acl_entry_link->nextp == NULL) {
1969 SAFE_FREE(file_acl);
1970 errno = ENOMEM;
1971 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
1972 return(NULL);
1975 acl_entry_link->nextp->prevp = acl_entry_link;
1976 acl_entry_link = acl_entry_link->nextp;
1977 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
1978 if(acl_entry_link->entryp == NULL) {
1979 SAFE_FREE(file_acl);
1980 errno = ENOMEM;
1981 DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
1982 return(NULL);
1986 acl_entry_link->nextp = NULL;
1988 new_acl_entry = acl_entry_link->entryp;
1989 idp = new_acl_entry->ace_id;
1991 new_acl_entry->ace_len = sizeof(struct acl_entry);
1992 new_acl_entry->ace_type = ACC_PERMIT;
1993 idp->id_len = sizeof(struct ace_id);
1994 DEBUG(10,("idp->id_len = %d\n",idp->id_len));
1995 memset(idp->id_data,0,sizeof(uid_t));
1997 switch(i) {
1998 case 2:
1999 new_acl_entry->ace_access = file_acl->g_access << 6;
2000 idp->id_type = SMB_ACL_GROUP_OBJ;
2001 break;
2003 case 3:
2004 new_acl_entry->ace_access = file_acl->o_access << 6;
2005 idp->id_type = SMB_ACL_OTHER;
2006 break;
2008 case 1:
2009 new_acl_entry->ace_access = file_acl->u_access << 6;
2010 idp->id_type = SMB_ACL_USER_OBJ;
2011 break;
2013 default:
2014 return(NULL);
2018 acl_entry_link_head->count++;
2019 DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
2022 acl_entry_link_head->count = 0;
2023 SAFE_FREE(file_acl);
2025 return(acl_entry_link_head);
2028 #if 0
2029 SMB_ACL_T sys_acl_get_fd(int fd)
2031 struct acl *file_acl = (struct acl *)NULL;
2032 struct acl_entry *acl_entry;
2033 struct new_acl_entry *new_acl_entry;
2034 struct ace_id *idp;
2035 struct acl_entry_link *acl_entry_link;
2036 struct acl_entry_link *acl_entry_link_head;
2037 int i;
2038 int rc = 0;
2040 /* Get the acl using fstatacl */
2042 DEBUG(10,("Entering sys_acl_get_fd\n"));
2043 DEBUG(10,("fd is %d\n",fd));
2044 file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2046 if(file_acl == NULL) {
2047 errno=ENOMEM;
2048 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2049 return(NULL);
2052 memset(file_acl,0,BUFSIZ);
2054 rc = fstatacl(fd,0,file_acl,BUFSIZ);
2055 if(rc == -1) {
2056 DEBUG(0,("The fstatacl call returned %d with errno %d\n",rc,errno));
2057 SAFE_FREE(file_acl);
2058 return(NULL);
2061 DEBUG(10,("Got facl and returned it\n"));
2063 /* Point to the first acl entry in the acl */
2065 acl_entry = file_acl->acl_ext;
2066 /* Begin setting up the head of the linked list *
2067 * that will be used for the storing the acl *
2068 * in a way that is useful for the posix_acls.c *
2069 * code. */
2071 acl_entry_link_head = acl_entry_link = sys_acl_init(0);
2072 if(acl_entry_link_head == NULL){
2073 SAFE_FREE(file_acl);
2074 return(NULL);
2077 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2079 if(acl_entry_link->entryp == NULL) {
2080 errno = ENOMEM;
2081 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2082 SAFE_FREE(file_acl);
2083 return(NULL);
2086 DEBUG(10,("acl_entry is %d\n",acl_entry));
2087 DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
2089 /* Check if the extended acl bit is on. *
2090 * If it isn't, do not show the *
2091 * contents of the acl since AIX intends *
2092 * the extended info to remain unused */
2094 if(file_acl->acl_mode & S_IXACL){
2095 /* while we are not pointing to the very end */
2096 while(acl_entry < acl_last(file_acl)) {
2097 /* before we malloc anything, make sure this is */
2098 /* a valid acl entry and one that we want to map */
2100 idp = id_nxt(acl_entry->ace_id);
2101 if((acl_entry->ace_type == ACC_SPECIFY ||
2102 (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
2103 acl_entry = acl_nxt(acl_entry);
2104 continue;
2107 idp = acl_entry->ace_id;
2109 /* Check if this is the first entry in the linked list. *
2110 * The first entry needs to keep prevp pointing to NULL *
2111 * and already has entryp allocated. */
2113 if(acl_entry_link_head->count != 0) {
2114 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2115 if(acl_entry_link->nextp == NULL) {
2116 errno = ENOMEM;
2117 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2118 SAFE_FREE(file_acl);
2119 return(NULL);
2121 acl_entry_link->nextp->prevp = acl_entry_link;
2122 acl_entry_link = acl_entry_link->nextp;
2123 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2124 if(acl_entry_link->entryp == NULL) {
2125 errno = ENOMEM;
2126 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2127 SAFE_FREE(file_acl);
2128 return(NULL);
2131 acl_entry_link->nextp = NULL;
2134 acl_entry_link->entryp->ace_len = acl_entry->ace_len;
2136 /* Don't really need this since all types are going *
2137 * to be specified but, it's better than leaving it 0 */
2139 acl_entry_link->entryp->ace_type = acl_entry->ace_type;
2140 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2142 memcpy(acl_entry_link->entryp->ace_id, idp, sizeof(struct ace_id));
2144 /* The access in the acl entries must be left shifted by *
2145 * three bites, because they will ultimately be compared *
2146 * to S_IRUSR, S_IWUSR, and S_IXUSR. */
2148 switch(acl_entry->ace_type){
2149 case ACC_PERMIT:
2150 case ACC_SPECIFY:
2151 acl_entry_link->entryp->ace_access = acl_entry->ace_access;
2152 acl_entry_link->entryp->ace_access <<= 6;
2153 acl_entry_link_head->count++;
2154 break;
2155 case ACC_DENY:
2156 /* Since there is no way to return a DENY acl entry *
2157 * change to PERMIT and then shift. */
2158 DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
2159 acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
2160 DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
2161 acl_entry_link->entryp->ace_access <<= 6;
2162 acl_entry_link_head->count++;
2163 break;
2164 default:
2165 return(0);
2168 DEBUG(10,("acl_entry = %d\n",acl_entry));
2169 DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
2171 acl_entry = acl_nxt(acl_entry);
2173 } /* end of if enabled */
2175 /* Since owner, group, other acl entries are not *
2176 * part of the acl entries in an acl, they must *
2177 * be dummied up to become part of the list. */
2179 for( i = 1; i < 4; i++) {
2180 DEBUG(10,("i is %d\n",i));
2181 if(acl_entry_link_head->count != 0){
2182 acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
2183 if(acl_entry_link->nextp == NULL) {
2184 errno = ENOMEM;
2185 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2186 SAFE_FREE(file_acl);
2187 return(NULL);
2190 acl_entry_link->nextp->prevp = acl_entry_link;
2191 acl_entry_link = acl_entry_link->nextp;
2192 acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
2194 if(acl_entry_link->entryp == NULL) {
2195 SAFE_FREE(file_acl);
2196 errno = ENOMEM;
2197 DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
2198 return(NULL);
2202 acl_entry_link->nextp = NULL;
2204 new_acl_entry = acl_entry_link->entryp;
2205 idp = new_acl_entry->ace_id;
2207 new_acl_entry->ace_len = sizeof(struct acl_entry);
2208 new_acl_entry->ace_type = ACC_PERMIT;
2209 idp->id_len = sizeof(struct ace_id);
2210 DEBUG(10,("idp->id_len = %d\n",idp->id_len));
2211 memset(idp->id_data,0,sizeof(uid_t));
2213 switch(i) {
2214 case 2:
2215 new_acl_entry->ace_access = file_acl->g_access << 6;
2216 idp->id_type = SMB_ACL_GROUP_OBJ;
2217 break;
2219 case 3:
2220 new_acl_entry->ace_access = file_acl->o_access << 6;
2221 idp->id_type = SMB_ACL_OTHER;
2222 break;
2224 case 1:
2225 new_acl_entry->ace_access = file_acl->u_access << 6;
2226 idp->id_type = SMB_ACL_USER_OBJ;
2227 break;
2229 default:
2230 return(NULL);
2233 acl_entry_link_head->count++;
2234 DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
2237 acl_entry_link_head->count = 0;
2238 SAFE_FREE(file_acl);
2240 return(acl_entry_link_head);
2242 #endif
2244 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)
2246 uint *permset;
2248 if (sys_acl_get_tag_type(entry, tag_type_p) != 0)
2249 return -1;
2251 if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP)
2252 memcpy(u_g_id_p, entry->ace_id->id_data, sizeof (id_t));
2254 permset = &entry->ace_access;
2256 DEBUG(10,("*permset is %d\n",*permset));
2257 *bits_p = (*permset & S_IRUSR ? 4 : 0)
2258 | (*permset & S_IWUSR ? 2 : 0)
2259 | (*permset & S_IXUSR ? 1 : 0);
2261 return 0;
2264 SMB_ACL_T sys_acl_init( int count)
2266 struct acl_entry_link *theacl = NULL;
2268 if (count < 0) {
2269 errno = EINVAL;
2270 return NULL;
2273 DEBUG(10,("Entering sys_acl_init\n"));
2275 theacl = SMB_MALLOC_P(struct acl_entry_link);
2276 if(theacl == NULL) {
2277 errno = ENOMEM;
2278 DEBUG(0,("Error in sys_acl_init is %d\n",errno));
2279 return(NULL);
2282 theacl->count = 0;
2283 theacl->nextp = NULL;
2284 theacl->prevp = NULL;
2285 theacl->entryp = NULL;
2286 DEBUG(10,("Exiting sys_acl_init\n"));
2287 return(theacl);
2290 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
2292 struct acl_entry_link *theacl;
2293 struct acl_entry_link *acl_entryp;
2294 struct acl_entry_link *temp_entry;
2295 int counting;
2297 DEBUG(10,("Entering the sys_acl_create_entry\n"));
2299 theacl = acl_entryp = *pacl;
2301 /* Get to the end of the acl before adding entry */
2303 for(counting=0; counting < theacl->count; counting++){
2304 DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
2305 temp_entry = acl_entryp;
2306 acl_entryp = acl_entryp->nextp;
2309 if(theacl->count != 0){
2310 temp_entry->nextp = acl_entryp = SMB_MALLOC_P(struct acl_entry_link);
2311 if(acl_entryp == NULL) {
2312 errno = ENOMEM;
2313 DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
2314 return(-1);
2317 DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
2318 acl_entryp->prevp = temp_entry;
2319 DEBUG(10,("The acl_entryp->prevp is %d\n",acl_entryp->prevp));
2322 *pentry = acl_entryp->entryp = SMB_MALLOC_P(struct new_acl_entry);
2323 if(*pentry == NULL) {
2324 errno = ENOMEM;
2325 DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
2326 return(-1);
2329 memset(*pentry,0,sizeof(struct new_acl_entry));
2330 acl_entryp->entryp->ace_len = sizeof(struct acl_entry);
2331 acl_entryp->entryp->ace_type = ACC_PERMIT;
2332 acl_entryp->entryp->ace_id->id_len = sizeof(struct ace_id);
2333 acl_entryp->nextp = NULL;
2334 theacl->count++;
2335 DEBUG(10,("Exiting sys_acl_create_entry\n"));
2336 return(0);
2339 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
2341 entry->ace_id->id_type = tag_type;
2342 DEBUG(10,("The tag type is %d\n",entry->ace_id->id_type));
2344 if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP)
2345 memcpy(entry->ace_id->id_data, &u_g_id, sizeof (id_t));
2347 entry->ace_access = bits;
2348 DEBUG(10,("entry->ace_access = %d\n",entry->ace_access));
2350 return 0;
2353 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits)
2355 DEBUG(10,("Starting AIX sys_acl_set_permset\n"));
2356 entry->ace_access = bits;
2357 DEBUG(10,("entry->ace_access = %d\n",entry->ace_access));
2358 DEBUG(10,("Ending AIX sys_acl_set_permset\n"));
2359 return(0);
2362 int sys_acl_valid( SMB_ACL_T theacl )
2364 int user_obj = 0;
2365 int group_obj = 0;
2366 int other_obj = 0;
2367 struct acl_entry_link *acl_entry;
2369 for(acl_entry=theacl; acl_entry != NULL; acl_entry = acl_entry->nextp) {
2370 user_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_USER_OBJ);
2371 group_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_GROUP_OBJ);
2372 other_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_OTHER);
2375 DEBUG(10,("user_obj=%d, group_obj=%d, other_obj=%d\n",user_obj,group_obj,other_obj));
2377 if(user_obj != 1 || group_obj != 1 || other_obj != 1)
2378 return(-1);
2380 return(0);
2383 int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
2385 struct acl_entry_link *acl_entry_link = NULL;
2386 struct acl *file_acl = NULL;
2387 struct acl *file_acl_temp = NULL;
2388 struct acl_entry *acl_entry = NULL;
2389 struct ace_id *ace_id = NULL;
2390 uint id_type;
2391 uint user_id;
2392 uint acl_length;
2393 uint rc;
2395 DEBUG(10,("Entering sys_acl_set_file\n"));
2396 DEBUG(10,("File name is %s\n",name));
2398 /* AIX has no default ACL */
2399 if(acltype == SMB_ACL_TYPE_DEFAULT)
2400 return(0);
2402 acl_length = BUFSIZ;
2403 file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2405 if(file_acl == NULL) {
2406 errno = ENOMEM;
2407 DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
2408 return(-1);
2411 memset(file_acl,0,BUFSIZ);
2413 file_acl->acl_len = ACL_SIZ;
2414 file_acl->acl_mode = S_IXACL;
2416 for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
2417 acl_entry_link->entryp->ace_access >>= 6;
2418 id_type = acl_entry_link->entryp->ace_id->id_type;
2420 switch(id_type) {
2421 case SMB_ACL_USER_OBJ:
2422 file_acl->u_access = acl_entry_link->entryp->ace_access;
2423 continue;
2424 case SMB_ACL_GROUP_OBJ:
2425 file_acl->g_access = acl_entry_link->entryp->ace_access;
2426 continue;
2427 case SMB_ACL_OTHER:
2428 file_acl->o_access = acl_entry_link->entryp->ace_access;
2429 continue;
2430 case SMB_ACL_MASK:
2431 continue;
2434 if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
2435 acl_length += sizeof(struct acl_entry);
2436 file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
2437 if(file_acl_temp == NULL) {
2438 SAFE_FREE(file_acl);
2439 errno = ENOMEM;
2440 DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
2441 return(-1);
2444 memcpy(file_acl_temp,file_acl,file_acl->acl_len);
2445 SAFE_FREE(file_acl);
2446 file_acl = file_acl_temp;
2449 acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
2450 file_acl->acl_len += sizeof(struct acl_entry);
2451 acl_entry->ace_len = acl_entry_link->entryp->ace_len;
2452 acl_entry->ace_access = acl_entry_link->entryp->ace_access;
2454 /* In order to use this, we'll need to wait until we can get denies */
2455 /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
2456 acl_entry->ace_type = ACC_SPECIFY; */
2458 acl_entry->ace_type = ACC_SPECIFY;
2460 ace_id = acl_entry->ace_id;
2462 ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
2463 DEBUG(10,("The id type is %d\n",ace_id->id_type));
2464 ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
2465 memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
2466 memcpy(acl_entry->ace_id->id_data, &user_id, sizeof(uid_t));
2469 rc = chacl((char*)name,file_acl,file_acl->acl_len);
2470 DEBUG(10,("errno is %d\n",errno));
2471 DEBUG(10,("return code is %d\n",rc));
2472 SAFE_FREE(file_acl);
2473 DEBUG(10,("Exiting the sys_acl_set_file\n"));
2474 return(rc);
2477 #if 0
2478 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
2480 struct acl_entry_link *acl_entry_link = NULL;
2481 struct acl *file_acl = NULL;
2482 struct acl *file_acl_temp = NULL;
2483 struct acl_entry *acl_entry = NULL;
2484 struct ace_id *ace_id = NULL;
2485 uint id_type;
2486 uint user_id;
2487 uint acl_length;
2488 uint rc;
2490 DEBUG(10,("Entering sys_acl_set_fd\n"));
2491 acl_length = BUFSIZ;
2492 file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
2494 if(file_acl == NULL) {
2495 errno = ENOMEM;
2496 DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
2497 return(-1);
2500 memset(file_acl,0,BUFSIZ);
2502 file_acl->acl_len = ACL_SIZ;
2503 file_acl->acl_mode = S_IXACL;
2505 for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
2506 acl_entry_link->entryp->ace_access >>= 6;
2507 id_type = acl_entry_link->entryp->ace_id->id_type;
2508 DEBUG(10,("The id_type is %d\n",id_type));
2510 switch(id_type) {
2511 case SMB_ACL_USER_OBJ:
2512 file_acl->u_access = acl_entry_link->entryp->ace_access;
2513 continue;
2514 case SMB_ACL_GROUP_OBJ:
2515 file_acl->g_access = acl_entry_link->entryp->ace_access;
2516 continue;
2517 case SMB_ACL_OTHER:
2518 file_acl->o_access = acl_entry_link->entryp->ace_access;
2519 continue;
2520 case SMB_ACL_MASK:
2521 continue;
2524 if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
2525 acl_length += sizeof(struct acl_entry);
2526 file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
2527 if(file_acl_temp == NULL) {
2528 SAFE_FREE(file_acl);
2529 errno = ENOMEM;
2530 DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
2531 return(-1);
2534 memcpy(file_acl_temp,file_acl,file_acl->acl_len);
2535 SAFE_FREE(file_acl);
2536 file_acl = file_acl_temp;
2539 acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
2540 file_acl->acl_len += sizeof(struct acl_entry);
2541 acl_entry->ace_len = acl_entry_link->entryp->ace_len;
2542 acl_entry->ace_access = acl_entry_link->entryp->ace_access;
2544 /* In order to use this, we'll need to wait until we can get denies */
2545 /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
2546 acl_entry->ace_type = ACC_SPECIFY; */
2548 acl_entry->ace_type = ACC_SPECIFY;
2550 ace_id = acl_entry->ace_id;
2552 ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
2553 DEBUG(10,("The id type is %d\n",ace_id->id_type));
2554 ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
2555 memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
2556 memcpy(ace_id->id_data, &user_id, sizeof(uid_t));
2559 rc = fchacl(fd,file_acl,file_acl->acl_len);
2560 DEBUG(10,("errno is %d\n",errno));
2561 DEBUG(10,("return code is %d\n",rc));
2562 SAFE_FREE(file_acl);
2563 DEBUG(10,("Exiting sys_acl_set_fd\n"));
2564 return(rc);
2566 #endif
2568 int sys_acl_delete_def_file(UNUSED(const char *name))
2570 /* AIX has no default ACL */
2571 return 0;
2574 int sys_acl_free_acl(SMB_ACL_T posix_acl)
2576 struct acl_entry_link *acl_entry_link;
2578 for(acl_entry_link = posix_acl->nextp; acl_entry_link->nextp != NULL; acl_entry_link = acl_entry_link->nextp) {
2579 SAFE_FREE(acl_entry_link->prevp->entryp);
2580 SAFE_FREE(acl_entry_link->prevp);
2583 SAFE_FREE(acl_entry_link->prevp->entryp);
2584 SAFE_FREE(acl_entry_link->prevp);
2585 SAFE_FREE(acl_entry_link->entryp);
2586 SAFE_FREE(acl_entry_link);
2588 return(0);
2591 #elif defined(HAVE_OSX_ACLS) /*----------------------------------------------*/
2593 #define OSX_BROKEN_GETENTRY /* returns 0 instead of 1 */
2595 #include <membership.h>
2597 int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
2599 int ret = acl_get_entry(the_acl, entry_id, entry_p);
2600 #ifdef OSX_BROKEN_GETENTRY
2601 if (ret == 0)
2602 ret = 1;
2603 else if (ret == -1 && errno == 22)
2604 ret = 0;
2605 #endif
2606 return ret;
2609 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
2611 if (type == ACL_TYPE_DEFAULT) {
2612 errno = ENOTSUP;
2613 return NULL;
2615 errno = 0;
2616 return acl_get_file(path_p, type);
2619 #if 0
2620 SMB_ACL_T sys_acl_get_fd(int fd)
2622 return acl_get_fd(fd);
2624 #endif
2626 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)
2628 uuid_t *uup;
2629 acl_tag_t tag;
2630 acl_flagset_t flagset;
2631 acl_permset_t permset;
2632 uint32 bits, fb, bb, pb;
2633 int id_type = -1;
2634 int rc;
2636 if (acl_get_tag_type(entry, &tag) != 0
2637 || acl_get_flagset_np(entry, &flagset) != 0
2638 || acl_get_permset(entry, &permset) != 0
2639 || (uup = acl_get_qualifier(entry)) == NULL)
2640 return -1;
2642 rc = mbr_uuid_to_id(*uup, u_g_id_p, &id_type);
2643 acl_free(uup);
2644 if (rc != 0)
2645 return rc;
2647 if (id_type == ID_TYPE_UID)
2648 *tag_type_p = SMB_ACL_USER;
2649 else
2650 *tag_type_p = SMB_ACL_GROUP;
2652 bits = tag == ACL_EXTENDED_ALLOW ? 1 : 0;
2654 for (fb = (1u<<4), bb = (1u<<1); bb < (1u<<12); fb *= 2, bb *= 2) {
2655 if (acl_get_flag_np(flagset, fb) == 1)
2656 bits |= bb;
2659 for (pb = (1u<<1), bb = (1u<<12); bb < (1u<<25); pb *= 2, bb *= 2) {
2660 if (acl_get_perm_np(permset, pb) == 1)
2661 bits |= bb;
2664 *bits_p = bits;
2666 return 0;
2669 SMB_ACL_T sys_acl_init(int count)
2671 return acl_init(count);
2674 int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
2676 return acl_create_entry(pacl, pentry);
2679 int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id)
2681 acl_flagset_t flagset;
2682 acl_permset_t permset;
2683 uint32 fb, bb, pb;
2684 int is_user = tag_type == SMB_ACL_USER;
2685 uuid_t uu;
2686 int rc;
2688 tag_type = bits & 1 ? ACL_EXTENDED_ALLOW : ACL_EXTENDED_DENY;
2690 if (acl_get_flagset_np(entry, &flagset) != 0
2691 || acl_get_permset(entry, &permset) != 0)
2692 return -1;
2694 acl_clear_flags_np(flagset);
2695 acl_clear_perms(permset);
2697 for (fb = (1u<<4), bb = (1u<<1); bb < (1u<<12); fb *= 2, bb *= 2) {
2698 if (bits & bb)
2699 acl_add_flag_np(flagset, fb);
2702 for (pb = (1u<<1), bb = (1u<<12); bb < (1u<<25); pb *= 2, bb *= 2) {
2703 if (bits & bb)
2704 acl_add_perm(permset, pb);
2707 if (is_user)
2708 rc = mbr_uid_to_uuid(u_g_id, uu);
2709 else
2710 rc = mbr_gid_to_uuid(u_g_id, uu);
2711 if (rc != 0)
2712 return rc;
2714 if (acl_set_tag_type(entry, tag_type) != 0
2715 || acl_set_qualifier(entry, &uu) != 0
2716 || acl_set_permset(entry, permset) != 0
2717 || acl_set_flagset_np(entry, flagset) != 0)
2718 return -1;
2720 return 0;
2723 #if 0
2724 int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits)
2726 return -1; /* Not needed for OS X. */
2728 #endif
2730 int sys_acl_valid(SMB_ACL_T theacl)
2732 return acl_valid(theacl);
2735 int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
2737 return acl_set_file(name, acltype, theacl);
2740 #if 0
2741 int sys_acl_set_fd(int fd, SMB_ACL_T theacl)
2743 return acl_set_fd(fd, theacl);
2745 #endif
2747 int sys_acl_delete_def_file(const char *name)
2749 return acl_delete_def_file(name);
2752 int sys_acl_free_acl(SMB_ACL_T the_acl)
2754 return acl_free(the_acl);
2757 #else /* No ACLs. */
2759 #error No ACL functions defined for this platform!
2761 #endif
2763 /************************************************************************
2764 Deliberately outside the ACL defines. Return 1 if this is a "no acls"
2765 errno, 0 if not.
2766 ************************************************************************/
2768 int no_acl_syscall_error(int err)
2770 #ifdef HAVE_OSX_ACLS
2771 if (err == ENOENT)
2772 return 1; /* Weird problem with directory ACLs. */
2773 #endif
2774 #if defined(ENOSYS)
2775 if (err == ENOSYS) {
2776 return 1;
2778 #endif
2779 #if defined(ENOTSUP)
2780 if (err == ENOTSUP) {
2781 return 1;
2783 #endif
2784 if (err == EINVAL) {
2785 /* If the type of SMB_ACL_TYPE_ACCESS or SMB_ACL_TYPE_DEFAULT
2786 * isn't valid, then the ACLs must be non-POSIX. */
2787 return 1;
2789 return 0;
2792 #endif /* SUPPORT_ACLS */