2 Unix SMB/Netbios implementation.
4 Samba system utilities for ACL support.
5 Copyright (C) Jeremy Allison 2000.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 extern int DEBUGLEVEL;
27 This file wraps all differing system ACL interfaces into a consistent
28 one based on the POSIX interface. It also returns the correct errors
29 for older UNIX systems that don't support ACLs.
31 The interfaces that each ACL implementation must support are as follows :
33 int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
34 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
35 int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p
36 void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
37 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
38 SMB_ACL_T sys_acl_get_fd(int fd)
39 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset);
40 int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm);
41 char *sys_acl_to_text( SMB_ACL_T theacl, ssize_t *plen)
42 SMB_ACL_T sys_acl_init( int count)
43 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
44 int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
45 int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
46 int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
47 int sys_acl_valid( SMB_ACL_T theacl )
48 int sys_acl_set_file( char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
49 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
51 This next one is not POSIX complient - but we *have* to have it !
52 More POSIX braindamage.
54 int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
56 The generic POSIX free is the following call. We split this into
57 several different free functions as we may need to add tag info
58 to structures when emulating the POSIX interface.
60 int sys_acl_free( void *obj_p)
62 The calls we actually use are :
64 int sys_acl_free_text(char *text) - free acl_to_text
65 int sys_acl_free_acl(SMB_ACL_T posix_acl)
69 #if defined(HAVE_POSIX_ACLS)
71 /* Identity mapping - easy. */
73 int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
75 return acl_get_entry( the_acl, entry_id, entry_p);
78 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
80 return acl_get_tag_type( entry_d, tag_type_p);
83 int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
85 return acl_get_permset( entry_d, permset_p);
88 void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
90 return acl_get_qualifier( entry_d);
93 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
95 return acl_get_file( path_p, type);
98 SMB_ACL_T sys_acl_get_fd(int fd)
100 return acl_get_fd(fd);
103 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
105 return acl_clear_perms(permset);
108 int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
110 return acl_add_perm(permset, perm);
113 int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
115 return acl_get_perm(permset, perm);
118 char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
120 return acl_to_text( the_acl, plen);
123 SMB_ACL_T sys_acl_init( int count)
125 return acl_init(count);
128 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
130 return acl_create_entry(pacl, pentry);
133 int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
135 return acl_set_tag_type(entry, tagtype);
138 int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
140 return acl_set_qualifier(entry, qual);
143 int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
145 return acl_set_permset(entry, permset);
148 int sys_acl_valid( SMB_ACL_T theacl )
150 return acl_valid(theacl);
153 int sys_acl_set_file( char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
155 return acl_set_file(name, acltype, theacl);
158 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
160 return acl_set_fd(fd, theacl);
163 int sys_acl_free_text(char *text)
165 return acl_free(text);
168 int sys_acl_free_acl(SMB_ACL_T the_acl)
170 return acl_free(the_acl);
173 #elif defined(HAVE_UNIXWARE_ACLS)
176 * Donated by Michael Davidson <md@sco.COM> for UnixWare.
177 * As this is generic SVR4.x code, it may also work for Solaris !
180 #define INITIAL_ACL_SIZE 16
182 #define SETACL ACL_SET
186 #define GETACL ACL_GET
190 #define GETACLCNT ACL_CNT
195 * until official facl() support shows up in UW 7.1.2
197 int facl(int fd, int cmd, int nentries, struct acl *aclbufp)
199 return syscall(188, fd, cmd, nentries, aclbufp);
204 int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
206 if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
211 if (entry_p == NULL) {
216 if (entry_id == SMB_ACL_FIRST_ENTRY) {
220 if (acl_d->next < 0) {
225 if (acl_d->next >= acl_d->count) {
229 *entry_p = &acl_d->acl[acl_d->next++];
234 int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
236 *type_p = entry_d->a_type;
241 int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
243 *permset_p = &entry_d->a_perm;
248 void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
250 if (entry_d->a_type != SMB_ACL_USER
251 && entry_d->a_type != SMB_ACL_GROUP) {
256 return &entry_d->a_id;
259 SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
262 int count; /* # of ACL entries allocated */
263 int naccess; /* # of access ACL entries */
264 int ndefault; /* # of default ACL entries */
266 if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
271 count = INITIAL_ACL_SIZE;
272 if ((acl_d = sys_acl_init(count)) == NULL) {
276 while ((count = acl(path_p, GETACL, count, &acl_d->acl[0])) < 0
277 && errno == ENOSPC) {
279 if ((count = acl(path_p, GETACLCNT, 0, NULL)) < 0) {
283 sys_acl_free_acl(acl_d);
285 if ((acl_d = sys_acl_init(count)) == NULL) {
295 * calculate the number of access and default ACL entries
297 * Note: we assume that the acl() system call returned a
298 * well formed ACL which is sorted so that all of the
299 * access ACL entries preceed any default ACL entries
301 for (naccess = 0; naccess < count; naccess++) {
302 if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
305 ndefault = count - naccess;
308 * if the caller wants the default ACL we have to copy
309 * the entries down to the start of the acl[] buffer
310 * and mask out the ACL_DEFAULT flag from the type field
312 if (type == SMB_ACL_TYPE_DEFAULT) {
315 for (i = 0, j = naccess; i < ndefault; i++, j++) {
316 acl_d->acl[i] = acl_d->acl[j];
317 acl_d->acl[i].a_type &= ~ACL_DEFAULT;
320 acl_d->count = ndefault;
322 acl_d->count = naccess;
328 SMB_ACL_T sys_acl_get_fd(int fd)
331 int count; /* # of ACL entries allocated */
332 int naccess; /* # of access ACL entries */
334 count = INITIAL_ACL_SIZE;
335 if ((acl_d = sys_acl_init(count)) == NULL) {
339 while ((count = facl(fd, GETACL, count, &acl_d->acl[0])) < 0
340 && errno == ENOSPC) {
342 if ((count = facl(fd, GETACLCNT, 0, NULL)) < 0) {
346 sys_acl_free_acl(acl_d);
348 if ((acl_d = sys_acl_init(count)) == NULL) {
358 * calculate the number of access ACL entries
360 for (naccess = 0; naccess < count; naccess++) {
361 if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
365 acl_d->count = naccess;
370 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
377 int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
379 if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
380 && perm != SMB_ACL_EXECUTE) {
385 if (permset_d == NULL) {
395 int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
397 return *permset_d & perm;
400 char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
407 * use an initial estimate of 20 bytes per ACL entry
408 * when allocating memory for the text representation
412 maxlen = 20 * acl_d->count;
413 if ((text = malloc(maxlen)) == NULL) {
418 for (i = 0; i < acl_d->count; i++) {
419 struct acl *ap = &acl_d->acl[i];
429 switch (ap->a_type) {
431 * for debugging purposes it's probably more
432 * useful to dump unknown tag types rather
433 * than just returning an error
436 snprintf(tagbuf, sizeof tagbuf, "0x%x",
439 snprintf(idbuf, sizeof idbuf, "%ld",
445 if ((pw = getpwuid(ap->a_id)) == NULL) {
446 snprintf(idbuf, sizeof idbuf, "%ld",
452 case SMB_ACL_USER_OBJ:
457 if ((gr = getgrgid(ap->a_id)) == NULL) {
458 snprintf(idbuf, sizeof idbuf, "%ld",
464 case SMB_ACL_GROUP_OBJ:
478 perms[0] = (ap->a_perm & S_IRUSR) ? 'r' : '-';
479 perms[1] = (ap->a_perm & S_IWUSR) ? 'w' : '-';
480 perms[2] = (ap->a_perm & S_IXUSR) ? 'x' : '-';
483 /* <tag> : <qualifier> : rwx \n \0 */
484 nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
486 if ((len + nbytes) > maxlen) {
488 * allocate enough additional memory for this
489 * entry and an estimate of another 20 bytes
490 * for each entry still to be processed
492 maxlen += nbytes + 20 * (acl_d->count - i);
494 if ((text = realloc(text, maxlen)) == NULL) {
500 snprintf(&text[len], nbytes, "%s:%s:%s\n", tag, id, perms);
510 SMB_ACL_T sys_acl_init(int count)
520 * note that since the definition of the structure pointed
521 * to by the SMB_ACL_T includes the first element of the
522 * acl[] array, this actually allocates an ACL with room
523 * for (count+1) entries
525 if ((a = malloc(sizeof(*a) + count * sizeof(struct acl))) == NULL) {
538 int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
541 SMB_ACL_ENTRY_T entry_d;
543 if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
548 if (acl_d->count >= acl_d->size) {
553 entry_d = &acl_d->acl[acl_d->count++];
562 int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
566 case SMB_ACL_USER_OBJ:
568 case SMB_ACL_GROUP_OBJ:
571 entry_d->a_type = tag_type;
581 int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
583 if (entry_d->a_type != SMB_ACL_GROUP
584 && entry_d->a_type != SMB_ACL_USER) {
589 entry_d->a_id = *((id_t *)qual_p);
594 int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
596 if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
600 entry_d->a_perm = *permset_d;
605 int sys_acl_valid(SMB_ACL_T acl_d)
607 if (aclsort(acl_d->count, 0, acl_d->acl) != 0) {
615 int sys_acl_set_file(char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
620 struct acl *acl_buf = NULL;
623 if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
628 if (stat(name, &s) != 0) {
632 acl_p = &acl_d->acl[0];
633 acl_count = acl_d->count;
636 * if it's a directory there is extra work to do
637 * since the acl() system call will replace both
638 * the access ACLs and the default ACLs (if any)
640 if (S_ISDIR(s.st_mode)) {
646 if (type == SMB_ACL_TYPE_ACCESS) {
649 tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
654 tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
657 if (tmp_acl == NULL) {
662 * allocate a temporary buffer for the complete ACL
664 acl_count = acc_acl->count + def_acl->count;
666 acl_buf = malloc(acl_count * sizeof(acl_buf[0]));
668 if (acl_buf == NULL) {
669 sys_acl_free_acl(tmp_acl);
675 * copy the access control and default entries into the buffer
677 memcpy(&acl_buf[0], &acc_acl->acl[0],
678 acc_acl->count * sizeof(acl_buf[0]));
680 memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
681 def_acl->count * sizeof(acl_buf[0]));
684 * set the ACL_DEFAULT flag on the default entries
686 for (i = acc_acl->count; i < acl_count; i++) {
687 acl_buf[i].a_type |= ACL_DEFAULT;
690 sys_acl_free_acl(tmp_acl);
692 } else if (type != SMB_ACL_TYPE_ACCESS) {
697 if (aclsort(acl_count, 0, acl_p) != 0) {
701 ret = acl(name, SETACL, acl_count, acl_p);
711 int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
713 if (aclsort(acl_d->count, 0, acl_d->acl) != 0) {
718 return facl(fd, SETACL, acl_d->count, &acl_d->acl[0]);
721 int sys_acl_free_text(char *text)
727 int sys_acl_free_acl(SMB_ACL_T acl_d)
732 #elif defined(HAVE_SOLARIS_ACLS)
734 #elif defined(HAVE_IRIX_ACLS)
738 int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
743 int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
748 int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
753 void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
758 SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
760 return (SMB_ACL_T)NULL;
763 SMB_ACL_T sys_acl_get_fd(int fd)
765 return (SMB_ACL_T)NULL;
768 int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
773 int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
778 int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
780 return (permset & perm) ? 1 : 0;
783 char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
788 int sys_acl_free_text(char *text)
793 SMB_ACL_T sys_acl_init( int count)
798 int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
803 int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
808 int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
813 int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
818 int sys_acl_valid( SMB_ACL_T theacl )
823 int sys_acl_set_file( char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
828 int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
833 int sys_acl_free_acl(SMB_ACL_T the_acl)
837 #endif /* No ACLs. */