diff options
Diffstat (limited to 'lib/sysacls.c')
-rw-r--r-- | lib/sysacls.c | 2802 |
1 files changed, 2802 insertions, 0 deletions
diff --git a/lib/sysacls.c b/lib/sysacls.c new file mode 100644 index 0000000..a5abe40 --- /dev/null +++ b/lib/sysacls.c @@ -0,0 +1,2802 @@ +/* + * Unix SMB/CIFS implementation. + * Based on the Samba ACL support code. + * Copyright (C) Jeremy Allison 2000. + * Copyright (C) 2007-2022 Wayne Davison + * + * The permission functions have been changed to get/set all bits via + * one call. Some functions that rsync doesn't need were also removed. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * with this program; if not, visit the http://fsf.org website. + */ + +#include "rsync.h" +#include "sysacls.h" + +#ifdef SUPPORT_ACLS + +#ifdef DEBUG +#undef DEBUG +#endif +#define DEBUG(x, y) + +void SAFE_FREE(void *mem) +{ + if (mem) + free(mem); +} + +/* + This file wraps all differing system ACL interfaces into a consistent + one based on the POSIX interface. It also returns the correct errors + for older UNIX systems that don't support ACLs. + + The interfaces that each ACL implementation must support are as follows : + + int sys_acl_get_entry(SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p) + int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p) + 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) + SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type) + SMB_ACL_T sys_acl_get_fd(int fd) + SMB_ACL_T sys_acl_init(int count) + int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry) + int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id) + int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits) + int sys_acl_valid(SMB_ACL_T theacl) + int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) + int sys_acl_set_fd(int fd, SMB_ACL_T theacl) + int sys_acl_delete_def_file(const char *path) + int sys_acl_free_acl(SMB_ACL_T posix_acl) + +*/ + +#if defined(HAVE_POSIX_ACLS) /*--------------------------------------------*/ + +/* Identity mapping - easy. */ + +int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p) +{ + return acl_get_entry(the_acl, entry_id, entry_p); +} + +int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p) +{ + return acl_get_tag_type(entry_d, tag_type_p); +} + +SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type) +{ + return acl_get_file(path_p, type); +} + +#if 0 +SMB_ACL_T sys_acl_get_fd(int fd) +{ + return acl_get_fd(fd); +} +#endif + +#if defined(HAVE_ACL_GET_PERM_NP) +#define acl_get_perm(p, b) acl_get_perm_np(p, b) +#endif + +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) +{ + acl_permset_t permset; + + if (acl_get_tag_type(entry, tag_type_p) != 0 + || acl_get_permset(entry, &permset) != 0) + return -1; + + *bits_p = (acl_get_perm(permset, ACL_READ) ? 4 : 0) + | (acl_get_perm(permset, ACL_WRITE) ? 2 : 0) + | (acl_get_perm(permset, ACL_EXECUTE) ? 1 : 0); + + if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP) { + void *qual; + if ((qual = acl_get_qualifier(entry)) == NULL) + return -1; + *u_g_id_p = *(id_t*)qual; + acl_free(qual); + } + + return 0; +} + +SMB_ACL_T sys_acl_init(int count) +{ + return acl_init(count); +} + +int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry) +{ + return acl_create_entry(pacl, pentry); +} + +int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id) +{ + if (acl_set_tag_type(entry, tag_type) != 0) + return -1; + + if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP) { + if (acl_set_qualifier(entry, (void*)&u_g_id) != 0) + return -1; + } + + return sys_acl_set_access_bits(entry, bits); +} + +int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits) +{ + acl_permset_t permset; + int rc; + if ((rc = acl_get_permset(entry, &permset)) != 0) + return rc; + acl_clear_perms(permset); + if (bits & 4) + acl_add_perm(permset, ACL_READ); + if (bits & 2) + acl_add_perm(permset, ACL_WRITE); + if (bits & 1) + acl_add_perm(permset, ACL_EXECUTE); + return acl_set_permset(entry, permset); +} + +int sys_acl_valid(SMB_ACL_T theacl) +{ + return acl_valid(theacl); +} + +int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) +{ + return acl_set_file(name, acltype, theacl); +} + +#if 0 +int sys_acl_set_fd(int fd, SMB_ACL_T theacl) +{ + return acl_set_fd(fd, theacl); +} +#endif + +int sys_acl_delete_def_file(const char *name) +{ + return acl_delete_def_file(name); +} + +int sys_acl_free_acl(SMB_ACL_T the_acl) +{ + return acl_free(the_acl); +} + +#elif defined(HAVE_TRU64_ACLS) /*--------------------------------------------*/ +/* + * The interface to DEC/Compaq Tru64 UNIX ACLs + * is based on Draft 13 of the POSIX spec which is + * slightly different from the Draft 16 interface. + * + * Also, some of the permset manipulation functions + * such as acl_clear_perm() and acl_add_perm() appear + * to be broken on Tru64 so we have to manipulate + * the permission bits in the permset directly. + */ +int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p) +{ + SMB_ACL_ENTRY_T entry; + + if (entry_id == SMB_ACL_FIRST_ENTRY && acl_first_entry(the_acl) != 0) { + return -1; + } + + errno = 0; + if ((entry = acl_get_entry(the_acl)) != NULL) { + *entry_p = entry; + return 1; + } + + return errno ? -1 : 0; +} + +int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p) +{ + return acl_get_tag_type(entry_d, tag_type_p); +} + +SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type) +{ + return acl_get_file((char *)path_p, type); +} + +#if 0 +SMB_ACL_T sys_acl_get_fd(int fd) +{ + return acl_get_fd(fd, ACL_TYPE_ACCESS); +} +#endif + +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) +{ + acl_permset_t permset; + + if (acl_get_tag_type(entry, tag_type_p) != 0 + || acl_get_permset(entry, &permset) != 0) + return -1; + + *bits_p = *permset & 7; /* Tru64 doesn't have acl_get_perm() */ + + if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP) { + void *qual; + if ((qual = acl_get_qualifier(entry)) == NULL) + return -1; + *u_g_id_p = *(id_t*)qual; + acl_free_qualifier(qual, *tag_type_p); + } + + return 0; +} + +SMB_ACL_T sys_acl_init(int count) +{ + return acl_init(count); +} + +int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry) +{ + SMB_ACL_ENTRY_T entry; + + if ((entry = acl_create_entry(pacl)) == NULL) { + return -1; + } + + *pentry = entry; + return 0; +} + +int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id) +{ + if (acl_set_tag_type(entry, tag_type) != 0) + return -1; + + if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP) { + if (acl_set_qualifier(entry, (void*)&u_g_id) != 0) + return -1; + } + + return sys_acl_set_access_bits(entry, bits); +} + +int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits) +{ + acl_permset_t permset; + int rc; + if ((rc = acl_get_permset(entry, &permset)) != 0) + return rc; + *permset = bits & 7; + return acl_set_permset(entry, permset); +} + +int sys_acl_valid(SMB_ACL_T theacl) +{ + acl_entry_t entry; + + return acl_valid(theacl, &entry); +} + +int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) +{ + return acl_set_file((char *)name, acltype, theacl); +} + +#if 0 +int sys_acl_set_fd(int fd, SMB_ACL_T theacl) +{ + return acl_set_fd(fd, ACL_TYPE_ACCESS, theacl); +} +#endif + +int sys_acl_delete_def_file(const char *name) +{ + return acl_delete_def_file((char *)name); +} + +int sys_acl_free_acl(SMB_ACL_T the_acl) +{ + return acl_free(the_acl); +} + +#elif defined(HAVE_UNIXWARE_ACLS) || defined(HAVE_SOLARIS_ACLS) /*-----------*/ + +/* + * Donated by Michael Davidson <md@sco.COM> for UnixWare / OpenUNIX. + * Modified by Toomas Soome <tsoome@ut.ee> for Solaris. + */ + +/* + * Note that while this code implements sufficient functionality + * to support the sys_acl_* interfaces it does not provide all + * of the semantics of the POSIX ACL interfaces. + * + * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned + * from a call to sys_acl_get_entry() should not be assumed to be + * valid after calling any of the following functions, which may + * reorder the entries in the ACL. + * + * sys_acl_valid() + * sys_acl_set_file() + * sys_acl_set_fd() + */ + +/* + * The only difference between Solaris and UnixWare / OpenUNIX is + * that the #defines for the ACL operations have different names + */ +#if defined(HAVE_UNIXWARE_ACLS) + +#define SETACL ACL_SET +#define GETACL ACL_GET +#define GETACLCNT ACL_CNT + +#endif + + +int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p) +{ + if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) { + errno = EINVAL; + return -1; + } + + if (entry_p == NULL) { + errno = EINVAL; + return -1; + } + + if (entry_id == SMB_ACL_FIRST_ENTRY) { + acl_d->next = 0; + } + + if (acl_d->next < 0) { + errno = EINVAL; + return -1; + } + + if (acl_d->next >= acl_d->count) { + return 0; + } + + *entry_p = &acl_d->acl[acl_d->next++]; + + return 1; +} + +int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p) +{ + *type_p = entry_d->a_type; + + return 0; +} + +/* + * There is no way of knowing what size the ACL returned by + * GETACL will be unless you first call GETACLCNT which means + * making an additional system call. + * + * In the hope of avoiding the cost of the additional system + * call in most cases, we initially allocate enough space for + * an ACL with INITIAL_ACL_SIZE entries. If this turns out to + * be too small then we use GETACLCNT to find out the actual + * size, reallocate the ACL buffer, and then call GETACL again. + */ + +#define INITIAL_ACL_SIZE 16 + +SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type) +{ + SMB_ACL_T acl_d; + int count; /* # of ACL entries allocated */ + int naccess; /* # of access ACL entries */ + int ndefault; /* # of default ACL entries */ + + if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) { + errno = EINVAL; + return NULL; + } + + count = INITIAL_ACL_SIZE; + if ((acl_d = sys_acl_init(count)) == NULL) { + return NULL; + } + + /* + * If there isn't enough space for the ACL entries we use + * GETACLCNT to determine the actual number of ACL entries + * reallocate and try again. This is in a loop because it + * is possible that someone else could modify the ACL and + * increase the number of entries between the call to + * GETACLCNT and the call to GETACL. + */ + while ((count = acl(path_p, GETACL, count, &acl_d->acl[0])) < 0 + && errno == ENOSPC) { + + sys_acl_free_acl(acl_d); + + if ((count = acl(path_p, GETACLCNT, 0, NULL)) < 0) { + return NULL; + } + + if ((acl_d = sys_acl_init(count)) == NULL) { + return NULL; + } + } + + if (count < 0) { + sys_acl_free_acl(acl_d); + return NULL; + } + + /* + * calculate the number of access and default ACL entries + * + * Note: we assume that the acl() system call returned a + * well formed ACL which is sorted so that all of the + * access ACL entries precede any default ACL entries + */ + for (naccess = 0; naccess < count; naccess++) { + if (acl_d->acl[naccess].a_type & ACL_DEFAULT) + break; + } + ndefault = count - naccess; + + /* + * if the caller wants the default ACL we have to copy + * the entries down to the start of the acl[] buffer + * and mask out the ACL_DEFAULT flag from the type field + */ + if (type == SMB_ACL_TYPE_DEFAULT) { + int i, j; + + for (i = 0, j = naccess; i < ndefault; i++, j++) { + acl_d->acl[i] = acl_d->acl[j]; + acl_d->acl[i].a_type &= ~ACL_DEFAULT; + } + + acl_d->count = ndefault; + } else { + acl_d->count = naccess; + } + + return acl_d; +} + +#if 0 +SMB_ACL_T sys_acl_get_fd(int fd) +{ + SMB_ACL_T acl_d; + int count; /* # of ACL entries allocated */ + int naccess; /* # of access ACL entries */ + + count = INITIAL_ACL_SIZE; + if ((acl_d = sys_acl_init(count)) == NULL) { + return NULL; + } + + while ((count = facl(fd, GETACL, count, &acl_d->acl[0])) < 0 + && errno == ENOSPC) { + + sys_acl_free_acl(acl_d); + + if ((count = facl(fd, GETACLCNT, 0, NULL)) < 0) { + return NULL; + } + + if ((acl_d = sys_acl_init(count)) == NULL) { + return NULL; + } + } + + if (count < 0) { + sys_acl_free_acl(acl_d); + return NULL; + } + + /* + * calculate the number of access ACL entries + */ + for (naccess = 0; naccess < count; naccess++) { + if (acl_d->acl[naccess].a_type & ACL_DEFAULT) + break; + } + + acl_d->count = naccess; + + return acl_d; +} +#endif + +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) +{ + *tag_type_p = entry->a_type; + + *bits_p = entry->a_perm; + + if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP) + *u_g_id_p = entry->a_id; + + return 0; +} + +SMB_ACL_T sys_acl_init(int count) +{ + SMB_ACL_T a; + + if (count < 0) { + errno = EINVAL; + return NULL; + } + + /* + * note that since the definition of the structure pointed + * to by the SMB_ACL_T includes the first element of the + * acl[] array, this actually allocates an ACL with room + * for (count+1) entries + */ + if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof a[0] + count * sizeof (struct acl))) == NULL) { + errno = ENOMEM; + return NULL; + } + + a->size = count + 1; + a->count = 0; + a->next = -1; + + return a; +} + + +int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p) +{ + SMB_ACL_T acl_d; + SMB_ACL_ENTRY_T entry_d; + + if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) { + errno = EINVAL; + return -1; + } + + if (acl_d->count >= acl_d->size) { + errno = ENOSPC; + return -1; + } + + entry_d = &acl_d->acl[acl_d->count++]; + entry_d->a_type = 0; + entry_d->a_id = -1; + entry_d->a_perm = 0; + *entry_p = entry_d; + + return 0; +} + +int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id) +{ + entry->a_type = tag_type; + + if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP) + entry->a_id = u_g_id; + + entry->a_perm = bits; + + return 0; +} + +int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry_d, uint32 bits) +{ + entry_d->a_perm = bits; + return 0; +} + +/* + * sort the ACL and check it for validity + * + * if it's a minimal ACL with only 4 entries then we + * need to recalculate the mask permissions to make + * sure that they are the same as the GROUP_OBJ + * permissions as required by the UnixWare acl() system call. + * + * (note: since POSIX allows minimal ACLs which only contain + * 3 entries - ie there is no mask entry - we should, in theory, + * check for this and add a mask entry if necessary - however + * we "know" that the caller of this interface always specifies + * a mask so, in practice "this never happens" (tm) - if it *does* + * happen aclsort() will fail and return an error and someone will + * have to fix it ...) + */ + +static int acl_sort(SMB_ACL_T acl_d) +{ + int fixmask = (acl_d->count <= 4); + + if (aclsort(acl_d->count, fixmask, acl_d->acl) != 0) { + errno = EINVAL; + return -1; + } + return 0; +} + +int sys_acl_valid(SMB_ACL_T acl_d) +{ + return acl_sort(acl_d); +} + +int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d) +{ + struct stat s; + struct acl *acl_p; + int acl_count; + struct acl *acl_buf = NULL; + int ret; + + if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) { + errno = EINVAL; + return -1; + } + + if (acl_sort(acl_d) != 0) { + return -1; + } + + acl_p = &acl_d->acl[0]; + acl_count = acl_d->count; + + /* + * if it's a directory there is extra work to do + * since the acl() system call will replace both + * the access ACLs and the default ACLs (if any) + */ + if (stat(name, &s) != 0) { + return -1; + } + if (S_ISDIR(s.st_mode)) { + SMB_ACL_T acc_acl; + SMB_ACL_T def_acl; + SMB_ACL_T tmp_acl; + int i; + + if (type == SMB_ACL_TYPE_ACCESS) { + acc_acl = acl_d; + def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT); + + } else { + def_acl = acl_d; + acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS); + } + + if (tmp_acl == NULL) { + return -1; + } + + /* + * allocate a temporary buffer for the complete ACL + */ + acl_count = acc_acl->count + def_acl->count; + acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count); + + if (acl_buf == NULL) { + sys_acl_free_acl(tmp_acl); + errno = ENOMEM; + return -1; + } + + /* + * copy the access control and default entries into the buffer + */ + memcpy(&acl_buf[0], &acc_acl->acl[0], + acc_acl->count * sizeof acl_buf[0]); + + memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0], + def_acl->count * sizeof acl_buf[0]); + + /* + * set the ACL_DEFAULT flag on the default entries + */ + for (i = acc_acl->count; i < acl_count; i++) { + acl_buf[i].a_type |= ACL_DEFAULT; + } + + sys_acl_free_acl(tmp_acl); + + } else if (type != SMB_ACL_TYPE_ACCESS) { + errno = EINVAL; + return -1; + } + + ret = acl(name, SETACL, acl_count, acl_p); + + SAFE_FREE(acl_buf); + + return ret; +} + +#if 0 +int sys_acl_set_fd(int fd, SMB_ACL_T acl_d) +{ + if (acl_sort(acl_d) != 0) { + return -1; + } + + return facl(fd, SETACL, acl_d->count, &acl_d->acl[0]); +} +#endif + +int sys_acl_delete_def_file(const char *path) +{ + SMB_ACL_T acl_d; + int ret; + + /* + * fetching the access ACL and rewriting it has + * the effect of deleting the default ACL + */ + if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) { + return -1; + } + + ret = acl(path, SETACL, acl_d->count, acl_d->acl); + + sys_acl_free_acl(acl_d); + + return ret; +} + +int sys_acl_free_acl(SMB_ACL_T acl_d) +{ + SAFE_FREE(acl_d); + return 0; +} + +#elif defined(HAVE_HPUX_ACLS) /*---------------------------------------------*/ + +#ifdef HAVE_DL_H +#include <dl.h> +#endif + +/* + * Based on the Solaris/SCO code - with modifications. + */ + +/* + * Note that while this code implements sufficient functionality + * to support the sys_acl_* interfaces it does not provide all + * of the semantics of the POSIX ACL interfaces. + * + * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned + * from a call to sys_acl_get_entry() should not be assumed to be + * valid after calling any of the following functions, which may + * reorder the entries in the ACL. + * + * sys_acl_valid() + * sys_acl_set_file() + * sys_acl_set_fd() + */ + +/* This checks if the POSIX ACL system call is defined */ +/* which basically corresponds to whether JFS 3.3 or */ +/* higher is installed. If acl() was called when it */ +/* isn't defined, it causes the process to core dump */ +/* so it is important to check this and avoid acl() */ +/* calls if it isn't there. */ + +#ifdef __TANDEM +inline int do_acl(const char *path_p, int cmd, int nentries, struct acl *aclbufp) +{ + return acl((char*)path_p, cmd, nentries, aclbufp); +} +#define acl(p,c,n,a) do_acl(p,c,n,a) +#endif + +static BOOL hpux_acl_call_presence(void) +{ +#ifndef __TANDEM + shl_t handle = NULL; + void *value; + int ret_val=0; + static BOOL already_checked=0; + + if (already_checked) + return True; + + ret_val = shl_findsym(&handle, "acl", TYPE_PROCEDURE, &value); + + if (ret_val != 0) { + DEBUG(5, ("hpux_acl_call_presence: shl_findsym() returned %d, errno = %d, error %s\n", + ret_val, errno, strerror(errno))); + DEBUG(5, ("hpux_acl_call_presence: acl() system call is not present. Check if you have JFS 3.3 and above?\n")); + return False; + } + + DEBUG(10, ("hpux_acl_call_presence: acl() system call is present. We have JFS 3.3 or above \n")); + + already_checked = True; +#endif + return True; +} + +int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p) +{ + if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) { + errno = EINVAL; + return -1; + } + + if (entry_p == NULL) { + errno = EINVAL; + return -1; + } + + if (entry_id == SMB_ACL_FIRST_ENTRY) { + acl_d->next = 0; + } + + if (acl_d->next < 0) { + errno = EINVAL; + return -1; + } + + if (acl_d->next >= acl_d->count) { + return 0; + } + + *entry_p = &acl_d->acl[acl_d->next++]; + + return 1; +} + +int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p) +{ + *type_p = entry_d->a_type; + + return 0; +} + +/* + * There is no way of knowing what size the ACL returned by + * ACL_GET will be unless you first call ACL_CNT which means + * making an additional system call. + * + * In the hope of avoiding the cost of the additional system + * call in most cases, we initially allocate enough space for + * an ACL with INITIAL_ACL_SIZE entries. If this turns out to + * be too small then we use ACL_CNT to find out the actual + * size, reallocate the ACL buffer, and then call ACL_GET again. + */ + +#define INITIAL_ACL_SIZE 16 + +#ifndef NACLENTRIES +#define NACLENTRIES 0 +#endif + +SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type) +{ + SMB_ACL_T acl_d; + int count; /* # of ACL entries allocated */ + int naccess; /* # of access ACL entries */ + int ndefault; /* # of default ACL entries */ + + if (hpux_acl_call_presence() == False) { + /* Looks like we don't have the acl() system call on HPUX. + * May be the system doesn't have the latest version of JFS. + */ + return NULL; + } + + if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) { + errno = EINVAL; + return NULL; + } + + count = INITIAL_ACL_SIZE; + if ((acl_d = sys_acl_init(count)) == NULL) { + return NULL; + } + + /* + * If there isn't enough space for the ACL entries we use + * ACL_CNT to determine the actual number of ACL entries + * reallocate and try again. This is in a loop because it + * is possible that someone else could modify the ACL and + * increase the number of entries between the call to + * ACL_CNT and the call to ACL_GET. + */ + while ((count = acl(path_p, ACL_GET, count, &acl_d->acl[0])) < 0 && errno == ENOSPC) { + + sys_acl_free_acl(acl_d); + + if ((count = acl(path_p, ACL_CNT, NACLENTRIES, NULL)) < 0) { + return NULL; + } + + if ((acl_d = sys_acl_init(count)) == NULL) { + return NULL; + } + } + + if (count < 0) { + sys_acl_free_acl(acl_d); + return NULL; + } + + /* + * calculate the number of access and default ACL entries + * + * Note: we assume that the acl() system call returned a + * well formed ACL which is sorted so that all of the + * access ACL entries precede any default ACL entries + */ + for (naccess = 0; naccess < count; naccess++) { + if (acl_d->acl[naccess].a_type & ACL_DEFAULT) + break; + } + ndefault = count - naccess; + + /* + * if the caller wants the default ACL we have to copy + * the entries down to the start of the acl[] buffer + * and mask out the ACL_DEFAULT flag from the type field + */ + if (type == SMB_ACL_TYPE_DEFAULT) { + int i, j; + + for (i = 0, j = naccess; i < ndefault; i++, j++) { + acl_d->acl[i] = acl_d->acl[j]; + acl_d->acl[i].a_type &= ~ACL_DEFAULT; + } + + acl_d->count = ndefault; + } else { + acl_d->count = naccess; + } + + return acl_d; +} + +#if 0 +SMB_ACL_T sys_acl_get_fd(int fd) +{ + /* + * HPUX doesn't have the facl call. Fake it using the path.... JRA. + */ + + files_struct *fsp = file_find_fd(fd); + + if (fsp == NULL) { + errno = EBADF; + return NULL; + } + + /* + * We know we're in the same conn context. So we + * can use the relative path. + */ + + return sys_acl_get_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS); +} +#endif + +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) +{ + *tag_type_p = entry->a_type; + + *bits_p = entry->a_perm; + + if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP) + *u_g_id_p = entry->a_id; + + return 0; +} + +SMB_ACL_T sys_acl_init(int count) +{ + SMB_ACL_T a; + + if (count < 0) { + errno = EINVAL; + return NULL; + } + + /* + * note that since the definition of the structure pointed + * to by the SMB_ACL_T includes the first element of the + * acl[] array, this actually allocates an ACL with room + * for (count+1) entries + */ + if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof a[0] + count * sizeof (struct acl))) == NULL) { + errno = ENOMEM; + return NULL; + } + + a->size = count + 1; + a->count = 0; + a->next = -1; + + return a; +} + + +int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p) +{ + SMB_ACL_T acl_d; + SMB_ACL_ENTRY_T entry_d; + + if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) { + errno = EINVAL; + return -1; + } + + if (acl_d->count >= acl_d->size) { + errno = ENOSPC; + return -1; + } + + entry_d = &acl_d->acl[acl_d->count++]; + entry_d->a_type = 0; + entry_d->a_id = -1; + entry_d->a_perm = 0; + *entry_p = entry_d; + + return 0; +} + +int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id) +{ + entry->a_type = tag_type; + + if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP) + entry->a_id = u_g_id; + + entry->a_perm = bits; + + return 0; +} + +int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry_d, uint32 bits) +{ + entry_d->a_perm = bits; + + return 0; +} + +/* Structure to capture the count for each type of ACE. */ + +struct hpux_acl_types { + int n_user; + int n_def_user; + int n_user_obj; + int n_def_user_obj; + + int n_group; + int n_def_group; + int n_group_obj; + int n_def_group_obj; + + int n_other; + int n_other_obj; + int n_def_other_obj; + + int n_class_obj; + int n_def_class_obj; + + int n_illegal_obj; +}; + +/* count_obj: + * Counts the different number of objects in a given array of ACL + * structures. + * Inputs: + * + * acl_count - Count of ACLs in the array of ACL structures. + * aclp - Array of ACL structures. + * acl_type_count - Pointer to acl_types structure. Should already be + * allocated. + * Output: + * + * acl_type_count - This structure is filled up with counts of various + * acl types. + */ + +static void hpux_count_obj(int acl_count, struct acl *aclp, struct hpux_acl_types *acl_type_count) +{ + int i; + + memset(acl_type_count, 0, sizeof (struct hpux_acl_types)); + + for (i = 0; i < acl_count; i++) { + switch (aclp[i].a_type) { + case USER: + acl_type_count->n_user++; + break; + case USER_OBJ: + acl_type_count->n_user_obj++; + break; + case DEF_USER_OBJ: + acl_type_count->n_def_user_obj++; + break; + case GROUP: + acl_type_count->n_group++; + break; + case GROUP_OBJ: + acl_type_count->n_group_obj++; + break; + case DEF_GROUP_OBJ: + acl_type_count->n_def_group_obj++; + break; + case OTHER_OBJ: + acl_type_count->n_other_obj++; + break; + case DEF_OTHER_OBJ: + acl_type_count->n_def_other_obj++; + break; + case CLASS_OBJ: + acl_type_count->n_class_obj++; + break; + case DEF_CLASS_OBJ: + acl_type_count->n_def_class_obj++; + break; + case DEF_USER: + acl_type_count->n_def_user++; + break; + case DEF_GROUP: + acl_type_count->n_def_group++; + break; + default: + acl_type_count->n_illegal_obj++; + break; + } + } +} + +/* swap_acl_entries: Swaps two ACL entries. + * + * Inputs: aclp0, aclp1 - ACL entries to be swapped. + */ + +static void hpux_swap_acl_entries(struct acl *aclp0, struct acl *aclp1) +{ + struct acl temp_acl; + + temp_acl.a_type = aclp0->a_type; + temp_acl.a_id = aclp0->a_id; + temp_acl.a_perm = aclp0->a_perm; + + aclp0->a_type = aclp1->a_type; + aclp0->a_id = aclp1->a_id; + aclp0->a_perm = aclp1->a_perm; + + aclp1->a_type = temp_acl.a_type; + aclp1->a_id = temp_acl.a_id; + aclp1->a_perm = temp_acl.a_perm; +} + +/* prohibited_duplicate_type + * Identifies if given ACL type can have duplicate entries or + * not. + * + * Inputs: acl_type - ACL Type. + * + * Outputs: + * + * Return.. + * + * True - If the ACL type matches any of the prohibited types. + * False - If the ACL type doesn't match any of the prohibited types. + */ + +static BOOL hpux_prohibited_duplicate_type(int acl_type) +{ + switch (acl_type) { + case USER: + case GROUP: + case DEF_USER: + case DEF_GROUP: + return True; + default: + return False; + } +} + +/* get_needed_class_perm + * Returns the permissions of a ACL structure only if the ACL + * type matches one of the pre-determined types for computing + * CLASS_OBJ permissions. + * + * Inputs: aclp - Pointer to ACL structure. + */ + +static int hpux_get_needed_class_perm(struct acl *aclp) +{ + switch (aclp->a_type) { + case USER: + case GROUP_OBJ: + case GROUP: + case DEF_USER_OBJ: + case DEF_USER: + case DEF_GROUP_OBJ: + case DEF_GROUP: + case DEF_CLASS_OBJ: + case DEF_OTHER_OBJ: + return aclp->a_perm; + default: + return 0; + } +} + +/* acl_sort for HPUX. + * Sorts the array of ACL structures as per the description in + * aclsort man page. Refer to aclsort man page for more details + * + * Inputs: + * + * acl_count - Count of ACLs in the array of ACL structures. + * calclass - If this is not zero, then we compute the CLASS_OBJ + * permissions. + * aclp - Array of ACL structures. + * + * Outputs: + * + * aclp - Sorted array of ACL structures. + * + * Outputs: + * + * Returns 0 for success -1 for failure. Prints a message to the Samba + * debug log in case of failure. + */ + +static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp) +{ +#if !defined(HAVE_HPUX_ACLSORT) + /* + * The aclsort() system call is available on the latest HPUX General + * Patch Bundles. So for HPUX, we developed our version of acl_sort + * function. Because, we don't want to update to a new + * HPUX GR bundle just for aclsort() call. + */ + + struct hpux_acl_types acl_obj_count; + int n_class_obj_perm = 0; + int i, j; + + if (!acl_count) { + DEBUG(10, ("Zero acl count passed. Returning Success\n")); + return 0; + } + + if (aclp == NULL) { + DEBUG(0, ("Null ACL pointer in hpux_acl_sort. Returning Failure. \n")); + return -1; + } + + /* Count different types of ACLs in the ACLs array */ + + hpux_count_obj(acl_count, aclp, &acl_obj_count); + + /* There should be only one entry each of type USER_OBJ, GROUP_OBJ, + * CLASS_OBJ and OTHER_OBJ + */ + + if (acl_obj_count.n_user_obj != 1 + || acl_obj_count.n_group_obj != 1 + || acl_obj_count.n_class_obj != 1 + || acl_obj_count.n_other_obj != 1) { + DEBUG(0, ("hpux_acl_sort: More than one entry or no entries for \ +USER OBJ or GROUP_OBJ or OTHER_OBJ or CLASS_OBJ\n")); + return -1; + } + + /* If any of the default objects are present, there should be only + * one of them each. + */ + if (acl_obj_count.n_def_user_obj > 1 || acl_obj_count.n_def_group_obj > 1 + || acl_obj_count.n_def_other_obj > 1 || acl_obj_count.n_def_class_obj > 1) { + DEBUG(0, ("hpux_acl_sort: More than one entry for DEF_CLASS_OBJ \ +or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n")); + return -1; + } + + /* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl + * structures. + * + * Sorting crieteria - First sort by ACL type. If there are multiple entries of + * same ACL type, sort by ACL id. + * + * I am using the trivial kind of sorting method here because, performance isn't + * really effected by the ACLs feature. More over there aren't going to be more + * than 17 entries on HPUX. + */ + + for (i = 0; i < acl_count; i++) { + for (j = i+1; j < acl_count; j++) { + if (aclp[i].a_type > aclp[j].a_type) { + /* ACL entries out of order, swap them */ + hpux_swap_acl_entries((aclp+i), (aclp+j)); + } else if (aclp[i].a_type == aclp[j].a_type) { + /* ACL entries of same type, sort by id */ + if (aclp[i].a_id > aclp[j].a_id) { + hpux_swap_acl_entries((aclp+i), (aclp+j)); + } else if (aclp[i].a_id == aclp[j].a_id) { + /* We have a duplicate entry. */ + if (hpux_prohibited_duplicate_type(aclp[i].a_type)) { + DEBUG(0, ("hpux_acl_sort: Duplicate entry: Type(hex): %x Id: %d\n", + aclp[i].a_type, aclp[i].a_id)); + return -1; + } + } + } + } + } + + /* set the class obj permissions to the computed one. */ + if (calclass) { + int n_class_obj_index = -1; + + for (i = 0;i < acl_count; i++) { + n_class_obj_perm |= hpux_get_needed_class_perm((aclp+i)); + if (aclp[i].a_type == CLASS_OBJ) + n_class_obj_index = i; + } + aclp[n_class_obj_index].a_perm = n_class_obj_perm; + } + + return 0; +#else + return aclsort(acl_count, calclass, aclp); +#endif +} + +/* + * sort the ACL and check it for validity + * + * if it's a minimal ACL with only 4 entries then we + * need to recalculate the mask permissions to make + * sure that they are the same as the GROUP_OBJ + * permissions as required by the UnixWare acl() system call. + * + * (note: since POSIX allows minimal ACLs which only contain + * 3 entries - ie there is no mask entry - we should, in theory, + * check for this and add a mask entry if necessary - however + * we "know" that the caller of this interface always specifies + * a mask so, in practice "this never happens" (tm) - if it *does* + * happen aclsort() will fail and return an error and someone will + * have to fix it ...) + */ + +static int acl_sort(SMB_ACL_T acl_d) +{ + int fixmask = (acl_d->count <= 4); + + if (hpux_acl_sort(acl_d->count, fixmask, acl_d->acl) != 0) { + errno = EINVAL; + return -1; + } + return 0; +} + +int sys_acl_valid(SMB_ACL_T acl_d) +{ + return acl_sort(acl_d); +} + +int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d) +{ + struct stat s; + struct acl *acl_p; + int acl_count; + struct acl *acl_buf = NULL; + int ret; + + if (hpux_acl_call_presence() == False) { + /* Looks like we don't have the acl() system call on HPUX. + * May be the system doesn't have the latest version of JFS. + */ + errno=ENOSYS; + return -1; + } + + if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) { + errno = EINVAL; + return -1; + } + + if (acl_sort(acl_d) != 0) { + return -1; + } + + acl_p = &acl_d->acl[0]; + acl_count = acl_d->count; + + /* + * if it's a directory there is extra work to do + * since the acl() system call will replace both + * the access ACLs and the default ACLs (if any) + */ + if (stat(name, &s) != 0) { + return -1; + } + if (S_ISDIR(s.st_mode)) { + SMB_ACL_T acc_acl; + SMB_ACL_T def_acl; + SMB_ACL_T tmp_acl; + int i; + + if (type == SMB_ACL_TYPE_ACCESS) { + acc_acl = acl_d; + def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT); + + } else { + def_acl = acl_d; + acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS); + } + + if (tmp_acl == NULL) { + return -1; + } + + /* + * allocate a temporary buffer for the complete ACL + */ + acl_count = acc_acl->count + def_acl->count; + acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count); + + if (acl_buf == NULL) { + sys_acl_free_acl(tmp_acl); + errno = ENOMEM; + return -1; + } + + /* + * copy the access control and default entries into the buffer + */ + memcpy(&acl_buf[0], &acc_acl->acl[0], + acc_acl->count * sizeof acl_buf[0]); + + memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0], + def_acl->count * sizeof acl_buf[0]); + + /* + * set the ACL_DEFAULT flag on the default entries + */ + for (i = acc_acl->count; i < acl_count; i++) { + acl_buf[i].a_type |= ACL_DEFAULT; + } + + sys_acl_free_acl(tmp_acl); + + } else if (type != SMB_ACL_TYPE_ACCESS) { + errno = EINVAL; + return -1; + } + + ret = acl(name, ACL_SET, acl_count, acl_p); + + if (acl_buf) { + free(acl_buf); + } + + return ret; +} + +#if 0 +int sys_acl_set_fd(int fd, SMB_ACL_T acl_d) +{ + /* + * HPUX doesn't have the facl call. Fake it using the path.... JRA. + */ + + files_struct *fsp = file_find_fd(fd); + + if (fsp == NULL) { + errno = EBADF; + return NULL; + } + + if (acl_sort(acl_d) != 0) { + return -1; + } + + /* + * We know we're in the same conn context. So we + * can use the relative path. + */ + + return sys_acl_set_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS, acl_d); +} +#endif + +int sys_acl_delete_def_file(const char *path) +{ + SMB_ACL_T acl_d; + int ret; + + /* + * fetching the access ACL and rewriting it has + * the effect of deleting the default ACL + */ + if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) { + return -1; + } + + ret = acl(path, ACL_SET, acl_d->count, acl_d->acl); + + sys_acl_free_acl(acl_d); + + return ret; +} + +int sys_acl_free_acl(SMB_ACL_T acl_d) +{ + free(acl_d); + return 0; +} + +#elif defined(HAVE_IRIX_ACLS) /*---------------------------------------------*/ + +int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p) +{ + if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) { + errno = EINVAL; + return -1; + } + + if (entry_p == NULL) { + errno = EINVAL; + return -1; + } + + if (entry_id == SMB_ACL_FIRST_ENTRY) { + acl_d->next = 0; + } + + if (acl_d->next < 0) { + errno = EINVAL; + return -1; + } + + if (acl_d->next >= acl_d->aclp->acl_cnt) { + return 0; + } + + *entry_p = &acl_d->aclp->acl_entry[acl_d->next++]; + + return 1; +} + +int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p) +{ + *type_p = entry_d->ae_tag; + + return 0; +} + +SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type) +{ + SMB_ACL_T a; + + if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) { + errno = ENOMEM; + return NULL; + } + if ((a->aclp = acl_get_file(path_p, type)) == NULL) { + SAFE_FREE(a); + return NULL; + } + a->next = -1; + a->freeaclp = True; + return a; +} + +#if 0 +SMB_ACL_T sys_acl_get_fd(int fd) +{ + SMB_ACL_T a; + + if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) { + errno = ENOMEM; + return NULL; + } + if ((a->aclp = acl_get_fd(fd)) == NULL) { + SAFE_FREE(a); + return NULL; + } + a->next = -1; + a->freeaclp = True; + return a; +} +#endif + +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) +{ + *tag_type_p = entry->ae_tag; + + *bits_p = entry->ae_perm; + + if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP) + *u_g_id_p = entry->ae_id; + + return 0; +} + +SMB_ACL_T sys_acl_init(int count) +{ + SMB_ACL_T a; + + if (count < 0) { + errno = EINVAL; + return NULL; + } + + if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof a[0] + sizeof (struct acl))) == NULL) { + errno = ENOMEM; + return NULL; + } + + a->next = -1; + a->freeaclp = False; + a->aclp = (struct acl *)((char *)a + sizeof a[0]); + a->aclp->acl_cnt = 0; + + return a; +} + + +int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p) +{ + SMB_ACL_T acl_d; + SMB_ACL_ENTRY_T entry_d; + + if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) { + errno = EINVAL; + return -1; + } + + if (acl_d->aclp->acl_cnt >= ACL_MAX_ENTRIES) { + errno = ENOSPC; + return -1; + } + + entry_d = &acl_d->aclp->acl_entry[acl_d->aclp->acl_cnt++]; + entry_d->ae_tag = 0; + entry_d->ae_id = 0; + entry_d->ae_perm = 0; + *entry_p = entry_d; + + return 0; +} + +int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id) +{ + entry->ae_tag = tag_type; + + if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP) + entry->ae_id = u_g_id; + + entry->ae_perm = bits; + + return 0; +} + +int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry_d, uint32 bits) +{ + entry_d->ae_perm = bits; + + return 0; +} + +int sys_acl_valid(SMB_ACL_T acl_d) +{ + return acl_valid(acl_d->aclp); +} + +int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d) +{ + return acl_set_file(name, type, acl_d->aclp); +} + +#if 0 +int sys_acl_set_fd(int fd, SMB_ACL_T acl_d) +{ + return acl_set_fd(fd, acl_d->aclp); +} +#endif + +int sys_acl_delete_def_file(const char *name) +{ + return acl_delete_def_file(name); +} + +int sys_acl_free_acl(SMB_ACL_T acl_d) +{ + if (acl_d->freeaclp) { + acl_free(acl_d->aclp); + } + acl_free(acl_d); + return 0; +} + +#elif defined(HAVE_AIX_ACLS) /*----------------------------------------------*/ + +/* Donated by Medha Date, mdate@austin.ibm.com, for IBM */ + +int sys_acl_get_entry(SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p) +{ + struct acl_entry_link *link; + int keep_going; + + if (entry_id == SMB_ACL_FIRST_ENTRY) + theacl->count = 0; + else if (entry_id != SMB_ACL_NEXT_ENTRY) { + errno = EINVAL; + return -1; + } + + DEBUG(10, ("This is the count: %d\n", theacl->count)); + + /* Check if count was previously set to -1. * + * If it was, that means we reached the end * + * of the acl last time. */ + if (theacl->count == -1) + return 0; + + link = theacl; + /* To get to the next acl, traverse linked list until index * + * of acl matches the count we are keeping. This count is * + * incremented each time we return an acl entry. */ + + for (keep_going = 0; keep_going < theacl->count; keep_going++) + link = link->nextp; + + *entry_p = link->entryp; + +#if 0 + { + struct new_acl_entry *entry = *entry_p; + DEBUG(10, ("*entry_p is %lx\n", (long)entry)); + DEBUG(10, ("*entry_p->ace_access is %d\n", entry->ace_access)); + } +#endif + + /* Increment count */ + theacl->count++; + if (link->nextp == NULL) + theacl->count = -1; + + return 1; +} + +int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p) +{ + /* Initialize tag type */ + + *tag_type_p = -1; + DEBUG(10, ("the tagtype is %d\n", entry_d->ace_id->id_type)); + + /* Depending on what type of entry we have, * + * return tag type. */ + switch (entry_d->ace_id->id_type) { + case ACEID_USER: + *tag_type_p = SMB_ACL_USER; + break; + case ACEID_GROUP: + *tag_type_p = SMB_ACL_GROUP; + break; + + case SMB_ACL_USER_OBJ: + case SMB_ACL_GROUP_OBJ: + case SMB_ACL_OTHER: + *tag_type_p = entry_d->ace_id->id_type; + break; + + default: + return -1; + } + + return 0; +} + +SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type) +{ + struct acl *file_acl = (struct acl *)NULL; + struct acl_entry *acl_entry; + struct new_acl_entry *new_acl_entry; + struct ace_id *idp; + struct acl_entry_link *acl_entry_link; + struct acl_entry_link *acl_entry_link_head; + int i; + int rc = 0; + + /* AIX has no DEFAULT */ + if (type == SMB_ACL_TYPE_DEFAULT) { +#ifdef ENOTSUP + errno = ENOTSUP; +#else + errno = ENOSYS; +#endif + return NULL; + } + + /* Get the acl using statacl */ + + DEBUG(10, ("Entering sys_acl_get_file\n")); + DEBUG(10, ("path_p is %s\n", path_p)); + + file_acl = (struct acl *)SMB_MALLOC(BUFSIZ); + + if (file_acl == NULL) { + errno=ENOMEM; + DEBUG(0, ("Error in AIX sys_acl_get_file: %d\n", errno)); + return NULL; + } + + memset(file_acl, 0, BUFSIZ); + + rc = statacl((char *)path_p, 0, file_acl, BUFSIZ); + if (rc == -1) { + DEBUG(0, ("statacl returned %d with errno %d\n", rc, errno)); + SAFE_FREE(file_acl); + return NULL; + } + + DEBUG(10, ("Got facl and returned it\n")); + + /* Point to the first acl entry in the acl */ + acl_entry = file_acl->acl_ext; + + /* Begin setting up the head of the linked list * + * that will be used for the storing the acl * + * in a way that is useful for the posix_acls.c * + * code. */ + + acl_entry_link_head = acl_entry_link = sys_acl_init(0); + if (acl_entry_link_head == NULL) + return NULL; + + acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry); + if (acl_entry_link->entryp == NULL) { + SAFE_FREE(file_acl); + errno = ENOMEM; + DEBUG(0, ("Error in AIX sys_acl_get_file is %d\n", errno)); + return NULL; + } + + DEBUG(10, ("acl_entry is %d\n", acl_entry)); + DEBUG(10, ("acl_last(file_acl) id %d\n", acl_last(file_acl))); + + /* Check if the extended acl bit is on. * + * If it isn't, do not show the * + * contents of the acl since AIX intends * + * the extended info to remain unused */ + + if (file_acl->acl_mode & S_IXACL){ + /* while we are not pointing to the very end */ + while (acl_entry < acl_last(file_acl)) { + /* before we malloc anything, make sure this is */ + /* a valid acl entry and one that we want to map */ + idp = id_nxt(acl_entry->ace_id); + if ((acl_entry->ace_type == ACC_SPECIFY || acl_entry->ace_type == ACC_PERMIT) + && idp != id_last(acl_entry)) { + acl_entry = acl_nxt(acl_entry); + continue; + } + + idp = acl_entry->ace_id; + + /* Check if this is the first entry in the linked list. * + * The first entry needs to keep prevp pointing to NULL * + * and already has entryp allocated. */ + + if (acl_entry_link_head->count != 0) { + acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link); + + if (acl_entry_link->nextp == NULL) { + SAFE_FREE(file_acl); + errno = ENOMEM; + DEBUG(0, ("Error in AIX sys_acl_get_file is %d\n", errno)); + return NULL; + } + + acl_entry_link->nextp->prevp = acl_entry_link; + acl_entry_link = acl_entry_link->nextp; + acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry); + if (acl_entry_link->entryp == NULL) { + SAFE_FREE(file_acl); + errno = ENOMEM; + DEBUG(0, ("Error in AIX sys_acl_get_file is %d\n", errno)); + return NULL; + } + acl_entry_link->nextp = NULL; + } + + acl_entry_link->entryp->ace_len = acl_entry->ace_len; + + /* Don't really need this since all types are going * + * to be specified but, it's better than leaving it 0 */ + + acl_entry_link->entryp->ace_type = acl_entry->ace_type; + + acl_entry_link->entryp->ace_access = acl_entry->ace_access; + + memcpy(acl_entry_link->entryp->ace_id, idp, sizeof (struct ace_id)); + + /* The access in the acl entries must be left shifted by * + * three bites, because they will ultimately be compared * + * to S_IRUSR, S_IWUSR, and S_IXUSR. */ + + switch (acl_entry->ace_type){ + case ACC_PERMIT: + case ACC_SPECIFY: + acl_entry_link->entryp->ace_access = acl_entry->ace_access; + acl_entry_link->entryp->ace_access <<= 6; + acl_entry_link_head->count++; + break; + case ACC_DENY: + /* Since there is no way to return a DENY acl entry * + * change to PERMIT and then shift. */ + DEBUG(10, ("acl_entry->ace_access is %d\n", acl_entry->ace_access)); + acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7; + DEBUG(10, ("acl_entry_link->entryp->ace_access is %d\n", acl_entry_link->entryp->ace_access)); + acl_entry_link->entryp->ace_access <<= 6; + acl_entry_link_head->count++; + break; + default: + return 0; + } + + DEBUG(10, ("acl_entry = %d\n", acl_entry)); + DEBUG(10, ("The ace_type is %d\n", acl_entry->ace_type)); + + acl_entry = acl_nxt(acl_entry); + } + } /* end of if enabled */ + + /* Since owner, group, other acl entries are not * + * part of the acl entries in an acl, they must * + * be dummied up to become part of the list. */ + + for (i = 1; i < 4; i++) { + DEBUG(10, ("i is %d\n", i)); + if (acl_entry_link_head->count != 0) { + acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link); + if (acl_entry_link->nextp == NULL) { + SAFE_FREE(file_acl); + errno = ENOMEM; + DEBUG(0, ("Error in AIX sys_acl_get_file is %d\n", errno)); + return NULL; + } + + acl_entry_link->nextp->prevp = acl_entry_link; + acl_entry_link = acl_entry_link->nextp; + acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry); + if (acl_entry_link->entryp == NULL) { + SAFE_FREE(file_acl); + errno = ENOMEM; + DEBUG(0, ("Error in AIX sys_acl_get_file is %d\n", errno)); + return NULL; + } + } + + acl_entry_link->nextp = NULL; + + new_acl_entry = acl_entry_link->entryp; + idp = new_acl_entry->ace_id; + + new_acl_entry->ace_len = sizeof (struct acl_entry); + new_acl_entry->ace_type = ACC_PERMIT; + idp->id_len = sizeof (struct ace_id); + DEBUG(10, ("idp->id_len = %d\n", idp->id_len)); + memset(idp->id_data, 0, sizeof (uid_t)); + + switch (i) { + case 2: + new_acl_entry->ace_access = file_acl->g_access << 6; + idp->id_type = SMB_ACL_GROUP_OBJ; + break; + + case 3: + new_acl_entry->ace_access = file_acl->o_access << 6; + idp->id_type = SMB_ACL_OTHER; + break; + + case 1: + new_acl_entry->ace_access = file_acl->u_access << 6; + idp->id_type = SMB_ACL_USER_OBJ; + break; + + default: + return NULL; + + } + + acl_entry_link_head->count++; + DEBUG(10, ("new_acl_entry->ace_access = %d\n", new_acl_entry->ace_access)); + } + + acl_entry_link_head->count = 0; + SAFE_FREE(file_acl); + + return acl_entry_link_head; +} + +#if 0 +SMB_ACL_T sys_acl_get_fd(int fd) +{ + struct acl *file_acl = (struct acl *)NULL; + struct acl_entry *acl_entry; + struct new_acl_entry *new_acl_entry; + struct ace_id *idp; + struct acl_entry_link *acl_entry_link; + struct acl_entry_link *acl_entry_link_head; + int i; + int rc = 0; + + /* Get the acl using fstatacl */ + + DEBUG(10, ("Entering sys_acl_get_fd\n")); + DEBUG(10, ("fd is %d\n", fd)); + file_acl = (struct acl *)SMB_MALLOC(BUFSIZ); + + if (file_acl == NULL) { + errno=ENOMEM; + DEBUG(0, ("Error in sys_acl_get_fd is %d\n", errno)); + return NULL; + } + + memset(file_acl, 0, BUFSIZ); + + rc = fstatacl(fd, 0, file_acl, BUFSIZ); + if (rc == -1) { + DEBUG(0, ("The fstatacl call returned %d with errno %d\n", rc, errno)); + SAFE_FREE(file_acl); + return NULL; + } + + DEBUG(10, ("Got facl and returned it\n")); + + /* Point to the first acl entry in the acl */ + + acl_entry = file_acl->acl_ext; + /* Begin setting up the head of the linked list * + * that will be used for the storing the acl * + * in a way that is useful for the posix_acls.c * + * code. */ + + acl_entry_link_head = acl_entry_link = sys_acl_init(0); + if (acl_entry_link_head == NULL){ + SAFE_FREE(file_acl); + return NULL; + } + + acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry); + + if (acl_entry_link->entryp == NULL) { + errno = ENOMEM; + DEBUG(0, ("Error in sys_acl_get_fd is %d\n", errno)); + SAFE_FREE(file_acl); + return NULL; + } + + DEBUG(10, ("acl_entry is %d\n", acl_entry)); + DEBUG(10, ("acl_last(file_acl) id %d\n", acl_last(file_acl))); + + /* Check if the extended acl bit is on. * + * If it isn't, do not show the * + * contents of the acl since AIX intends * + * the extended info to remain unused */ + + if (file_acl->acl_mode & S_IXACL){ + /* while we are not pointing to the very end */ + while (acl_entry < acl_last(file_acl)) { + /* before we malloc anything, make sure this is */ + /* a valid acl entry and one that we want to map */ + + idp = id_nxt(acl_entry->ace_id); + if ((acl_entry->ace_type == ACC_SPECIFY || + (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) { + acl_entry = acl_nxt(acl_entry); + continue; + } + + idp = acl_entry->ace_id; + + /* Check if this is the first entry in the linked list. * + * The first entry needs to keep prevp pointing to NULL * + * and already has entryp allocated. */ + + if (acl_entry_link_head->count != 0) { + acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link); + if (acl_entry_link->nextp == NULL) { + errno = ENOMEM; + DEBUG(0, ("Error in sys_acl_get_fd is %d\n", errno)); + SAFE_FREE(file_acl); + return NULL; + } + acl_entry_link->nextp->prevp = acl_entry_link; + acl_entry_link = acl_entry_link->nextp; + acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry); + if (acl_entry_link->entryp == NULL) { + errno = ENOMEM; + DEBUG(0, ("Error in sys_acl_get_fd is %d\n", errno)); + SAFE_FREE(file_acl); + return NULL; + } + + acl_entry_link->nextp = NULL; + } + + acl_entry_link->entryp->ace_len = acl_entry->ace_len; + + /* Don't really need this since all types are going * + * to be specified but, it's better than leaving it 0 */ + + acl_entry_link->entryp->ace_type = acl_entry->ace_type; + acl_entry_link->entryp->ace_access = acl_entry->ace_access; + + memcpy(acl_entry_link->entryp->ace_id, idp, sizeof (struct ace_id)); + + /* The access in the acl entries must be left shifted by * + * three bites, because they will ultimately be compared * + * to S_IRUSR, S_IWUSR, and S_IXUSR. */ + + switch (acl_entry->ace_type){ + case ACC_PERMIT: + case ACC_SPECIFY: + acl_entry_link->entryp->ace_access = acl_entry->ace_access; + acl_entry_link->entryp->ace_access <<= 6; + acl_entry_link_head->count++; + break; + case ACC_DENY: + /* Since there is no way to return a DENY acl entry * + * change to PERMIT and then shift. */ + DEBUG(10, ("acl_entry->ace_access is %d\n", acl_entry->ace_access)); + acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7; + DEBUG(10, ("acl_entry_link->entryp->ace_access is %d\n", acl_entry_link->entryp->ace_access)); + acl_entry_link->entryp->ace_access <<= 6; + acl_entry_link_head->count++; + break; + default: + return 0; + } + + DEBUG(10, ("acl_entry = %d\n", acl_entry)); + DEBUG(10, ("The ace_type is %d\n", acl_entry->ace_type)); + + acl_entry = acl_nxt(acl_entry); + } + } /* end of if enabled */ + + /* Since owner, group, other acl entries are not * + * part of the acl entries in an acl, they must * + * be dummied up to become part of the list. */ + + for (i = 1; i < 4; i++) { + DEBUG(10, ("i is %d\n", i)); + if (acl_entry_link_head->count != 0){ + acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link); + if (acl_entry_link->nextp == NULL) { + errno = ENOMEM; + DEBUG(0, ("Error in sys_acl_get_fd is %d\n", errno)); + SAFE_FREE(file_acl); + return NULL; + } + + acl_entry_link->nextp->prevp = acl_entry_link; + acl_entry_link = acl_entry_link->nextp; + acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry); + + if (acl_entry_link->entryp == NULL) { + SAFE_FREE(file_acl); + errno = ENOMEM; + DEBUG(0, ("Error in sys_acl_get_fd is %d\n", errno)); + return NULL; + } + } + + acl_entry_link->nextp = NULL; + + new_acl_entry = acl_entry_link->entryp; + idp = new_acl_entry->ace_id; + + new_acl_entry->ace_len = sizeof (struct acl_entry); + new_acl_entry->ace_type = ACC_PERMIT; + idp->id_len = sizeof (struct ace_id); + DEBUG(10, ("idp->id_len = %d\n", idp->id_len)); + memset(idp->id_data, 0, sizeof (uid_t)); + + switch (i) { + case 2: + new_acl_entry->ace_access = file_acl->g_access << 6; + idp->id_type = SMB_ACL_GROUP_OBJ; + break; + + case 3: + new_acl_entry->ace_access = file_acl->o_access << 6; + idp->id_type = SMB_ACL_OTHER; + break; + + case 1: + new_acl_entry->ace_access = file_acl->u_access << 6; + idp->id_type = SMB_ACL_USER_OBJ; + break; + + default: + return NULL; + } + + acl_entry_link_head->count++; + DEBUG(10, ("new_acl_entry->ace_access = %d\n", new_acl_entry->ace_access)); + } + + acl_entry_link_head->count = 0; + SAFE_FREE(file_acl); + + return acl_entry_link_head; +} +#endif + +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) +{ + uint *permset; + + if (sys_acl_get_tag_type(entry, tag_type_p) != 0) + return -1; + + if (*tag_type_p == SMB_ACL_USER || *tag_type_p == SMB_ACL_GROUP) + memcpy(u_g_id_p, entry->ace_id->id_data, sizeof (id_t)); + + permset = &entry->ace_access; + + DEBUG(10, ("*permset is %d\n", *permset)); + *bits_p = (*permset & S_IRUSR ? 4 : 0) + | (*permset & S_IWUSR ? 2 : 0) + | (*permset & S_IXUSR ? 1 : 0); + + return 0; +} + +SMB_ACL_T sys_acl_init(int count) +{ + struct acl_entry_link *theacl = NULL; + + if (count < 0) { + errno = EINVAL; + return NULL; + } + + DEBUG(10, ("Entering sys_acl_init\n")); + + theacl = SMB_MALLOC_P(struct acl_entry_link); + if (theacl == NULL) { + errno = ENOMEM; + DEBUG(0, ("Error in sys_acl_init is %d\n", errno)); + return NULL; + } + + theacl->count = 0; + theacl->nextp = NULL; + theacl->prevp = NULL; + theacl->entryp = NULL; + DEBUG(10, ("Exiting sys_acl_init\n")); + return theacl; +} + +int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry) +{ + struct acl_entry_link *theacl; + struct acl_entry_link *acl_entryp; + struct acl_entry_link *temp_entry = NULL; + int counting; + + DEBUG(10, ("Entering the sys_acl_create_entry\n")); + + theacl = acl_entryp = *pacl; + + /* Get to the end of the acl before adding entry */ + + for (counting = 0; counting < theacl->count; counting++){ + DEBUG(10, ("The acl_entryp is %d\n", acl_entryp)); + temp_entry = acl_entryp; + acl_entryp = acl_entryp->nextp; + } + + if (theacl->count != 0){ + temp_entry->nextp = acl_entryp = SMB_MALLOC_P(struct acl_entry_link); + if (acl_entryp == NULL) { + errno = ENOMEM; + DEBUG(0, ("Error in sys_acl_create_entry is %d\n", errno)); + return -1; + } + + DEBUG(10, ("The acl_entryp is %d\n", acl_entryp)); + acl_entryp->prevp = temp_entry; + DEBUG(10, ("The acl_entryp->prevp is %d\n", acl_entryp->prevp)); + } + + *pentry = acl_entryp->entryp = SMB_MALLOC_P(struct new_acl_entry); + if (*pentry == NULL) { + errno = ENOMEM; + DEBUG(0, ("Error in sys_acl_create_entry is %d\n", errno)); + return -1; + } + + memset(*pentry, 0, sizeof (struct new_acl_entry)); + acl_entryp->entryp->ace_len = sizeof (struct acl_entry); + acl_entryp->entryp->ace_type = ACC_PERMIT; + acl_entryp->entryp->ace_id->id_len = sizeof (struct ace_id); + acl_entryp->nextp = NULL; + theacl->count++; + DEBUG(10, ("Exiting sys_acl_create_entry\n")); + return 0; +} + +int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id) +{ + entry->ace_id->id_type = tag_type; + DEBUG(10, ("The tag type is %d\n", entry->ace_id->id_type)); + + if (tag_type == SMB_ACL_USER || tag_type == SMB_ACL_GROUP) + memcpy(entry->ace_id->id_data, &u_g_id, sizeof (id_t)); + + entry->ace_access = bits; + DEBUG(10, ("entry->ace_access = %d\n", entry->ace_access)); + + return 0; +} + +int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits) +{ + DEBUG(10, ("Starting AIX sys_acl_set_permset\n")); + entry->ace_access = bits; + DEBUG(10, ("entry->ace_access = %d\n", entry->ace_access)); + DEBUG(10, ("Ending AIX sys_acl_set_permset\n")); + return 0; +} + +int sys_acl_valid(SMB_ACL_T theacl) +{ + int user_obj = 0; + int group_obj = 0; + int other_obj = 0; + struct acl_entry_link *acl_entry; + + for (acl_entry=theacl; acl_entry != NULL; acl_entry = acl_entry->nextp) { + user_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_USER_OBJ); + group_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_GROUP_OBJ); + other_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_OTHER); + } + + DEBUG(10, ("user_obj=%d, group_obj=%d, other_obj=%d\n", user_obj, group_obj, other_obj)); + + if (user_obj != 1 || group_obj != 1 || other_obj != 1) + return -1; + + return 0; +} + +int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) +{ + struct acl_entry_link *acl_entry_link = NULL; + struct acl *file_acl = NULL; + struct acl *file_acl_temp = NULL; + struct acl_entry *acl_entry = NULL; + struct ace_id *ace_id = NULL; + uint id_type; + uint user_id; + uint acl_length; + uint rc; + + DEBUG(10, ("Entering sys_acl_set_file\n")); + DEBUG(10, ("File name is %s\n", name)); + + /* AIX has no default ACL */ + if (acltype == SMB_ACL_TYPE_DEFAULT) + return 0; + + acl_length = BUFSIZ; + file_acl = (struct acl *)SMB_MALLOC(BUFSIZ); + + if (file_acl == NULL) { + errno = ENOMEM; + DEBUG(0, ("Error in sys_acl_set_file is %d\n", errno)); + return -1; + } + + memset(file_acl, 0, BUFSIZ); + + file_acl->acl_len = ACL_SIZ; + file_acl->acl_mode = S_IXACL; + + for (acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) { + acl_entry_link->entryp->ace_access >>= 6; + id_type = acl_entry_link->entryp->ace_id->id_type; + + switch (id_type) { + case SMB_ACL_USER_OBJ: + file_acl->u_access = acl_entry_link->entryp->ace_access; + continue; + case SMB_ACL_GROUP_OBJ: + file_acl->g_access = acl_entry_link->entryp->ace_access; + continue; + case SMB_ACL_OTHER: + file_acl->o_access = acl_entry_link->entryp->ace_access; + continue; + case SMB_ACL_MASK: + continue; + } + + if ((file_acl->acl_len + sizeof (struct acl_entry)) > acl_length) { + acl_length += sizeof (struct acl_entry); + file_acl_temp = (struct acl *)SMB_MALLOC(acl_length); + if (file_acl_temp == NULL) { + SAFE_FREE(file_acl); + errno = ENOMEM; + DEBUG(0, ("Error in sys_acl_set_file is %d\n", errno)); + return -1; + } + + memcpy(file_acl_temp, file_acl, file_acl->acl_len); + SAFE_FREE(file_acl); + file_acl = file_acl_temp; + } + + acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len); + file_acl->acl_len += sizeof (struct acl_entry); + acl_entry->ace_len = acl_entry_link->entryp->ace_len; + acl_entry->ace_access = acl_entry_link->entryp->ace_access; + + /* In order to use this, we'll need to wait until we can get denies */ + /* if (!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT) + acl_entry->ace_type = ACC_SPECIFY; */ + + acl_entry->ace_type = ACC_SPECIFY; + + ace_id = acl_entry->ace_id; + + ace_id->id_type = acl_entry_link->entryp->ace_id->id_type; + DEBUG(10, ("The id type is %d\n", ace_id->id_type)); + ace_id->id_len = acl_entry_link->entryp->ace_id->id_len; + memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof (uid_t)); + memcpy(acl_entry->ace_id->id_data, &user_id, sizeof (uid_t)); + } + + rc = chacl((char*)name, file_acl, file_acl->acl_len); + DEBUG(10, ("errno is %d\n", errno)); + DEBUG(10, ("return code is %d\n", rc)); + SAFE_FREE(file_acl); + DEBUG(10, ("Exiting the sys_acl_set_file\n")); + return rc; +} + +#if 0 +int sys_acl_set_fd(int fd, SMB_ACL_T theacl) +{ + struct acl_entry_link *acl_entry_link = NULL; + struct acl *file_acl = NULL; + struct acl *file_acl_temp = NULL; + struct acl_entry *acl_entry = NULL; + struct ace_id *ace_id = NULL; + uint id_type; + uint user_id; + uint acl_length; + uint rc; + + DEBUG(10, ("Entering sys_acl_set_fd\n")); + acl_length = BUFSIZ; + file_acl = (struct acl *)SMB_MALLOC(BUFSIZ); + + if (file_acl == NULL) { + errno = ENOMEM; + DEBUG(0, ("Error in sys_acl_set_fd is %d\n", errno)); + return -1; + } + + memset(file_acl, 0, BUFSIZ); + + file_acl->acl_len = ACL_SIZ; + file_acl->acl_mode = S_IXACL; + + for (acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) { + acl_entry_link->entryp->ace_access >>= 6; + id_type = acl_entry_link->entryp->ace_id->id_type; + DEBUG(10, ("The id_type is %d\n", id_type)); + + switch (id_type) { + case SMB_ACL_USER_OBJ: + file_acl->u_access = acl_entry_link->entryp->ace_access; + continue; + case SMB_ACL_GROUP_OBJ: + file_acl->g_access = acl_entry_link->entryp->ace_access; + continue; + case SMB_ACL_OTHER: + file_acl->o_access = acl_entry_link->entryp->ace_access; + continue; + case SMB_ACL_MASK: + continue; + } + + if ((file_acl->acl_len + sizeof (struct acl_entry)) > acl_length) { + acl_length += sizeof (struct acl_entry); + file_acl_temp = (struct acl *)SMB_MALLOC(acl_length); + if (file_acl_temp == NULL) { + SAFE_FREE(file_acl); + errno = ENOMEM; + DEBUG(0, ("Error in sys_acl_set_fd is %d\n", errno)); + return -1; + } + + memcpy(file_acl_temp, file_acl, file_acl->acl_len); + SAFE_FREE(file_acl); + file_acl = file_acl_temp; + } + + acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len); + file_acl->acl_len += sizeof (struct acl_entry); + acl_entry->ace_len = acl_entry_link->entryp->ace_len; + acl_entry->ace_access = acl_entry_link->entryp->ace_access; + + /* In order to use this, we'll need to wait until we can get denies */ + /* if (!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT) + acl_entry->ace_type = ACC_SPECIFY; */ + + acl_entry->ace_type = ACC_SPECIFY; + + ace_id = acl_entry->ace_id; + + ace_id->id_type = acl_entry_link->entryp->ace_id->id_type; + DEBUG(10, ("The id type is %d\n", ace_id->id_type)); + ace_id->id_len = acl_entry_link->entryp->ace_id->id_len; + memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof (uid_t)); + memcpy(ace_id->id_data, &user_id, sizeof (uid_t)); + } + + rc = fchacl(fd, file_acl, file_acl->acl_len); + DEBUG(10, ("errno is %d\n", errno)); + DEBUG(10, ("return code is %d\n", rc)); + SAFE_FREE(file_acl); + DEBUG(10, ("Exiting sys_acl_set_fd\n")); + return rc; +} +#endif + +int sys_acl_delete_def_file(UNUSED(const char *name)) +{ + /* AIX has no default ACL */ + return 0; +} + +int sys_acl_free_acl(SMB_ACL_T posix_acl) +{ + struct acl_entry_link *acl_entry_link; + + for (acl_entry_link = posix_acl->nextp; acl_entry_link->nextp != NULL; acl_entry_link = acl_entry_link->nextp) { + SAFE_FREE(acl_entry_link->prevp->entryp); + SAFE_FREE(acl_entry_link->prevp); + } + + SAFE_FREE(acl_entry_link->prevp->entryp); + SAFE_FREE(acl_entry_link->prevp); + SAFE_FREE(acl_entry_link->entryp); + SAFE_FREE(acl_entry_link); + + return 0; +} + +#elif defined(HAVE_OSX_ACLS) /*----------------------------------------------*/ + +#define OSX_BROKEN_GETENTRY /* returns 0 instead of 1 */ + +#include <membership.h> + +int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p) +{ + int ret = acl_get_entry(the_acl, entry_id, entry_p); +#ifdef OSX_BROKEN_GETENTRY + if (ret == 0) + ret = 1; + else if (ret == -1 && errno == 22) + ret = 0; +#endif + return ret; +} + +SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type) +{ + if (type == ACL_TYPE_DEFAULT) { + errno = ENOTSUP; + return NULL; + } + errno = 0; + return acl_get_file(path_p, type); +} + +#if 0 +SMB_ACL_T sys_acl_get_fd(int fd) +{ + return acl_get_fd(fd); +} +#endif + +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) +{ + uuid_t *uup; + acl_tag_t tag; + acl_flagset_t flagset; + acl_permset_t permset; + uint32 bits, fb, bb, pb; + int id_type = -1; + int rc; + + if (acl_get_tag_type(entry, &tag) != 0 + || acl_get_flagset_np(entry, &flagset) != 0 + || acl_get_permset(entry, &permset) != 0 + || (uup = acl_get_qualifier(entry)) == NULL) + return -1; + + rc = mbr_uuid_to_id(*uup, u_g_id_p, &id_type); + acl_free(uup); + if (rc != 0) + return rc; + + if (id_type == ID_TYPE_UID) + *tag_type_p = SMB_ACL_USER; + else + *tag_type_p = SMB_ACL_GROUP; + + bits = tag == ACL_EXTENDED_ALLOW ? 1 : 0; + + for (fb = (1u<<4), bb = (1u<<1); bb < (1u<<12); fb *= 2, bb *= 2) { + if (acl_get_flag_np(flagset, fb) == 1) + bits |= bb; + } + + for (pb = (1u<<1), bb = (1u<<12); bb < (1u<<25); pb *= 2, bb *= 2) { + if (acl_get_perm_np(permset, pb) == 1) + bits |= bb; + } + + *bits_p = bits; + + return 0; +} + +SMB_ACL_T sys_acl_init(int count) +{ + return acl_init(count); +} + +int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry) +{ + return acl_create_entry(pacl, pentry); +} + +int sys_acl_set_info(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tag_type, uint32 bits, id_t u_g_id) +{ + acl_flagset_t flagset; + acl_permset_t permset; + uint32 fb, bb, pb; + int is_user = tag_type == SMB_ACL_USER; + uuid_t uu; + int rc; + + tag_type = bits & 1 ? ACL_EXTENDED_ALLOW : ACL_EXTENDED_DENY; + + if (acl_get_flagset_np(entry, &flagset) != 0 + || acl_get_permset(entry, &permset) != 0) + return -1; + + acl_clear_flags_np(flagset); + acl_clear_perms(permset); + + for (fb = (1u<<4), bb = (1u<<1); bb < (1u<<12); fb *= 2, bb *= 2) { + if (bits & bb) + acl_add_flag_np(flagset, fb); + } + + for (pb = (1u<<1), bb = (1u<<12); bb < (1u<<25); pb *= 2, bb *= 2) { + if (bits & bb) + acl_add_perm(permset, pb); + } + + if (is_user) + rc = mbr_uid_to_uuid(u_g_id, uu); + else + rc = mbr_gid_to_uuid(u_g_id, uu); + if (rc != 0) + return rc; + + if (acl_set_tag_type(entry, tag_type) != 0 + || acl_set_qualifier(entry, &uu) != 0 + || acl_set_permset(entry, permset) != 0 + || acl_set_flagset_np(entry, flagset) != 0) + return -1; + + return 0; +} + +#if 0 +int sys_acl_set_access_bits(SMB_ACL_ENTRY_T entry, uint32 bits) +{ + return -1; /* Not needed for OS X. */ +} +#endif + +int sys_acl_valid(SMB_ACL_T theacl) +{ + return acl_valid(theacl); +} + +int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) +{ + return acl_set_file(name, acltype, theacl); +} + +#if 0 +int sys_acl_set_fd(int fd, SMB_ACL_T theacl) +{ + return acl_set_fd(fd, theacl); +} +#endif + +int sys_acl_delete_def_file(const char *name) +{ + return acl_delete_def_file(name); +} + +int sys_acl_free_acl(SMB_ACL_T the_acl) +{ + return acl_free(the_acl); +} + +#else /* No ACLs. */ + +#error No ACL functions defined for this platform! + +#endif + +/************************************************************************ + Deliberately outside the ACL defines. Return 1 if this is a "no acls" + errno, 0 if not. +************************************************************************/ + +int no_acl_syscall_error(int err) +{ +#ifdef HAVE_OSX_ACLS + if (err == ENOENT) + return 1; /* Weird problem with directory ACLs. */ +#endif +#if defined(ENOSYS) + if (err == ENOSYS) { + return 1; + } +#endif +#if defined(ENOTSUP) + if (err == ENOTSUP) { + return 1; + } +#endif + if (err == EINVAL) { + /* If the type of SMB_ACL_TYPE_ACCESS or SMB_ACL_TYPE_DEFAULT + * isn't valid, then the ACLs must be non-POSIX. */ + return 1; + } + return 0; +} + +#endif /* SUPPORT_ACLS */ |