From 45646e88188b5d175f7755bc64f186cd59ed4c80 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 5 Apr 2001 20:52:02 +0000 Subject: Fix from Michael Davidson to merge Solaris and UnixWare ACLs. Jeremy. (This used to be commit ffa800e980bfed3d82ec7b0a037085c4558f8f0f) --- source3/include/smb_acls.h | 51 +--- source3/lib/smbrun.c | 1 - source3/lib/sysacls.c | 623 +++++---------------------------------------- 3 files changed, 64 insertions(+), 611 deletions(-) diff --git a/source3/include/smb_acls.h b/source3/include/smb_acls.h index 9de3a5b6a1..570b8eab8c 100644 --- a/source3/include/smb_acls.h +++ b/source3/include/smb_acls.h @@ -54,11 +54,10 @@ #define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS #define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT -#elif defined(HAVE_UNIXWARE_ACLS) - +#elif defined(HAVE_UNIXWARE_ACLS) || defined(HAVE_SOLARIS_ACLS) /* - * Donated by Michael Davidson for UnixWare. - * As this is generic SVR4.x code, it may also work for Solaris ! + * Donated by Michael Davidson for UnixWare / OpenUNIX. + * Modified by Toomas Soome for Solaris. */ /* SVR4.2 ES/MP ACLs */ @@ -66,9 +65,9 @@ typedef int SMB_ACL_TAG_T; typedef int SMB_ACL_TYPE_T; typedef ushort *SMB_ACL_PERMSET_T; typedef ushort SMB_ACL_PERM_T; -#define SMB_ACL_READ S_IRUSR -#define SMB_ACL_WRITE S_IWUSR -#define SMB_ACL_EXECUTE S_IXUSR +#define SMB_ACL_READ 4 +#define SMB_ACL_WRITE 2 +#define SMB_ACL_EXECUTE 1 /* Types of ACLs. */ #define SMB_ACL_USER USER @@ -93,44 +92,6 @@ typedef struct acl *SMB_ACL_ENTRY_T; #define SMB_ACL_TYPE_ACCESS 0 #define SMB_ACL_TYPE_DEFAULT 1 -#elif defined(HAVE_SOLARIS_ACLS) - -/* - * Code donated by Toomas Soome . - * Based on the implementation by Michael Davidson for UnixWare. - */ - -typedef int SMB_ACL_TAG_T; -typedef int SMB_ACL_TYPE_T; -typedef ushort *SMB_ACL_PERMSET_T; -typedef ushort SMB_ACL_PERM_T; -#define SMB_ACL_READ 4 -#define SMB_ACL_WRITE 2 -#define SMB_ACL_EXECUTE 1 - -/* Types of ACLs. */ -#define SMB_ACL_USER USER -#define SMB_ACL_USER_OBJ USER_OBJ -#define SMB_ACL_GROUP GROUP -#define SMB_ACL_GROUP_OBJ GROUP_OBJ -#define SMB_ACL_OTHER OTHER_OBJ -#define SMB_ACL_MASK CLASS_OBJ - -typedef struct SMB_ACL_T { - int size; - int count; - int next; - struct acl acl[1]; -} *SMB_ACL_T; - -typedef struct acl *SMB_ACL_ENTRY_T; - -#define SMB_ACL_FIRST_ENTRY 0 -#define SMB_ACL_NEXT_ENTRY 1 - -#define SMB_ACL_TYPE_ACCESS 0 -#define SMB_ACL_TYPE_DEFAULT 1 - #elif defined(HAVE_IRIX_ACLS) #define SMB_ACL_TAG_T acl_tag_t diff --git a/source3/lib/smbrun.c b/source3/lib/smbrun.c index 983c61f862..2b7d141834 100644 --- a/source3/lib/smbrun.c +++ b/source3/lib/smbrun.c @@ -33,7 +33,6 @@ the child as it may leave the caller in a privileged state. static BOOL setup_stdout_file(char *outfile,BOOL shared) { int fd; - SMB_STRUCT_STAT st; mode_t mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH; int flags = O_RDWR|O_CREAT|O_TRUNC|O_EXCL; diff --git a/source3/lib/sysacls.c b/source3/lib/sysacls.c index a01667ce36..b0ba2075ab 100644 --- a/source3/lib/sysacls.c +++ b/source3/lib/sysacls.c @@ -170,34 +170,38 @@ int sys_acl_free_acl(SMB_ACL_T the_acl) return acl_free(the_acl); } -#elif defined(HAVE_UNIXWARE_ACLS) +#elif defined(HAVE_UNIXWARE_ACLS) || defined(HAVE_SOLARIS_ACLS) /* - * Donated by Michael Davidson for UnixWare. - * As this is generic SVR4.x code, it may also work for Solaris ! + * Donated by Michael Davidson for UnixWare / OpenUNIX. + * Modified by Toomas Soome for Solaris. */ -#define INITIAL_ACL_SIZE 16 -#ifndef SETACL -#define SETACL ACL_SET -#endif +/* + * 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() + */ -#ifndef GETACL -#define GETACL ACL_GET -#endif +/* + * The only difference between Solaris and UnixWare / OpenUNIX is + * that the #defines for the ACL operations have different names + */ +#if defined(HAVE_UNIXWARE_ACLS) -#ifndef GETACLCNT +#define SETACL ACL_SET +#define GETACL ACL_GET #define GETACLCNT ACL_CNT -#endif -#ifndef HAVE__FACL -/* - * until official facl() support shows up in UW 7.1.2 - */ - int facl(int fd, int cmd, int nentries, struct acl *aclbufp) -{ - return syscall(188, fd, cmd, nentries, aclbufp); -} #endif @@ -256,6 +260,20 @@ void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d) return &entry_d->a_id; } +/* + * 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; @@ -273,6 +291,14 @@ SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type) 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) { @@ -475,561 +501,27 @@ char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p) } - perms[0] = (ap->a_perm & S_IRUSR) ? 'r' : '-'; - perms[1] = (ap->a_perm & S_IWUSR) ? 'w' : '-'; - perms[2] = (ap->a_perm & S_IXUSR) ? 'x' : '-'; + perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-'; + perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-'; + perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-'; perms[3] = '\0'; /* : : rwx \n \0 */ nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1; - if ((len + nbytes) > maxlen) { - /* - * allocate enough additional memory for this - * entry and an estimate of another 20 bytes - * for each entry still to be processed - */ - maxlen += nbytes + 20 * (acl_d->count - i); - - if ((text = realloc(text, maxlen)) == NULL) { - errno = ENOMEM; - return NULL; - } - } - - slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms); - len += nbytes - 1; - } - - if (len_p) - *len_p = len; - - return text; -} - -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 = malloc(sizeof(*a) + 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_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type) -{ - switch (tag_type) { - case SMB_ACL_USER: - case SMB_ACL_USER_OBJ: - case SMB_ACL_GROUP: - case SMB_ACL_GROUP_OBJ: - case SMB_ACL_OTHER: - case SMB_ACL_MASK: - entry_d->a_type = tag_type; - break; - default: - errno = EINVAL; - return -1; - } - - return 0; -} - -int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p) -{ - if (entry_d->a_type != SMB_ACL_GROUP - && entry_d->a_type != SMB_ACL_USER) { - errno = EINVAL; - return -1; - } - - entry_d->a_id = *((id_t *)qual_p); - - return 0; -} - -int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d) -{ - if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) { - return EINVAL; - } - - entry_d->a_perm = *permset_d; - - return 0; -} - -int sys_acl_valid(SMB_ACL_T acl_d) -{ - if (aclsort(acl_d->count, 0, acl_d->acl) != 0) { - errno = EINVAL; - return -1; - } - - return 0; -} - -int sys_acl_set_file(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 (stat(name, &s) != 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 (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 = malloc(acl_count * sizeof(acl_buf[0])); - - 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 + * If this entry would overflow the buffer + * allocate enough additional memory for this + * entry and an estimate of another 20 bytes + * for each entry still to be processed */ - 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; - } - - if (aclsort(acl_count, 0, acl_p) != 0) { - errno = EINVAL; - ret = -1; - } else { - ret = acl(name, SETACL, acl_count, acl_p); - } - - if (acl_buf) { - free(acl_buf); - } - - return ret; -} - -int sys_acl_set_fd(int fd, SMB_ACL_T acl_d) -{ - if (aclsort(acl_d->count, 0, acl_d->acl) != 0) { - errno = EINVAL; - return -1; - } + if ((len + nbytes) > maxlen) { + char *oldtext = text; - return facl(fd, SETACL, acl_d->count, &acl_d->acl[0]); -} - -int sys_acl_free_text(char *text) -{ - free(text); - return 0; -} - -int sys_acl_free_acl(SMB_ACL_T acl_d) -{ - free(acl_d); - return 0; -} - -#elif defined(HAVE_SOLARIS_ACLS) - -/* - * Code donated by Toomas Soome . - * Based on the implementation by Michael Davidson for UnixWare. - */ - -#define INITIAL_ACL_SIZE 16 - -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; -} - -int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p) -{ - *permset_p = &entry_d->a_perm; - - return 0; -} - -void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d) -{ - if (entry_d->a_type != SMB_ACL_USER - && entry_d->a_type != SMB_ACL_GROUP) { - errno = EINVAL; - return NULL; - } - - return &entry_d->a_id; -} - -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; - } - - while ((count = acl(path_p, GETACL, count, &acl_d->acl[0])) < 0 - && errno == ENOSPC) { - - if ((count = acl(path_p, GETACLCNT, 0, NULL)) < 0) { - return NULL; - } - - sys_acl_free_acl(acl_d); - - if ((acl_d = sys_acl_init(count)) == NULL) { - return NULL; - } - } - - if (count < 0) { - 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 preceed 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; -} - -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) { - - if ((count = facl(fd, GETACLCNT, 0, NULL)) < 0) { - return NULL; - } - - sys_acl_free_acl(acl_d); - - if ((acl_d = sys_acl_init(count)) == NULL) { - return NULL; - } - } - - if (count < 0) { - 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; -} - -int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d) -{ - *permset_d = 0; - - return 0; -} - -int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm) -{ - if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE - && perm != SMB_ACL_EXECUTE) { - errno = EINVAL; - return -1; - } - - if (permset_d == NULL) { - errno = EINVAL; - return -1; - } - - *permset_d |= perm; - - return 0; -} - -int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm) -{ - return *permset_d & perm; -} - -char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p) -{ - int i; - int len, maxlen; - char *text; - - /* - * use an initial estimate of 20 bytes per ACL entry - * when allocating memory for the text representation - * of the ACL - */ - len = 0; - maxlen = 20 * acl_d->count; - if ((text = malloc(maxlen)) == NULL) { - errno = ENOMEM; - return NULL; - } - - for (i = 0; i < acl_d->count; i++) { - struct acl *ap = &acl_d->acl[i]; - struct passwd *pw; - struct group *gr; - char tagbuf[12]; - char idbuf[12]; - char *tag; - char *id = ""; - char perms[4]; - int nbytes; - - switch (ap->a_type) { - /* - * for debugging purposes it's probably more - * useful to dump unknown tag types rather - * than just returning an error - */ - default: - slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x", - ap->a_type); - tag = tagbuf; - slprintf(idbuf, sizeof(idbuf)-1, "%ld", - (long)ap->a_id); - id = idbuf; - break; - - case SMB_ACL_USER: - if ((pw = sys_getpwuid(ap->a_id)) == NULL) { - slprintf(idbuf, sizeof(idbuf)-1, "%ld", - (long)ap->a_id); - id = idbuf; - } else { - id = pw->pw_name; - } - case SMB_ACL_USER_OBJ: - tag = "user"; - break; - - case SMB_ACL_GROUP: - if ((gr = getgrgid(ap->a_id)) == NULL) { - slprintf(idbuf, sizeof(idbuf)-1, "%ld", - (long)ap->a_id); - id = idbuf; - } else { - id = gr->gr_name; - } - case SMB_ACL_GROUP_OBJ: - tag = "group"; - break; - - case SMB_ACL_OTHER: - tag = "other"; - break; - - case SMB_ACL_MASK: - tag = "mask"; - break; - - } - - perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-'; - perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-'; - perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-'; - perms[3] = '\0'; - - /* : : rwx \n \0 */ - nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1; - - if ((len + nbytes) > maxlen) { - /* - * allocate enough additional memory for this - * entry and an estimate of another 20 bytes - * for each entry still to be processed - */ maxlen += nbytes + 20 * (acl_d->count - i); - if ((text = realloc(text, maxlen)) == NULL) { + if ((text = realloc(oldtext, maxlen)) == NULL) { + free(oldtext); errno = ENOMEM; return NULL; } @@ -1727,6 +1219,7 @@ int sys_acl_free_acl(SMB_ACL_T the_acl) return acl_free(the_acl); } +>>>>>>> 1.15 #else /* No ACLs. */ int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p) -- cgit