summaryrefslogtreecommitdiff
path: root/usr/src/lib/libsec/common/acltext.c
diff options
context:
space:
mode:
authorahrens <none@none>2005-10-31 11:33:35 -0800
committerahrens <none@none>2005-10-31 11:33:35 -0800
commitfa9e4066f08beec538e775443c5be79dd423fcab (patch)
tree576d99665e57bb7cb70584431adb08c14d47e3ce /usr/src/lib/libsec/common/acltext.c
parentf1b64740276f67fc6914c1d855f2af601efe99ac (diff)
downloadillumos-joyent-fa9e4066f08beec538e775443c5be79dd423fcab.tar.gz
PSARC 2002/240 ZFS
6338653 Integrate ZFS PSARC 2004/652 - DKIOCFLUSH 5096886 Write caching disks need mechanism to flush cache to physical media
Diffstat (limited to 'usr/src/lib/libsec/common/acltext.c')
-rw-r--r--usr/src/lib/libsec/common/acltext.c801
1 files changed, 757 insertions, 44 deletions
diff --git a/usr/src/lib/libsec/common/acltext.c b/usr/src/lib/libsec/common/acltext.c
index da3195379c..75b0dc7857 100644
--- a/usr/src/lib/libsec/common/acltext.c
+++ b/usr/src/lib/libsec/common/acltext.c
@@ -32,9 +32,15 @@
#include <string.h>
#include <limits.h>
#include <stdlib.h>
+#include <errno.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/acl.h>
+#include <aclutils.h>
+#include <libintl.h>
+
+
+extern acl_t *acl_alloc(enum acl_type);
/*
* acltotext() converts each ACL entry to look like this:
@@ -64,8 +70,21 @@ static char *strappend(char *, char *);
static char *convert_perm(char *, o_mode_t);
static int increase_length(struct dynaclstr *, size_t);
-#define FREE free(aclp);\
- free(allocp)
+static int
+acl_str_to_id(char *str, int *id)
+{
+ char *end;
+ uid_t value;
+
+ value = strtol(str, &end, 10);
+
+ if (errno != 0 || *end != '\0')
+ return (EACL_INVALID_USER_GROUP);
+
+ *id = value;
+
+ return (0);
+}
/*
* Convert internal acl representation to external representation.
@@ -213,8 +232,8 @@ acltotext(aclent_t *aclp, int aclcnt)
* The comma at the end is not prescribed by the man pages.
* But it is needed not to break the old programs.
*/
-aclent_t *
-aclfromtext(char *aclstr, int *aclcnt)
+static int
+aclent_aclfromtext(char *aclstr, acl_t **ret_aclp)
{
char *fieldp;
char *tp;
@@ -224,23 +243,29 @@ aclfromtext(char *aclstr, int *aclcnt)
int entry_type;
int id;
int len;
+ int error;
o_mode_t perm;
aclent_t *tmpaclp;
- aclent_t *aclp;
+ acl_t *aclp;
struct group *groupp;
struct passwd *passwdp;
- *aclcnt = 0;
aclp = NULL;
if (! aclstr)
return (NULL);
+ aclp = acl_alloc(ACLENT_T);
+ if (aclp == NULL) {
+ return (EACL_MEM_ERROR);
+ }
+
+ *ret_aclp = NULL;
+
len = strlen(aclstr);
if ((aclimport = allocp = strdup(aclstr)) == NULL) {
- fprintf(stderr, "malloc() failed\n");
- return (NULL);
+ return (EACL_MEM_ERROR);
}
if (aclimport[len - 1] == ',')
@@ -256,32 +281,33 @@ aclfromtext(char *aclstr, int *aclcnt)
nextp = tp + 1;
}
- *aclcnt += 1;
+ aclp->acl_cnt += 1;
/*
* get additional memory:
* can be more efficient by allocating a bigger block
* each time.
*/
- if (*aclcnt > 1)
- tmpaclp = (aclent_t *)realloc(aclp,
- sizeof (aclent_t) * (*aclcnt));
+ if (aclp->acl_cnt > 1)
+ tmpaclp = (aclent_t *)realloc(aclp->acl_aclp,
+ sizeof (aclent_t) * (aclp->acl_cnt));
else
tmpaclp = (aclent_t *)malloc(sizeof (aclent_t));
if (tmpaclp == NULL) {
free(allocp);
- if (aclp)
- free(aclp);
- return (NULL);
+ acl_free(aclp);
+ return (EACL_MEM_ERROR);
}
- aclp = tmpaclp;
- tmpaclp = aclp + (*aclcnt - 1);
+ aclp->acl_aclp = tmpaclp;
+ tmpaclp = (aclent_t *)aclp->acl_aclp + (aclp->acl_cnt - 1);
/* look for entry type field */
tp = strchr(aclimport, ':');
if (tp == NULL) {
- FREE;
- return (NULL);
+ free(allocp);
+ if (aclp)
+ acl_free(aclp);
+ return (EACL_ENTRY_ERROR);
} else
*tp = '\0';
if (strcmp(aclimport, "user") == 0) {
@@ -313,8 +339,9 @@ aclfromtext(char *aclstr, int *aclcnt)
else if (strcmp(aclimport, "defaultother") == 0)
entry_type = DEF_OTHER_OBJ;
else {
- FREE;
- return (NULL);
+ free(allocp);
+ acl_free(aclp);
+ return (EACL_ENTRY_ERROR);
}
/* look for user/group name */
@@ -324,8 +351,9 @@ aclfromtext(char *aclstr, int *aclcnt)
fieldp = tp + 1;
tp = strchr(fieldp, ':');
if (tp == NULL) {
- FREE;
- return (NULL);
+ free(allocp);
+ acl_free(aclp);
+ return (EACL_INVALID_USER_GROUP);
} else
*tp = '\0';
if (fieldp != tp) {
@@ -341,32 +369,37 @@ aclfromtext(char *aclstr, int *aclcnt)
* change. Use the friendlier interface
* getpwnam().
*/
+ error = 0;
passwdp = getpwnam(fieldp);
if (passwdp == NULL) {
- (void) fprintf(stderr,
- "user %s not found\n", fieldp);
- id = UID_NOBODY; /* nobody */
- }
- else
+ error = acl_str_to_id(fieldp,
+ &id);
+ } else {
id = passwdp->pw_uid;
+ }
+
+ if (error) {
+ free(allocp);
+ acl_free(aclp);
+ return (error);
+ }
+
} else {
+ error = 0;
if (entry_type == GROUP ||
entry_type == DEF_GROUP) {
groupp = getgrnam(fieldp);
if (groupp == NULL) {
- (void) fprintf(stderr,
- "group %s not found\n",
- fieldp);
- /* no group? */
- id = GID_NOBODY;
+ error = acl_str_to_id(
+ fieldp, &id);
}
- else
+ if (error == 0)
id = groupp->gr_gid;
- } else {
- (void) fprintf(stderr,
- "acl import errors\n");
- FREE;
- return (NULL);
+ }
+ if (error) {
+ free(allocp);
+ acl_free(aclp);
+ return (error);
}
}
} else {
@@ -390,8 +423,9 @@ aclfromtext(char *aclstr, int *aclcnt)
fieldp = tp + 1;
if (strlen(fieldp) != 3) {
/* not "rwx" format */
- FREE;
- return (NULL);
+ free(allocp);
+ acl_free(aclp);
+ return (EACL_PERM_MASK_ERROR);
} else {
char s[] = "rwx";
int mask = 0x04;
@@ -402,8 +436,9 @@ aclfromtext(char *aclstr, int *aclcnt)
if (fieldp[i] == s[i])
perm |= mask;
else if (fieldp[i] != '-') {
- FREE;
- return (NULL);
+ free(allocp);
+ acl_free(aclp);
+ return (EACL_PERM_MASK_ERROR);
}
}
}
@@ -414,9 +449,30 @@ aclfromtext(char *aclstr, int *aclcnt)
aclimport = nextp;
}
free(allocp);
- return (aclp);
+ *ret_aclp = aclp;
+ return (0);
+}
+
+aclent_t *
+aclfromtext(char *aclstr, int *aclcnt)
+{
+ acl_t *aclp;
+ aclent_t *aclentp;
+ int error;
+
+ error = aclent_aclfromtext(aclstr, &aclp);
+ if (error)
+ return (NULL);
+
+ aclentp = aclp->acl_aclp;
+ aclp->acl_aclp = NULL;
+ acl_free(aclp);
+
+ *aclcnt = aclp->acl_cnt;
+ return (aclentp);
}
+
static char *
strappend(char *where, char *newstr)
{
@@ -443,6 +499,129 @@ convert_perm(char *where, o_mode_t perm)
return (where);
}
+static char *
+ace_convert_perm(char *where, mode_t perm, int isdir, int iflags)
+{
+ char *start = where;
+
+ /*
+ * The following mneumonics all have the
+ * same value. The only difference is the
+ * first value is for files and second for directories
+ * ACE_READ_DATA/ACE_LIST_DIRECTORY
+ * ACE_WRITE_DATA/ACE_ADD_FILE
+ * ACE_APPEND_DATA/ACE_ADD_SUBDIRECTORY
+ */
+
+ /*
+ * If ACE is a directory, but inheritance indicates its
+ * for a file then print permissions for file rather than
+ * dir.
+ */
+ if (isdir) {
+ if (perm & ACE_LIST_DIRECTORY) {
+ if (iflags == ACE_FILE_INHERIT_ACE)
+ where = strappend(where, "read_data/");
+ else
+ where = strappend(where,
+ "list_directory/read_data/");
+ }
+ if (perm & ACE_ADD_FILE) {
+ if (iflags == ACE_FILE_INHERIT_ACE)
+ where = strappend(where, "write_data/");
+ else
+ where = strappend(where,
+ "add_file/write_data/");
+ }
+ if (perm & ACE_ADD_SUBDIRECTORY) {
+ if (iflags == ACE_FILE_INHERIT_ACE)
+ where = strappend(where, "append_data/");
+ else
+ where = strappend(where,
+ "add_subdirectory/append_data/");
+ }
+ } else {
+ if (perm & ACE_READ_DATA)
+ where = strappend(where, "read_data/");
+ if (perm & ACE_WRITE_DATA)
+ where = strappend(where, "write_data/");
+ if (perm & ACE_APPEND_DATA)
+ where = strappend(where, "append_data/");
+ }
+ if (perm & ACE_READ_NAMED_ATTRS)
+ where = strappend(where, "read_xattr/");
+ if (perm & ACE_WRITE_NAMED_ATTRS)
+ where = strappend(where, "write_xattr/");
+ if (perm & ACE_EXECUTE)
+ where = strappend(where, "execute/");
+ if (perm & ACE_DELETE_CHILD)
+ where = strappend(where, "delete_child/");
+ if (perm & ACE_READ_ATTRIBUTES)
+ where = strappend(where, "read_attributes/");
+ if (perm & ACE_WRITE_ATTRIBUTES)
+ where = strappend(where, "write_attributes/");
+ if (perm & ACE_DELETE)
+ where = strappend(where, "delete/");
+ if (perm & ACE_READ_ACL)
+ where = strappend(where, "read_acl/");
+ if (perm & ACE_WRITE_ACL)
+ where = strappend(where, "write_acl/");
+ if (perm & ACE_WRITE_OWNER)
+ where = strappend(where, "write_owner/");
+ if (perm & ACE_SYNCHRONIZE)
+ where = strappend(where, "synchronize");
+
+ if (start[strlen(start) - 1] == '/') {
+ start[strlen(start) - 1] = '\0';
+ where = start + strlen(start);
+ }
+ return (where);
+}
+
+int
+ace_permask(char *perm_tok, int *perm)
+{
+ if (strcmp(perm_tok, "read_data") == 0)
+ *perm |= ACE_READ_DATA;
+ else if (strcmp(perm_tok, "list_directory") == 0)
+ *perm |= ACE_LIST_DIRECTORY;
+ else if (strcmp(perm_tok, "write_data") == 0)
+ *perm |= ACE_WRITE_DATA;
+ else if (strcmp(perm_tok, "add_file") == 0)
+ *perm |= ACE_ADD_FILE;
+ else if (strcmp(perm_tok, "append_data") == 0)
+ *perm |= ACE_APPEND_DATA;
+ else if (strcmp(perm_tok, "add_subdirectory") == 0)
+ *perm |= ACE_ADD_SUBDIRECTORY;
+ else if (strcmp(perm_tok, "read_xattr") == 0)
+ *perm |= ACE_READ_NAMED_ATTRS;
+ else if (strcmp(perm_tok, "write_xattr") == 0)
+ *perm |= ACE_WRITE_NAMED_ATTRS;
+ else if (strcmp(perm_tok, "execute") == 0)
+ *perm |= ACE_EXECUTE;
+ else if (strcmp(perm_tok, "delete_child") == 0)
+ *perm |= ACE_DELETE_CHILD;
+ else if (strcmp(perm_tok, "read_attributes") == 0)
+ *perm |= ACE_READ_ATTRIBUTES;
+ else if (strcmp(perm_tok, "write_attributes") == 0)
+ *perm |= ACE_WRITE_ATTRIBUTES;
+ else if (strcmp(perm_tok, "delete") == 0)
+ *perm |= ACE_DELETE;
+ else if (strcmp(perm_tok, "read_acl") == 0)
+ *perm |= ACE_READ_ACL;
+ else if (strcmp(perm_tok, "write_acl") == 0)
+ *perm |= ACE_WRITE_ACL;
+ else if (strcmp(perm_tok, "write_owner") == 0)
+ *perm |= ACE_WRITE_OWNER;
+ else if (strcmp(perm_tok, "synchronize") == 0)
+ *perm |= ACE_SYNCHRONIZE;
+ else {
+ return (1);
+ }
+
+ return (0);
+}
+
/*
* Callers should check the return code as this routine may change the string
* pointer in dynaclstr.
@@ -462,3 +641,537 @@ increase_length(struct dynaclstr *dacl, size_t increase)
} else
return (0);
}
+
+/*
+ * ace_acltotext() conver each ace formatted acl to look like this:
+ *
+ * entry_type:uid^gid^name:perms:allow^deny[:flags][,]
+ *
+ * The maximum length of entry_type is 5 ("group")
+ *
+ * The max length of a uid^gid^name entry (in theory) is 8, hence we use
+ * LOGNAME_MAX.
+ *
+ * The length of a perms entry is 144 i.e read_data/write_data...
+ * to each acl entry.
+ *
+ * iflags: file_inherit/dir_inherit/inherit_only/no_propagate
+ *
+ */
+
+#define ACE_ENTRYTYPLEN 6
+#define IFLAGS_SIZE 51
+#define ACCESS_TYPE_SIZE 5
+#define COLON_CNT 3
+#define PERMS_LEN 216
+#define ACE_ENTRY_SIZE (ACE_ENTRYTYPLEN + LOGNAME_MAX + PERMS_LEN +\
+ ACCESS_TYPE_SIZE + IFLAGS_SIZE + COLON_CNT)
+
+static char *
+ace_acltotext(acl_t *aceaclp)
+{
+ ace_t *aclp = aceaclp->acl_aclp;
+ int aclcnt = aceaclp->acl_cnt;
+ char *aclexport;
+ char *where;
+ char *start;
+ struct group *groupp;
+ struct passwd *passwdp;
+ struct dynaclstr *dstr;
+ int i, rtn;
+ int isdir = (aceaclp->acl_flags & ACL_IS_DIR);
+ size_t excess = 0;
+
+ if (aclp == NULL)
+ return (NULL);
+ if ((dstr = malloc(sizeof (struct dynaclstr))) == NULL)
+ return (NULL);
+ dstr->bufsize = aclcnt * ACE_ENTRY_SIZE;
+ if ((dstr->aclexport = malloc(dstr->bufsize)) == NULL)
+ return (NULL);
+ *dstr->aclexport = '\0';
+ where = dstr->aclexport;
+
+ for (i = 0; i < aclcnt; i++, aclp++) {
+ switch (aclp->a_flags & 0xf040) {
+ case ACE_OWNER:
+ case 0:
+ if ((aclp->a_flags & 0xf040) == ACE_OWNER)
+ where = strappend(where, "owner@");
+ else
+ where = strappend(where, "user:");
+ if ((aclp->a_flags & 0xf040) == 0) {
+ passwdp = getpwuid(aclp->a_who);
+ if (passwdp == (struct passwd *)NULL) {
+ /* put in uid instead */
+ (void) sprintf(where, "%d",
+ aclp->a_who);
+ } else {
+ excess = strlen(passwdp->pw_name) -
+ LOGNAME_MAX;
+ if (excess > 0) {
+ rtn = increase_length(dstr,
+ excess);
+ if (rtn == 1)
+ /* reset where */
+ where =
+ dstr->aclexport +
+ strlen(
+ dstr->aclexport);
+ else
+ return (NULL);
+ }
+ where = strappend(where,
+ passwdp->pw_name);
+ }
+ } else {
+ where = strappend(where, "");
+ }
+ where = strappend(where, ":");
+ break;
+ case ACE_GROUP|ACE_IDENTIFIER_GROUP:
+ case ACE_IDENTIFIER_GROUP:
+ if ((aclp->a_flags & 0xf040) ==
+ (ACE_GROUP | ACE_IDENTIFIER_GROUP))
+ where = strappend(where, "group@");
+ else
+ where = strappend(where, "group:");
+ if (!(aclp->a_flags & ACE_GROUP)) {
+ groupp = getgrgid(aclp->a_who);
+ if (groupp == (struct group *)NULL) {
+ /* put in gid instead */
+ (void) sprintf(where,
+ "%d", aclp->a_who);
+ } else {
+ excess = strlen(groupp->gr_name) -
+ LOGNAME_MAX;
+ if (excess > 0) {
+ rtn = increase_length(dstr,
+ excess);
+ if (rtn == 1)
+ /* reset where */
+ where =
+ dstr->aclexport +
+ strlen(
+ dstr->aclexport);
+ else
+ return (NULL);
+ }
+ where = strappend(where,
+ groupp->gr_name);
+ }
+ } else {
+ where = strappend(where, "");
+ }
+ where = strappend(where, ":");
+ break;
+ case ACE_EVERYONE:
+ where = strappend(where, "everyone@:");
+ break;
+ default:
+ free(dstr->aclexport);
+ free(dstr);
+ return (NULL);
+
+ }
+ where = ace_convert_perm(where, aclp->a_access_mask,
+ isdir, (aclp->a_flags &
+ (ACE_FILE_INHERIT_ACE|ACE_DIRECTORY_INHERIT_ACE)));
+ where = strappend(where,
+ (aclp->a_type == ACE_ACCESS_ALLOWED_ACE_TYPE) ?
+ ":allow" : ":deny");
+
+ /*
+ * slap on inheritance flags if we have any
+ */
+
+ if (aclp->a_flags & 0xf) {
+ where = strappend(where, ":");
+ start = where;
+ if (aclp->a_flags & ACE_FILE_INHERIT_ACE)
+ where = strappend(where, "file_inherit/");
+ if (aclp->a_flags & ACE_DIRECTORY_INHERIT_ACE)
+ where = strappend(where, "dir_inherit/");
+ if (aclp->a_flags & ACE_NO_PROPAGATE_INHERIT_ACE)
+ where = strappend(where, "no_propagate/");
+ if (aclp->a_flags & ACE_INHERIT_ONLY_ACE)
+ where = strappend(where, "inherit_only");
+
+ /*
+ * chop off trailing slash, if present
+ */
+ if (start[strlen(start) - 1] == '/') {
+ start[strlen(start) - 1] = '\0';
+ where = start + strlen(start);
+ }
+ }
+ if (i < aclcnt - 1)
+ where = strappend(where, ",");
+ }
+ aclexport = dstr->aclexport;
+ free(dstr);
+ return (aclexport);
+}
+
+static int
+build_iflags(char *str, int *iflags)
+{
+
+ char *tok;
+ *iflags = 0;
+
+ tok = strtok(str, "/");
+
+ if (tok == NULL)
+ return (1);
+
+ do {
+ if (strcmp(tok, "file_inherit") == 0)
+ *iflags |= ACE_FILE_INHERIT_ACE;
+ else if (strcmp(tok, "dir_inherit") == 0)
+ *iflags |= ACE_DIRECTORY_INHERIT_ACE;
+ else if (strcmp(tok, "inherit_only") == 0)
+ *iflags |= ACE_INHERIT_ONLY_ACE;
+ else if (strcmp(tok, "no_propagate") == 0)
+ *iflags |= ACE_NO_PROPAGATE_INHERIT_ACE;
+ else
+ return (1);
+ } while (tok = strtok(NULL, "/"));
+ return (0);
+}
+
+/*
+ * Convert external acl representation to internal representation.
+ * The accepted syntax is: <acl_entry>[,<acl_entry>]*[,]
+ * The comma at the end is not prescribed by the man pages.
+ * But it is needed not to break the old programs.
+ */
+
+int
+ace_aclfromtext(char *aclstr, acl_t **ret_aclp)
+{
+ char *fieldp;
+ char *tp;
+ char *nextp;
+ char *allocp;
+ char *aclimport;
+ char *str;
+ char *perm_tok;
+ int entry_type;
+ int id;
+ int type;
+ int iflags;
+ int len;
+ int error;
+ int32_t perm;
+ ace_t *tmpaclp;
+ acl_t *aclp;
+ struct group *groupp;
+ struct passwd *passwdp;
+
+ if (! aclstr)
+ return (EACL_INVALID_STR);
+
+ len = strlen(aclstr);
+
+ aclp = acl_alloc(ACE_T);
+ if (aclp == NULL) {
+ return (EACL_MEM_ERROR);
+ }
+
+ *ret_aclp = NULL;
+
+ if ((aclimport = allocp = strdup(aclstr)) == NULL) {
+ return (EACL_MEM_ERROR);
+ }
+
+
+ if (aclimport[len - 1] == ',')
+ aclimport[len - 1] = '\0';
+
+ for (; aclimport; ) {
+ /* look for an ACL entry */
+ tp = strchr(aclimport, ',');
+ if (tp == NULL) {
+ nextp = NULL;
+ } else {
+ *tp = '\0';
+ nextp = tp + 1;
+ }
+
+ aclp->acl_cnt += 1;
+
+ /*
+ * get additional memory:
+ * can be more efficient by allocating a bigger block
+ * each time.
+ */
+ if (aclp->acl_cnt > 1)
+ tmpaclp = (ace_t *)realloc(aclp->acl_aclp,
+ sizeof (ace_t) * (aclp->acl_cnt));
+ else
+ tmpaclp = (ace_t *)malloc(sizeof (ace_t));
+ if (tmpaclp == NULL) {
+ free(allocp);
+ acl_free(aclp);
+ return (EACL_MEM_ERROR);
+ }
+ aclp->acl_aclp = tmpaclp;
+ tmpaclp = (ace_t *)aclp->acl_aclp + (aclp->acl_cnt - 1);
+
+ /* look for entry type field */
+ tp = strchr(aclimport, ':');
+ if (tp == NULL) {
+ free(allocp);
+ acl_free(aclp);
+ return (EACL_ENTRY_ERROR);
+ } else
+ *tp = '\0';
+ if (strcmp(aclimport, "owner@") == 0) {
+ entry_type = ACE_OWNER;
+ } else if (strcmp(aclimport, "group@") == 0) {
+ entry_type = ACE_GROUP | ACE_IDENTIFIER_GROUP;
+ } else if (strcmp(aclimport, "everyone@") == 0) {
+ entry_type = ACE_EVERYONE;
+ } else if (strcmp(aclimport, "group") == 0) {
+ entry_type = ACE_IDENTIFIER_GROUP;
+ } else if (strcmp(aclimport, "user") == 0) {
+ entry_type = 0;
+ } else {
+ free(allocp);
+ acl_free(aclp);
+ return (EACL_ENTRY_ERROR);
+ }
+
+ /*
+ * If not an abstraction owner@, group@ or everyone@
+ * then we must have a user/group name next
+ */
+
+ if (entry_type == 0 || entry_type == ACE_IDENTIFIER_GROUP) {
+ fieldp = tp + 1;
+ tp = strchr(fieldp, ':');
+ if (tp == NULL) {
+ free(allocp);
+ acl_free(aclp);
+ return (EACL_INVALID_USER_GROUP);
+ } else
+ *tp = '\0';
+ if (fieldp != tp) {
+ /*
+ * The second field could be empty. We only care
+ * when the field has user/group name.
+ */
+ if (entry_type == 0) {
+ /*
+ * The reentrant interface getpwnam_r()
+ * is uncommitted and subject to
+ * change. Use the friendlier interface
+ * getpwnam().
+ */
+ error = 0;
+ passwdp = getpwnam(fieldp);
+ if (passwdp == NULL) {
+ error = acl_str_to_id(
+ fieldp, &id);
+ } else {
+ id = passwdp->pw_uid;
+ }
+
+ if (error) {
+ free(allocp);
+ acl_free(aclp);
+ return (error);
+ }
+ } else {
+ error = 0;
+ if (entry_type ==
+ ACE_IDENTIFIER_GROUP) {
+ groupp = getgrnam(fieldp);
+ if (groupp == NULL) {
+ /* no group? */
+ error = acl_str_to_id(
+ fieldp, &id);
+ } else
+ id = groupp->gr_gid;
+
+ } else if ((entry_type == ACE_OWNER) ||
+ (entry_type ==
+ (ACE_IDENTIFIER_GROUP|ACE_GROUP)) ||
+ (entry_type != ACE_EVERYONE)) {
+ error = EACL_FIELD_NOT_BLANK;
+ } else {
+ error = EACL_ENTRY_ERROR;
+ }
+
+ if (error) {
+ free(allocp);
+ acl_free(aclp);
+ return (error);
+ }
+ }
+ }
+ } else {
+ id = -1;
+ }
+
+ /* next field: permission */
+ fieldp = tp + 1;
+ tp = strchr(fieldp, ':');
+ if (tp == NULL) {
+ free(allocp);
+ acl_free(aclp);
+ return (EACL_PERM_MASK_ERROR);
+ } else
+ *tp = '\0';
+
+ perm = 0;
+
+ perm_tok = strtok(fieldp, "/");
+ if (perm_tok == NULL) {
+ perm = 0;
+ } else {
+ do {
+ if (ace_permask(perm_tok, &perm) != 0) {
+ free(allocp);
+ acl_free(aclp);
+ return (EACL_PERM_MASK_ERROR);
+ }
+ } while (perm_tok = strtok(NULL, "/"));
+ }
+
+ /* grab allow/deny */
+ fieldp = tp + 1;
+ tp = strchr(fieldp, ':');
+ if (tp != NULL)
+ *tp = '\0';
+
+ if (strcmp(fieldp, "allow") == 0)
+ type = ACE_ACCESS_ALLOWED_ACE_TYPE;
+ else if (strcmp(fieldp, "deny") == 0)
+ type = ACE_ACCESS_DENIED_ACE_TYPE;
+ else {
+ free(allocp);
+ acl_free(aclp);
+ return (EACL_INVALID_ACCESS_TYPE);
+ }
+
+ /* grab option inherit flags */
+
+ iflags = 0;
+ if (tp != NULL) {
+ fieldp = tp + 1;
+ if (fieldp != NULL) {
+ *tp = '\0';
+ str = fieldp;
+ if (build_iflags(str, &iflags) != 0) {
+ free(allocp);
+ acl_free(aclp);
+ return (EACL_INHERIT_ERROR);
+ }
+ } else {
+ free(allocp);
+ acl_free(aclp);
+ return (EACL_UNKNOWN_DATA);
+ }
+ }
+ /* slap fields into ace_t structure */
+
+ tmpaclp->a_flags = entry_type;
+ tmpaclp->a_flags |= iflags;
+ tmpaclp->a_who = id;
+ tmpaclp->a_access_mask = perm;
+ tmpaclp->a_type = type;
+ aclimport = nextp;
+ }
+ free(allocp);
+ *ret_aclp = aclp;
+ return (0);
+}
+
+char
+*acl_totext(acl_t *aclp)
+{
+ if (aclp == NULL)
+ return (NULL);
+
+ switch (aclp->acl_type) {
+ case ACE_T:
+ return (ace_acltotext(aclp));
+ case ACLENT_T:
+ return (acltotext(aclp->acl_aclp, aclp->acl_cnt));
+ }
+ return (NULL);
+}
+
+int
+acl_fromtext(const char *acltextp, acl_t **ret_aclp)
+{
+ acl_t *aclp;
+ char *token;
+ char *ptr;
+ char *textp;
+ enum acl_type flavor;
+ int colon_cnt = 0;
+ int error;
+
+ /*
+ * first try and detect what type of acl entries we have
+ *
+ * aclent_t can have 1, 2 or 3 colons
+ * if 3 then must have word default:
+ *
+ * ace_t can have 2, 3 or 4
+ * for 2 then must be owner@, group@ or everyone@
+ */
+
+ textp = strdup(acltextp);
+ if (textp == NULL)
+ return (-1);
+
+ token = strtok(textp, ",");
+ if (token == NULL) {
+ free(textp);
+ return (-1);
+ }
+
+ for (ptr = token; *ptr; ptr++) {
+ if (*ptr == ':')
+ colon_cnt++;
+ }
+
+ if (colon_cnt == 1 || colon_cnt == 2) {
+ if ((strncmp(acltextp, "owner@", 6) == 0) ||
+ (strncmp(acltextp, "group@", 6) == 0) ||
+ (strncmp(acltextp, "everyone@", 9) == 0))
+ flavor = ACE_T;
+ else
+ flavor = ACLENT_T;
+ } else if (colon_cnt == 3) {
+ ptr = strtok(token, ":");
+ if (ptr == NULL) {
+ free(textp);
+ return (EACL_MISSING_FIELDS);
+ } else if (strcmp(ptr, "default") == 0) {
+ flavor = ACLENT_T;
+ } else {
+ flavor = ACE_T;
+ }
+ } else if (colon_cnt == 4) {
+ flavor = ACE_T;
+ } else {
+ free(textp);
+ return (EACL_MISSING_FIELDS);
+ }
+
+
+ free(textp);
+
+ if (flavor == ACLENT_T)
+ error = aclent_aclfromtext((char *)acltextp, &aclp);
+ else
+ error = ace_aclfromtext((char *)acltextp, &aclp);
+
+ *ret_aclp = aclp;
+ return (error);
+}