summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/bart/create.c4
-rw-r--r--usr/src/cmd/chmod/chmod.c8
-rw-r--r--usr/src/cmd/cmd-inet/usr.bin/rcp.c4
-rw-r--r--usr/src/cmd/cpio/cpio.c2
-rw-r--r--usr/src/cmd/ls/ls.c17
-rw-r--r--usr/src/cmd/tar/tar.c3
-rw-r--r--usr/src/lib/libsec/Makefile6
-rw-r--r--usr/src/lib/libsec/Makefile.com19
-rw-r--r--usr/src/lib/libsec/common/acl.y484
-rw-r--r--usr/src/lib/libsec/common/acl_lex.l719
-rw-r--r--usr/src/lib/libsec/common/acltext.c1693
-rw-r--r--usr/src/lib/libsec/common/aclutils.c241
-rw-r--r--usr/src/lib/libsec/common/aclutils.h34
-rw-r--r--usr/src/lib/libsec/spec/acl.spec18
-rw-r--r--usr/src/uts/common/sys/acl.h14
15 files changed, 2192 insertions, 1074 deletions
diff --git a/usr/src/cmd/bart/create.c b/usr/src/cmd/bart/create.c
index a676cd480b..c1eb95eca6 100644
--- a/usr/src/cmd/bart/create.c
+++ b/usr/src/cmd/bart/create.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -642,7 +642,7 @@ get_acl_string(const char *fname, const struct stat64 *statb, int *err_code)
(void) fprintf(stderr, "%s: %s\n", fname, acl_strerror(error));
return (safe_strdup("-"));
} else {
- acltext = acl_totext(aclp);
+ acltext = acl_totext(aclp, 0);
acl_free(aclp);
return (acltext);
}
diff --git a/usr/src/cmd/chmod/chmod.c b/usr/src/cmd/chmod/chmod.c
index 403d757dbd..8be3ff9373 100644
--- a/usr/src/cmd/chmod/chmod.c
+++ b/usr/src/cmd/chmod/chmod.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -429,7 +429,6 @@ parse_acl_args(char *arg, acl_args_t **acl_args)
{
acl_t *new_acl = NULL;
int slot;
- int error;
int len;
int action;
acl_args_t *new_acl_args;
@@ -478,9 +477,8 @@ parse_acl_args(char *arg, acl_args_t **acl_args)
return (1);
if (acl_spec) {
- if (error = acl_fromtext(acl_spec, &new_acl)) {
- errmsg(1, 1, "%s\n", acl_strerror(error));
- return (1);
+ if (acl_parse(acl_spec, &new_acl)) {
+ exit(1);
}
}
diff --git a/usr/src/cmd/cmd-inet/usr.bin/rcp.c b/usr/src/cmd/cmd-inet/usr.bin/rcp.c
index 7b76b8967a..057a0c7f1c 100644
--- a/usr/src/cmd/cmd-inet/usr.bin/rcp.c
+++ b/usr/src/cmd/cmd-inet/usr.bin/rcp.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1826,7 +1826,7 @@ sendacl(int f)
* imply its not trivial.
*/
if (aclp && (trivial != ACL_IS_TRIVIAL)) {
- acltext = acl_totext(aclp);
+ acltext = acl_totext(aclp, 0);
if (acltext == NULL) {
error("rcp: failed to convert to text\n");
acl_free(aclp);
diff --git a/usr/src/cmd/cpio/cpio.c b/usr/src/cmd/cpio/cpio.c
index 6f8e97a199..adfa8c53e6 100644
--- a/usr/src/cmd/cpio/cpio.c
+++ b/usr/src/cmd/cpio/cpio.c
@@ -6645,7 +6645,7 @@ append_secattr(
case ACLENT_T:
case ACE_T:
/* LINTED alignment */
- attrtext = acl_totext(aclp);
+ attrtext = acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT);
if (attrtext == NULL) {
(void) fprintf(stderr, "acltotext failed\n");
return (-1);
diff --git a/usr/src/cmd/ls/ls.c b/usr/src/cmd/ls/ls.c
index 540be3b046..50027cf4eb 100644
--- a/usr/src/cmd/ls/ls.c
+++ b/usr/src/cmd/ls/ls.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -221,6 +221,7 @@ static int Lflg;
static int Rflg;
static int Sflg;
static int vflg;
+static int Vflg;
static long hscale;
static mode_t flags;
static int err = 0; /* Contains return code */
@@ -287,7 +288,7 @@ main(int argc, char *argv[])
}
while ((c = getopt(argc, argv,
- "aAbcCdeEfFghHilLmnopqrRsStux1@v")) != EOF)
+ "aAbcCdeEfFghHilLmnopqrRsStux1@vV")) != EOF)
switch (c) {
case 'a':
aflg++;
@@ -416,6 +417,9 @@ main(int argc, char *argv[])
cflg = 0;
uflg++;
continue;
+ case 'V':
+ Vflg++;
+ /*FALLTHROUGH*/
case 'v':
vflg++;
#if !defined(XPG4)
@@ -460,7 +464,7 @@ main(int argc, char *argv[])
}
if (opterr) {
(void) fprintf(stderr, gettext(
- "usage: ls -aAbcCdeEfFghHilLmnopqrRsStuxv1@ [files]\n"));
+ "usage: ls -aAbcCdeEfFghHilLmnopqrRsStuxvV1@ [files]\n"));
exit(2);
}
@@ -868,7 +872,7 @@ pentry(struct lbuf *ap)
if (vflg) {
new_line();
if (p->aclp) {
- acl_printacl(p->aclp, num_cols);
+ acl_printacl(p->aclp, num_cols, Vflg);
}
}
}
@@ -1378,6 +1382,11 @@ gstat(char *file, int argfl, struct ditem *myparent)
}
}
+ if (!vflg && !Vflg && rep->aclp) {
+ acl_free(rep->aclp);
+ rep->aclp = NULL;
+ }
+
if (atflg && pathconf(file, _PC_XATTR_EXISTS) == 1)
rep->acl = '@';
} else
diff --git a/usr/src/cmd/tar/tar.c b/usr/src/cmd/tar/tar.c
index f1a132892e..92eb40a452 100644
--- a/usr/src/cmd/tar/tar.c
+++ b/usr/src/cmd/tar/tar.c
@@ -3025,7 +3025,6 @@ filedone:
/* header is 8 */
attrsize = 8 + (int)strlen(
&attr->attr_info[0]) + 1;
-
error =
acl_fromtext(
&attr->attr_info[0], &aclp);
@@ -5571,7 +5570,7 @@ append_secattr(
switch (acl_type(aclp)) {
case ACLENT_T:
case ACE_T:
- attrtext = acl_totext(aclp);
+ attrtext = acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT);
if (attrtext == NULL) {
(void) fprintf(stderr, "acltotext failed\n");
return (-1);
diff --git a/usr/src/lib/libsec/Makefile b/usr/src/lib/libsec/Makefile
index b0550e8e8e..8859248afd 100644
--- a/usr/src/lib/libsec/Makefile
+++ b/usr/src/lib/libsec/Makefile
@@ -20,7 +20,7 @@
# CDDL HEADER END
#
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -41,7 +41,9 @@ install := TARGET= install
lint := TARGET= lint
MSGFILES= common/acltext.c common/aclutils.c common/aclmode.c \
- common/aclsort.c common/aclcheck.c
+ common/aclsort.c common/aclcheck.c common/acl_lex.l \
+ common/acl.y
+
POFILE= libsec.po
.KEEP_STATE:
diff --git a/usr/src/lib/libsec/Makefile.com b/usr/src/lib/libsec/Makefile.com
index 531db17548..0ea10507db 100644
--- a/usr/src/lib/libsec/Makefile.com
+++ b/usr/src/lib/libsec/Makefile.com
@@ -20,7 +20,7 @@
# CDDL HEADER END
#
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -31,9 +31,14 @@
LIBRARY= libsec.a
VERS= .1
+YFLAGS = -d -v -b acl
+LFLAGS = -t
OBJS_SHARED= acl_common.o
+GENERATED_SRCS = acl.tab.o acl_lex.o
OBJS_COMMON= aclcheck.o aclmode.o aclsort.o acltext.o aclutils.o
-OBJECTS= $(OBJS_COMMON) $(OBJS_SHARED)
+OBJECTS= $(OBJS_COMMON) $(OBJS_SHARED) $(GENERATED_SRCS)
+CLEANFILES += acl_lex.c acl.tab.c acl.tab.h
+LINTSRCS = $(OBJS_COMMON)
# include library definitions
include ../../Makefile.lib
@@ -41,8 +46,8 @@ include ../../Makefile.lib
LIBS = $(DYNLIB) $(LINTLIB)
CFLAGS += $(CCVERBOSE)
-CPPFLAGS += -I$(SRCDIR) -I../../../common/acl
-LDLIBS += -lc
+CPPFLAGS += -I$(SRCDIR) -I. -I../../../common/acl
+LDLIBS += -lc
# install this library in the root filesystem
include ../../Makefile.rootfs
@@ -66,4 +71,10 @@ pics/%.o: ../../../common/acl/%.c
$(COMPILE.c) -o $@ $<
$(POST_PROCESS_O)
+acl.tab.c acl.tab.h: $(SRCDIR)/acl.y
+ $(YACC) $(YFLAGS) $(SRCDIR)/acl.y
+
+acl_lex.c: $(SRCDIR)/acl_lex.l acl.tab.h
+ $(LEX) $(LFLAGS) $(SRCDIR)/acl_lex.l > $@
+
include ../../Makefile.targ
diff --git a/usr/src/lib/libsec/common/acl.y b/usr/src/lib/libsec/common/acl.y
new file mode 100644
index 0000000000..6e842acd2e
--- /dev/null
+++ b/usr/src/lib/libsec/common/acl.y
@@ -0,0 +1,484 @@
+%{
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/acl.h>
+#include <aclutils.h>
+
+extern int yyinteractive;
+extern acl_t *yyacl;
+%}
+
+
+%union {
+ char *str;
+ int val;
+ struct acl_perm_type acl_perm;
+ ace_t ace;
+ aclent_t aclent;
+ acl_t *acl;
+}
+
+
+%token USER_TOK GROUP_TOK MASK_TOK OTHER_TOK OWNERAT_TOK
+%token GROUPAT_TOK EVERYONEAT_TOK DEFAULT_USER_TOK DEFAULT_GROUP_TOK
+%token DEFAULT_MASK_TOK DEFAULT_OTHER_TOK COLON COMMA NL SLASH
+%token <str> IDNAME PERM_TOK INHERIT_TOK
+%token <val> ID ERROR ACE_PERM ACE_INHERIT ENTRY_TYPE ACCESS_TYPE
+
+%type <str> idname
+%type <acl_perm> perms perm aclent_perm ace_perms
+%type <acl> acl_entry
+%type <ace> ace
+%type <aclent> aclent
+%type <val> iflags verbose_iflag compact_iflag access_type id entry_type
+
+%left ERROR COLON
+
+%%
+
+acl: acl_entry NL
+ {
+ yyacl = $1;
+ return (0);
+ }
+
+ /* This seems illegal, but the old aclfromtext() allows it */
+ | acl_entry COMMA NL
+ {
+ yyacl = $1;
+ return (0);
+ }
+ | acl_entry COMMA acl
+ {
+ yyacl = $1;
+ return (0);
+ }
+
+acl_entry: ace
+ {
+ ace_t *acep;
+
+ if (yyacl == NULL) {
+ yyacl = acl_alloc(ACE_T);
+ if (yyacl == NULL)
+ return (EACL_MEM_ERROR);
+ }
+
+ $$ = yyacl;
+ if ($$->acl_type == ACLENT_T) {
+ acl_error(gettext("Cannot have POSIX draft ACL entries"
+ " with NFSV4/ZFS ACL entries\n"));
+ acl_free(yyacl);
+ yyacl = NULL;
+ return (EACL_DIFF_TYPE);
+ }
+
+ $$->acl_aclp = realloc($$->acl_aclp,
+ ($$->acl_entry_size * ($$->acl_cnt + 1)));
+ if ($$->acl_aclp == NULL) {
+ free (yyacl);
+ return (EACL_MEM_ERROR);
+ }
+ acep = $$->acl_aclp;
+ acep[$$->acl_cnt] = $1;
+ $$->acl_cnt++;
+ }
+ | aclent
+ {
+ aclent_t *aclent;
+
+ if (yyacl == NULL) {
+ yyacl = acl_alloc(ACLENT_T);
+ if (yyacl == NULL)
+ return (EACL_MEM_ERROR);
+ }
+
+ $$ = yyacl;
+ if ($$->acl_type == ACE_T) {
+ acl_error(gettext("Cannot have NFSv4/ZFS ACL entries"
+ " with POSIX draft ACL entries\n"));
+ acl_free(yyacl);
+ yyacl = NULL;
+ return (EACL_DIFF_TYPE);
+ }
+
+ $$->acl_aclp = realloc($$->acl_aclp,
+ ($$->acl_entry_size * ($$->acl_cnt +1)));
+ if ($$->acl_aclp == NULL) {
+ free (yyacl);
+ return (EACL_MEM_ERROR);
+ }
+ aclent = $$->acl_aclp;
+ aclent[$$->acl_cnt] = $1;
+ $$->acl_cnt++;
+ }
+
+ace: entry_type idname ace_perms access_type
+ {
+ int error;
+ int id;
+ int mask;
+
+ error = get_id($1, $2, &id);
+ if (error) {
+ acl_error(gettext("Invalid user %s specified\n"), $2);
+ free($2);
+ return (EACL_INVALID_USER_GROUP);
+ }
+
+ $$.a_who = id;
+ $$.a_flags = ace_entry_type($1);
+ free($2);
+ error = ace_perm_mask(&$3, &$$.a_access_mask);
+ if (error)
+ return (error);
+ $$.a_type = $4;
+
+ }
+ | entry_type idname ace_perms access_type COLON id
+ {
+ int error;
+ int id;
+
+ if (yyinteractive) {
+ acl_error(gettext("Extra fields on the end of "
+ "ACL specification\n"));
+ return (EACL_UNKNOWN_DATA);
+ }
+ error = get_id($1, $2, &id);
+ if (error) {
+ $$.a_who = $6;
+ } else {
+ $$.a_who = id;
+ }
+ $$.a_flags = ace_entry_type($1);
+ free($2);
+ error = ace_perm_mask(&$3, &$$.a_access_mask);
+ if (error)
+ return (error);
+ $$.a_type = $4;
+ }
+ | entry_type idname ace_perms iflags access_type
+ {
+ int error;
+ int id;
+
+ error = get_id($1, $2, &id);
+ if (error) {
+ acl_error(gettext("Invalid user %s specified\n"), $2);
+ free($2);
+ return (EACL_INVALID_USER_GROUP);
+ }
+
+ $$.a_who = id;
+ $$.a_flags = ace_entry_type($1);
+ free($2);
+ error = ace_perm_mask(&$3, &$$.a_access_mask);
+ if (error)
+ return (error);
+ $$.a_type = $5;
+ $$.a_flags |= $4;
+ }
+ | entry_type idname ace_perms iflags access_type COLON id
+ {
+ int error;
+ int id;
+
+ if (yyinteractive) {
+ acl_error(gettext("Extra fields on the end of "
+ "ACL specification\n"));
+ return (EACL_UNKNOWN_DATA);
+ }
+ error = get_id($1, $2, &id);
+ if (error) {
+ $$.a_who = $7;
+ } else {
+ $$.a_who = id;
+ }
+
+ $$.a_flags = ace_entry_type($1);
+ free($2);
+ error = ace_perm_mask(&$3, &$$.a_access_mask);
+ if (error)
+ return (error);
+
+ $$.a_type = $5;
+ $$.a_flags |= $4;
+ }
+ | entry_type ace_perms access_type
+ {
+ int error;
+
+ $$.a_who = -1;
+ $$.a_flags = ace_entry_type($1);
+ error = ace_perm_mask(&$2, &$$.a_access_mask);
+ if (error) {
+ return (error);
+ }
+ $$.a_type = $3;
+ }
+ | entry_type ace_perms access_type COLON id
+ {
+ if (yyinteractive) {
+ acl_error(gettext("Extra fields on the end of "
+ "ACL specification\n"));
+ return (EACL_UNKNOWN_DATA);
+ }
+
+ return (EACL_ENTRY_ERROR);
+ }
+ | entry_type ace_perms iflags access_type
+ {
+ int error;
+
+ $$.a_who = -1;
+ $$.a_flags = ace_entry_type($1);
+ error = ace_perm_mask(&$2, &$$.a_access_mask);
+ if (error)
+ return (error);
+ $$.a_type = $4;
+ $$.a_flags |= $3;
+
+ }
+ | entry_type ace_perms iflags access_type COLON id
+ {
+ if (yyinteractive) {
+ acl_error(gettext("Extra fields on the end of "
+ "ACL specification\n"));
+ return (EACL_UNKNOWN_DATA);
+ }
+ return (EACL_ENTRY_ERROR);
+ }
+
+aclent: entry_type idname aclent_perm /* user or group */
+ {
+ int error;
+ int id;
+
+ error = get_id($1, $2, &id);
+ if (error) {
+ acl_error(gettext("Invalid user '%s' specified\n"),
+ $2);
+ free($2);
+ return (EACL_INVALID_USER_GROUP);
+ }
+
+ error = compute_aclent_perms($3.perm_str, &$$.a_perm);
+ if (error) {
+ free($2);
+ acl_error(gettext(
+ "Invalid permission(s) '%s' specified\n"),
+ $3.perm_str);
+ return (error);
+ }
+ $$.a_id = id;
+ error = aclent_entry_type($1, 0, &$$.a_type);
+ free($2);
+ if (error) {
+ acl_error(
+ gettext("Invalid ACL entry type '%s' specified\n"),
+ $1);
+ return (error);
+ }
+ }
+ | entry_type COLON aclent_perm /* owner group other */
+ {
+ int error;
+
+ error = compute_aclent_perms($3.perm_str, &$$.a_perm);
+ if (error) {
+ acl_error(gettext(
+ "Invalid permission(s) '%s' specified\n"),
+ $3.perm_str);
+ return (error);
+ }
+ $$.a_id = -1;
+ error = aclent_entry_type($1, 1, &$$.a_type);
+ if (error) {
+ acl_error(
+ gettext("Invalid ACL entry type '%s' specified\n"),
+ $1);
+ return (error);
+ }
+ }
+ | entry_type COLON aclent_perm COLON id
+ {
+ if (yyinteractive) {
+ acl_error(gettext("Extra fields on the end of "
+ "ACL specification\n"));
+ return (EACL_UNKNOWN_DATA);
+ }
+ return (EACL_ENTRY_ERROR);
+ }
+ | entry_type idname aclent_perm COLON id /* user or group */
+ {
+ int error;
+ int id;
+
+ if (yyinteractive) {
+ acl_error(gettext("Extra fields on the end of "
+ "ACL specification\n"));
+ return (EACL_UNKNOWN_DATA);
+ }
+ error = compute_aclent_perms($3.perm_str, &$$.a_perm);
+ if (error) {
+ free($2);
+ acl_error(gettext(
+ "Invalid permission(s) '%s' specified\n"),
+ $3.perm_str);
+ return (error);
+ }
+ error = get_id($1, $2, &id);
+ if (error)
+ $$.a_id = $5;
+ else
+ $$.a_id = id;
+
+ error = aclent_entry_type($1, 0, &$$.a_type);
+ free($2);
+ if (error) {
+ acl_error(
+ gettext("Invalid ACL entry type '%s' specified\n"),
+ $1);
+ return (error);
+ }
+ }
+ | entry_type aclent_perm /* mask entry */
+ {
+ int error;
+
+ error = compute_aclent_perms($2.perm_str, &$$.a_perm);
+ if (error) {
+ acl_error(gettext(
+ "Invalid permission(s) '%s' specified\n"),
+ $2.perm_str);
+ return (error);
+ }
+ $$.a_id = -1;
+ error = aclent_entry_type($1, 0, &$$.a_type);
+ if (error) {
+ acl_error(
+ gettext("Invalid ACL entry type specified %d\n"),
+ error);
+ return (error);
+ }
+ }
+ | entry_type aclent_perm COLON id
+ {
+ if (yyinteractive) {
+ acl_error(gettext("Extra fields on the end of "
+ "ACL specification\n"));
+ return (EACL_UNKNOWN_DATA);
+ }
+ return (EACL_ENTRY_ERROR);
+ }
+
+iflags: compact_iflag COLON {$$ = $1;}
+ | verbose_iflag COLON {$$ = $1;}
+ | COLON {$$ = 0;}
+
+compact_iflag : INHERIT_TOK
+ {
+ int error;
+ uint32_t iflags;
+
+ error = compute_ace_inherit($1, &iflags);
+ if (error) {
+ acl_error(gettext("Invalid inheritance flags "
+ "'%s' specified\n"), $1);
+ free($1);
+ return (error);
+ }
+ $$ = iflags;
+ }
+ | INHERIT_TOK SLASH verbose_iflag
+ {
+ acl_error(gettext("Can't mix compact inherit flags with"
+ " verbose inheritance flags\n"));
+ return (EACL_INHERIT_ERROR);
+ }
+
+verbose_iflag: ACE_INHERIT {$$ |= $1;}
+ | ACE_INHERIT SLASH verbose_iflag {$$ = $1 | $3;}
+ | ACE_INHERIT SLASH compact_iflag
+ {
+ acl_error(gettext("Can't mix verbose inherit flags with"
+ " compact inheritance flags\n"));
+ return (EACL_INHERIT_ERROR);
+ }
+ | ACE_INHERIT SLASH ERROR {return ($3);}
+
+aclent_perm: PERM_TOK
+ {
+ $$.perm_style = PERM_TYPE_UNKNOWN;
+ $$.perm_str = $1;
+ $$.perm_val = 0;
+ }
+ | PERM_TOK ERROR
+ {
+ acl_error(gettext("ACL entry permissions are incorrectly "
+ "specified\n"));
+ return ($2);
+ }
+
+access_type: ACCESS_TYPE { $$ = $1;}
+ | ERROR {return ($1);}
+
+id: ID {$$ = $1;}
+ | ERROR {return ($1);}
+
+ace_perms: perm {$$ = $1;}
+ | aclent_perm COLON {$$ = $1;}
+ | ERROR {return ($1);}
+
+perm: perms COLON {$$ = $1;}
+ | COLON {$$.perm_style = PERM_TYPE_EMPTY;}
+
+perms: ACE_PERM
+ {
+ $$.perm_style = PERM_TYPE_ACE;
+ $$.perm_val |= $1;
+ }
+ | ACE_PERM SLASH perms
+ {
+ $$.perm_style = PERM_TYPE_ACE;
+ $$.perm_val = $1 | $3.perm_val;
+ }
+ | ACE_PERM SLASH aclent_perm
+ {
+
+ acl_error(gettext("Can't mix verbose permissions with"
+ " compact permission\n"));
+ return (EACL_PERM_MASK_ERROR);
+
+ }
+
+idname: IDNAME {$$ = $1;}
+
+entry_type: ENTRY_TYPE {$$ = $1;}
+ | ERROR {return ($1);}
diff --git a/usr/src/lib/libsec/common/acl_lex.l b/usr/src/lib/libsec/common/acl_lex.l
new file mode 100644
index 0000000000..ae82a95124
--- /dev/null
+++ b/usr/src/lib/libsec/common/acl_lex.l
@@ -0,0 +1,719 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+%{
+#include <sys/acl.h>
+#include <aclutils.h>
+#include <errno.h>
+#include "acl.tab.h"
+
+#ifdef input
+#undef input
+#endif
+
+#ifdef unput
+#undef unput
+#endif
+
+int grab_string(char *terminators);
+static int input();
+static void unput(int);
+
+int
+yyerror(const char *s)
+{
+ return (0);
+}
+
+int
+yywrap(void)
+{
+ return (1);
+}
+
+extern char *yybuf;
+int yybufpos;
+
+%}
+
+%s TS NS PS AIS US ES
+/*
+ * TS = type state
+ * NS = name state
+ * PS = Permission state
+ * AIS = Allow/deny/inheritance state
+ * US = UID/GID state
+ * ES = End state
+ */
+
+ID [1-9][0-9]*
+LOGNAME [a-z0-9A-Z]+:
+BADLOGNAME [a-z0-9A-Z]+
+PERM_STR [rRwWxpdDaAcCos-]+
+INHERIT_STR [fdinFS-]+
+
+%%
+
+<TS>user: {
+ BEGIN NS;
+ yylval.val = USER_TOK;
+ return (ENTRY_TYPE);
+ }
+<TS>owner@: {
+ BEGIN PS;
+ yylval.val = OWNERAT_TOK;
+ return (ENTRY_TYPE);
+ }
+<TS>group@: {
+ BEGIN PS;
+ yylval.val = GROUPAT_TOK;
+ return (ENTRY_TYPE);
+ }
+<TS>everyone@: {
+ BEGIN PS;
+ yylval.val = EVERYONEAT_TOK;
+ return (ENTRY_TYPE);
+ }
+<TS>group: {
+ BEGIN NS;
+ yylval.val = GROUP_TOK;
+ return (ENTRY_TYPE);
+ }
+<TS>mask: {
+ BEGIN PS;
+ yylval.val = MASK_TOK;
+ return (ENTRY_TYPE);
+ }
+<TS>mask:: {
+ BEGIN PS;
+ yylval.val = MASK_TOK;
+ return (ENTRY_TYPE);
+ }
+<TS>other: {
+ BEGIN PS;
+ yylval.val = OTHER_TOK;
+ return (ENTRY_TYPE);
+ }
+<TS>other:: {
+ BEGIN PS;
+ yylval.val = OTHER_TOK;
+ return (ENTRY_TYPE);
+ }
+<TS>defaultuser: {
+ BEGIN NS;
+ yylval.val = DEFAULT_USER_TOK;
+ return (ENTRY_TYPE);
+ }
+<TS>default:user: {
+ BEGIN NS;
+ yylval.val = DEFAULT_USER_TOK;
+ return (ENTRY_TYPE);
+ }
+<TS>defaultgroup: {
+ BEGIN NS;
+ yylval.val = DEFAULT_GROUP_TOK;
+ return (ENTRY_TYPE);
+ }
+<TS>default:group: {
+ BEGIN NS;
+ yylval.val = DEFAULT_GROUP_TOK;
+ return (ENTRY_TYPE);
+ }
+<TS>defaultother: {
+ BEGIN PS;
+ yylval.val = DEFAULT_OTHER_TOK;
+ return (ENTRY_TYPE);
+ }
+<TS>defaultother:: {
+ BEGIN PS;
+ yylval.val = DEFAULT_OTHER_TOK;
+ return (ENTRY_TYPE);
+ }
+<TS>default:other: {
+ BEGIN PS;
+ yylval.val = DEFAULT_OTHER_TOK;
+ return (ENTRY_TYPE);
+ }
+<TS>defaultmask: {
+ BEGIN PS;
+ yylval.val = DEFAULT_MASK_TOK;
+ return (ENTRY_TYPE);
+ }
+<TS>defaultmask:: {
+ BEGIN PS;
+ yylval.val = DEFAULT_MASK_TOK;
+ return (ENTRY_TYPE);
+ }
+<TS>default:mask: {
+ BEGIN PS;
+ yylval.val = DEFAULT_MASK_TOK;
+ return (ENTRY_TYPE);
+ }
+<TS>"\n" {
+ return (NL);
+ }
+<TS>. {
+ if (grab_string(":\n") != 0) {
+ acl_error(gettext("Failed to retrieve"
+ " error string\n"));
+ yylval.val = EACL_MEM_ERROR;
+ return (ERROR);
+ }
+ acl_error(gettext("Invalid ACL entry "
+ "type '%s' specified\n"), yylval.str);
+ free(yylval.str);
+ yylval.val = EACL_ENTRY_ERROR;
+ return (ERROR);
+ }
+<NS>: {
+ BEGIN PS;
+ return (COLON);
+ }
+<NS>{LOGNAME} {
+ yylval.str = strdup(yytext);
+ if (yylval.str == NULL) {
+ yylval.val = EACL_MEM_ERROR;
+ return (ERROR);
+ }
+ yylval.str[strlen(yylval.str) -1] = '\0';
+ BEGIN PS;
+ return (IDNAME);
+ }
+<NS>{BADLOGNAME} {
+ acl_error(gettext("Missing fields after "
+ "user/group '%s'\n"), yytext);
+ yylval.val = EACL_MISSING_FIELDS;
+ return (ERROR);
+ }
+<NS>"\n" {
+ acl_error(gettext("Missing user/group name"
+ " from ACL specification\n"));
+ yylval.val = EACL_MISSING_FIELDS;
+ return (ERROR);
+ }
+<NS>. {
+ int error;
+
+ error = grab_string(":\n");
+ if (error != 0) {
+ acl_error(gettext("Invalid user/group "
+ "name specification\n"));
+ yylval.val = EACL_INVALID_USER_GROUP;
+ } else {
+ acl_error(gettext("User/Group name "
+ "'%s' not specified correctly\n"),
+ yylval.str);
+ free(yylval.str);
+ yylval.val = EACL_ENTRY_ERROR;
+ }
+ return (ERROR);
+ }
+<PS>read_data/[:/] {
+ yylval.val = ACE_READ_DATA;
+ return (ACE_PERM);
+ }
+<PS>list_directory/[:/] {
+ yylval.val = ACE_LIST_DIRECTORY;
+ return (ACE_PERM);
+ }
+<PS>write_data/[:/] {
+ yylval.val = ACE_WRITE_DATA;
+ return (ACE_PERM);
+ }
+<PS>add_file/[:/] {
+ yylval.val = ACE_ADD_FILE;
+ return (ACE_PERM);
+ }
+<PS>append_data/[:/] {
+ yylval.val = ACE_APPEND_DATA;
+ return (ACE_PERM);
+ }
+<PS>add_subdirectory/[:/] {
+ yylval.val = ACE_ADD_SUBDIRECTORY;
+ return (ACE_PERM);
+ }
+<PS>read_xattr/[:/] {
+ yylval.val = ACE_READ_NAMED_ATTRS;
+ return (ACE_PERM);
+ }
+<PS>write_xattr/[:/] {
+ yylval.val = ACE_WRITE_NAMED_ATTRS;
+ return (ACE_PERM);
+ }
+<PS>execute/[:/] {
+ yylval.val = ACE_EXECUTE;
+ return (ACE_PERM);
+ }
+<PS>delete_child/[:/] {
+ yylval.val = ACE_DELETE_CHILD;
+ return (ACE_PERM);
+ }
+<PS>read_attributes/[:/] {
+ yylval.val = ACE_READ_ATTRIBUTES;
+ return (ACE_PERM);
+ }
+<PS>write_attributes/[:/] {
+ yylval.val = ACE_WRITE_ATTRIBUTES;
+ return (ACE_PERM);
+ }
+<PS>delete/[:/] {
+ yylval.val = ACE_DELETE;
+ return (ACE_PERM);
+ }
+<PS>read_acl/[:/] {
+ yylval.val = ACE_READ_ACL;
+ return (ACE_PERM);
+ }
+<PS>write_acl/[:/] {
+ yylval.val = ACE_WRITE_ACL;
+ return (ACE_PERM);
+ }
+<PS>write_owner/[:/] {
+ yylval.val = ACE_WRITE_OWNER;
+ return (ACE_PERM);
+ }
+<PS>synchronize/[:/] {
+ yylval.val = ACE_SYNCHRONIZE;
+ return (ACE_PERM);
+ }
+<PS>{PERM_STR} {
+ int c;
+
+ c = input();
+ unput(c);
+ yylval.str = strdup(yytext);
+ if (yylval.str == NULL) {
+ yylval.val = EACL_MEM_ERROR;
+ return (ERROR);
+ }
+
+ /*
+ * aclent are done after permissions.
+ */
+ if (isdigit(c))
+ BEGIN US;
+ else if (c != ':')
+ BEGIN ES;
+
+ return (PERM_TOK);
+ }
+<PS>"/:" {
+ acl_error(gettext("Invalid permission /: "
+ "specified\n"));
+ yylval.val = EACL_ENTRY_ERROR;
+ return (ERROR);
+ }
+<PS>: {
+ int c;
+
+ c = input();
+ unput(c);
+ if (isdigit(c))
+ BEGIN (US);
+ else
+ BEGIN AIS;
+ return (COLON);
+ }
+<PS>"/" {
+ return (SLASH);
+ }
+<PS>"\n" {
+ acl_error(gettext("ACL entry is missing "
+ "permission fields\n"));
+ yylval.val = EACL_MISSING_FIELDS;
+ return (ERROR);
+ }
+<PS>. {
+ if (grab_string("/:\n") != 0) {
+ acl_error(gettext("Failed to retrieve"
+ " error string\n"));
+ yylval.val = EACL_MEM_ERROR;
+ return (ERROR);
+ }
+ acl_error(gettext("Invalid permission '%s' "
+ "specified\n"), yylval.str);
+ free(yylval.str);
+ yylval.val = EACL_PERM_MASK_ERROR;
+ return (ERROR);
+ }
+<AIS>allow/[:,\n] {
+
+ int c;
+
+ c = input();
+ if (c == ',' || c == '\n')
+ BEGIN ES;
+ unput(c);
+ yylval.val = ACE_ACCESS_ALLOWED_ACE_TYPE;
+ return (ACCESS_TYPE);
+ }
+<AIS>deny/[:,\n] {
+
+ int c;
+
+ c = input();
+ if (c == ',' || c == '\n')
+ BEGIN ES;
+ unput(c);
+ yylval.val = ACE_ACCESS_DENIED_ACE_TYPE;
+ return (ACCESS_TYPE);
+ }
+
+<AIS>file_inherit/[:/] {
+ yylval.val = ACE_FILE_INHERIT_ACE;
+ return (ACE_INHERIT);
+ }
+<AIS>dir_inherit/[:/] {
+ yylval.val = ACE_DIRECTORY_INHERIT_ACE;
+ return (ACE_INHERIT);
+ }
+<AIS>no_propagate/[/:] {
+ yylval.val = ACE_NO_PROPAGATE_INHERIT_ACE;
+ return (ACE_INHERIT);
+ }
+<AIS>inherit_only/[/:] {
+ yylval.val = ACE_INHERIT_ONLY_ACE;
+ return (ACE_INHERIT);
+ }
+<AIS>{INHERIT_STR} {
+ yylval.str = strdup(yytext);
+ if (yylval.str == NULL) {
+ yylval.val = EACL_MEM_ERROR;
+ return (ERROR);
+ }
+ return (INHERIT_TOK);
+ }
+<AIS>: {
+ int c;
+
+ c = input();
+ unput(c);
+
+ if (isdigit(c)) {
+ BEGIN US;
+ }
+ return (COLON);
+ }
+<AIS>"/" {
+ return (SLASH);
+ }
+<AIS>"\n" {
+ acl_error(
+ gettext("Extra data on end of ACL "
+ "specification\n"), yylval.str);
+ yylval.val = EACL_UNKNOWN_DATA;
+ return (ERROR);
+ }
+<AIS>. {
+ if (yytext[0] != '\n' && yytext[0] != '\0') {
+ if (grab_string(":\n") != 0) {
+ acl_error(gettext("Failed to "
+ "retrieve error string\n"));
+ yylval.val = EACL_MEM_ERROR;
+ return (ERROR);
+ }
+ acl_error(
+ gettext("Invalid inheritance or"
+ " access type '%s' specified\n"),
+ yylval.str);
+ } else {
+ acl_error(
+ gettext("No inheritance or "
+ "access type specified\n"),
+ yylval.str);
+ }
+
+ free(yylval.str);
+ yylval.val = EACL_INVALID_ACCESS_TYPE;
+ return (ERROR);
+ }
+<US>{ID} {
+ BEGIN ES;
+ yylval.val = atoi(yytext);
+ return (ID);
+ }
+<US>. {
+ if (grab_string(",\n") != 0) {
+ acl_error(gettext("Failed to retrieve"
+ " error string\n"));
+ yylval.val = EACL_MEM_ERROR;
+ return (ERROR);
+ }
+ acl_error(
+ gettext("Invalid uid/gid '%s' specified\n"),
+ yylval.str);
+ free(yylval.str);
+ yylval.val = EACL_ENTRY_ERROR;
+ return (ERROR);
+ }
+<US>"\n" {
+ acl_error(gettext("Missing fields in ACL "
+ "specification.\nShould either have "
+ "inheritance flags or uid/gid "
+ "specified.\n"));
+ yylval.val = EACL_ENTRY_ERROR;
+ return (ERROR);
+ }
+<ES>"," {
+ BEGIN TS;
+ return (COMMA);
+ }
+<ES>. {
+ if (grab_string("/:\n") != 0) {
+ acl_error(
+ gettext("Failed to retrieve error"
+ " string\n"));
+ yylval.val = EACL_MEM_ERROR;
+ return (ERROR);
+ }
+ acl_error(
+ gettext("Unrecognized data '%s' found"
+ " in ACL specification\n"), yylval.str);
+ free(yylval.str);
+ yylval.val = EACL_UNKNOWN_DATA;
+ return (ERROR);
+ }
+<ES>"\n" {
+ return (NL);
+ }
+%%
+
+
+/*
+ * pull string up to terminator of off input string.
+ * used for retrieving illegal data in ACL specification.
+ */
+int
+grab_string(char *terminators)
+{
+ int c;
+ int done = 0;
+ int cnt;
+ int alloced;
+ int error = 0;
+ char *ptr;
+
+ cnt = strlen(yytext);
+ yylval.str = calloc(cnt + 1, sizeof (char));
+ if (yylval.str == NULL) {
+ return (1);
+ }
+ alloced = cnt + 1;
+ strcpy(yylval.str, yytext);
+
+ do {
+ c = input();
+ if (c == EOF)
+ break;
+
+ for (ptr = terminators; *ptr; ptr++) {
+ if (c == *ptr) {
+ done = 1;
+ break;
+ }
+ }
+
+ if (done)
+ break;
+
+ if (cnt >= alloced) {
+ yylval.str = realloc(yylval.str,
+ alloced + 80);
+ alloced += 80;
+ if (yylval.str == NULL)
+ return (1);
+
+ memset(yylval.str + cnt, 0,
+ alloced - strlen(yylval.str));
+ }
+ yylval.str[strlen(yylval.str)] = c;
+ cnt++;
+ } while (!done);
+
+ return (error);
+}
+
+static int
+input(void)
+{
+ int c;
+
+ c = yybuf[yybufpos++];
+ if (c == '\0') {
+ return (EOF);
+ }
+
+ return (c);
+}
+
+static void
+unput(int c)
+{
+ if (c == '\0') {
+ return;
+ }
+
+ if (yybufpos > 0) {
+ --yybufpos;
+ }
+}
+
+/*
+ * return ACE entry type
+ */
+int
+ace_entry_type(int type)
+{
+ int ret = -1;
+ switch (type) {
+ case USER_TOK:
+ ret = 0;
+ break;
+ case GROUP_TOK:
+ ret = ACE_IDENTIFIER_GROUP;
+ break;
+ case OWNERAT_TOK:
+ ret = ACE_OWNER;
+ break;
+ case GROUPAT_TOK:
+ ret = ACE_IDENTIFIER_GROUP | ACE_GROUP;
+ break;
+ case EVERYONEAT_TOK:
+ ret = ACE_EVERYONE;
+ break;
+ }
+ return (ret);
+}
+
+
+/*
+ * return aclent entry type
+ */
+int
+aclent_entry_type(int type, int owning, int *ret)
+{
+
+ *ret = 0;
+
+ switch (type) {
+ case USER_TOK:
+ *ret = (owning == 0) ? USER : USER_OBJ;
+ break;
+ case GROUP_TOK:
+ *ret = (owning == 0) ? GROUP : GROUP_OBJ;
+ break;
+
+ case OTHER_TOK:
+ *ret = OTHER_OBJ;
+ break;
+
+ case MASK_TOK:
+ *ret = CLASS_OBJ;
+ break;
+ case DEFAULT_USER_TOK:
+ *ret = (owning == 0) ? DEF_USER : DEF_USER_OBJ;
+ break;
+ case DEFAULT_GROUP_TOK:
+ *ret = (owning == 0) ? DEF_GROUP : DEF_GROUP_OBJ;
+ break;
+ case DEFAULT_MASK_TOK:
+ *ret = DEF_CLASS_OBJ;
+ break;
+ case DEFAULT_OTHER_TOK:
+ *ret = DEF_OTHER_OBJ;
+ break;
+ default:
+ return (EACL_ENTRY_ERROR);
+ }
+
+ return (0);
+}
+
+/*
+ * convert string into numeric id.
+ */
+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);
+}
+
+/*
+ * determine either uid/gid for given entry type
+ */
+int
+get_id(int entry_type, char *name, int *id)
+{
+ struct passwd *pw;
+ struct group *gr;
+ int error;
+
+ if (entry_type == USER_TOK || entry_type == DEFAULT_USER_TOK) {
+ pw = getpwnam(name);
+ if (pw) {
+ *id = pw->pw_uid;
+ return (0);
+ }
+ } else {
+ gr = getgrnam(name);
+ if (gr) {
+ *id = gr->gr_gid;
+ return (0);
+ }
+ }
+
+ /*
+ * getpwnam or getgrnam failed, try and see if
+ * they are numeric strings.
+ */
+ error = acl_str_to_id(name, id);
+
+ if (error)
+ return (error);
+ return (0);
+}
+/*
+ * reset beginning state to TS and set character position
+ * back to zero.
+ */
+void
+yyreset()
+{
+ yybufpos = 0;
+ BEGIN TS;
+}
+
diff --git a/usr/src/lib/libsec/common/acltext.c b/usr/src/lib/libsec/common/acltext.c
index a928d580a9..8f19040b9e 100644
--- a/usr/src/lib/libsec/common/acltext.c
+++ b/usr/src/lib/libsec/common/acltext.c
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -35,33 +35,24 @@
#include <errno.h>
#include <sys/param.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <sys/acl.h>
#include <aclutils.h>
-#include <libintl.h>
+#define ID_STR_MAX 20 /* digits in LONG_MAX */
-extern acl_t *acl_alloc(enum acl_type);
-
+#define APPENDED_ID_MAX ID_STR_MAX + 1 /* id + colon */
/*
- * acltotext() converts each ACL entry to look like this:
- *
- * entry_type:uid^gid^name:perms
- *
- * The maximum length of entry_type is 14 ("defaultgroup::" and
- * "defaultother::") hence ENTRYTYPELEN is set to 14.
- *
- * 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 4 to allow for the comma appended to each
- * to each acl entry. Hence PERMS is set to 4.
+ * yyinteractive controls whether yyparse should print out
+ * error messages to stderr, and whether or not id's should be
+ * allowed from acl_fromtext().
*/
+int yyinteractive;
+acl_t *yyacl;
+char *yybuf;
-#define ENTRYTYPELEN 14
-#define PERMS 4
-#define ACL_ENTRY_SIZE (ENTRYTYPELEN + LOGNAME_MAX + PERMS)
+extern acl_t *acl_alloc(enum acl_type);
-#define UPDATE_WHERE where = dstr->aclexport + strlen(dstr->aclexport)
struct dynaclstr {
size_t bufsize; /* current size of aclexport */
@@ -72,20 +63,504 @@ static char *strappend(char *, char *);
static char *convert_perm(char *, o_mode_t);
static int increase_length(struct dynaclstr *, size_t);
-static int
-acl_str_to_id(char *str, int *id)
+static void
+aclent_perms(int perm, char *txt_perms)
{
- char *end;
- uid_t value;
+ if (perm & S_IROTH)
+ txt_perms[0] = 'r';
+ else
+ txt_perms[0] = '-';
+ if (perm & S_IWOTH)
+ txt_perms[1] = 'w';
+ else
+ txt_perms[1] = '-';
+ if (perm & S_IXOTH)
+ txt_perms[2] = 'x';
+ else
+ txt_perms[2] = '-';
+ txt_perms[3] = '\0';
+}
- value = strtol(str, &end, 10);
+static char *
+pruname(uid_t uid, char *uidp)
+{
+ struct passwd *passwdp;
- if (errno != 0 || *end != '\0')
- return (EACL_INVALID_USER_GROUP);
+ passwdp = getpwuid(uid);
+ if (passwdp == (struct passwd *)NULL) {
+ /* could not get passwd information: display uid instead */
+ (void) sprintf(uidp, "%ld", (long)uid);
+ return (uidp);
+ } else
+ return (passwdp->pw_name);
+}
- *id = value;
+static char *
+prgname(gid_t gid, char *gidp)
+{
+ struct group *groupp;
- return (0);
+ groupp = getgrgid(gid);
+ if (groupp == (struct group *)NULL) {
+ /* could not get group information: display gid instead */
+ (void) sprintf(gidp, "%ld", (long)gid);
+ return (gidp);
+ } else
+ return (groupp->gr_name);
+}
+static void
+aclent_printacl(acl_t *aclp)
+{
+ aclent_t *tp;
+ int aclcnt;
+ int mask;
+ int slot = 0;
+ char perm[4];
+ char uidp[10];
+ char gidp[10];
+
+ /* display ACL: assume it is sorted. */
+ aclcnt = aclp->acl_cnt;
+ for (tp = aclp->acl_aclp; tp && aclcnt--; tp++) {
+ if (tp->a_type == CLASS_OBJ)
+ mask = tp->a_perm;
+ }
+ aclcnt = aclp->acl_cnt;
+ for (tp = aclp->acl_aclp; aclcnt--; tp++) {
+ (void) printf(" %d:", slot++);
+ switch (tp->a_type) {
+ case USER:
+ aclent_perms(tp->a_perm, perm);
+ (void) printf("user:%s:%s\t\t",
+ pruname(tp->a_id, uidp), perm);
+ aclent_perms((tp->a_perm & mask), perm);
+ (void) printf("#effective:%s\n", perm);
+ break;
+ case USER_OBJ:
+ /* no need to display uid */
+ aclent_perms(tp->a_perm, perm);
+ (void) printf("user::%s\n", perm);
+ break;
+ case GROUP:
+ aclent_perms(tp->a_perm, perm);
+ (void) printf("group:%s:%s\t\t",
+ prgname(tp->a_id, gidp), perm);
+ aclent_perms(tp->a_perm & mask, perm);
+ (void) printf("#effective:%s\n", perm);
+ break;
+ case GROUP_OBJ:
+ aclent_perms(tp->a_perm, perm);
+ (void) printf("group::%s\t\t", perm);
+ aclent_perms(tp->a_perm & mask, perm);
+ (void) printf("#effective:%s\n", perm);
+ break;
+ case CLASS_OBJ:
+ aclent_perms(tp->a_perm, perm);
+ (void) printf("mask:%s\n", perm);
+ break;
+ case OTHER_OBJ:
+ aclent_perms(tp->a_perm, perm);
+ (void) printf("other:%s\n", perm);
+ break;
+ case DEF_USER:
+ aclent_perms(tp->a_perm, perm);
+ (void) printf("default:user:%s:%s\n",
+ pruname(tp->a_id, uidp), perm);
+ break;
+ case DEF_USER_OBJ:
+ aclent_perms(tp->a_perm, perm);
+ (void) printf("default:user::%s\n", perm);
+ break;
+ case DEF_GROUP:
+ aclent_perms(tp->a_perm, perm);
+ (void) printf("default:group:%s:%s\n",
+ prgname(tp->a_id, gidp), perm);
+ break;
+ case DEF_GROUP_OBJ:
+ aclent_perms(tp->a_perm, perm);
+ (void) printf("default:group::%s\n", perm);
+ break;
+ case DEF_CLASS_OBJ:
+ aclent_perms(tp->a_perm, perm);
+ (void) printf("default:mask:%s\n", perm);
+ break;
+ case DEF_OTHER_OBJ:
+ aclent_perms(tp->a_perm, perm);
+ (void) printf("default:other:%s\n", perm);
+ break;
+ default:
+ (void) fprintf(stderr,
+ gettext("unrecognized entry\n"));
+ break;
+ }
+ }
+}
+
+static void
+split_line(char *str, int cols)
+{
+ char *ptr;
+ int len;
+ int i;
+ int last_split;
+ char *pad = "";
+ int pad_len;
+
+ len = strlen(str);
+ ptr = str;
+ pad_len = 0;
+
+ ptr = str;
+ last_split = 0;
+ for (i = 0; i != len; i++) {
+ if ((i + pad_len + 4) >= cols) {
+ (void) printf("%s%.*s\n", pad, last_split, ptr);
+ ptr = &ptr[last_split];
+ len = strlen(ptr);
+ i = 0;
+ pad_len = 4;
+ pad = " ";
+ } else {
+ if (ptr[i] == '/' || ptr[i] == ':') {
+ last_split = i;
+ }
+ }
+ }
+ if (i == len) {
+ (void) printf("%s%s\n", pad, ptr);
+ }
+}
+
+#define OWNERAT_TXT "owner@"
+#define GROUPAT_TXT "group@"
+#define EVERYONEAT_TXT "everyone@"
+#define GROUP_TXT "group:"
+#define USER_TXT "user:"
+
+char *
+ace_type_txt(char *buf, char **endp, ace_t *acep)
+{
+
+ char idp[10];
+
+ if (buf == NULL)
+ return (NULL);
+
+ switch (acep->a_flags & ACE_TYPE_FLAGS) {
+ case ACE_OWNER:
+ strcpy(buf, OWNERAT_TXT);
+ *endp = buf + sizeof (OWNERAT_TXT) - 1;
+ break;
+
+ case ACE_GROUP|ACE_IDENTIFIER_GROUP:
+ strcpy(buf, GROUPAT_TXT);
+ *endp = buf + sizeof (GROUPAT_TXT) - 1;
+ break;
+
+ case ACE_IDENTIFIER_GROUP:
+ strcpy(buf, GROUP_TXT);
+ strcat(buf, prgname(acep->a_who, idp));
+ *endp = buf + strlen(buf);
+ break;
+
+ case ACE_EVERYONE:
+ strcpy(buf, EVERYONEAT_TXT);
+ *endp = buf + sizeof (EVERYONEAT_TXT) - 1;
+ break;
+
+ case 0:
+ strcpy(buf, USER_TXT);
+ strcat(buf, pruname(acep->a_who, idp));
+ *endp = buf + strlen(buf);
+ break;
+ }
+
+ return (buf);
+}
+
+#define READ_DATA_TXT "read_data/"
+#define WRITE_DATA_TXT "write_data/"
+#define EXECUTE_TXT "execute/"
+#define READ_XATTR_TXT "read_xattr/"
+#define WRITE_XATTR_TXT "write_xattr/"
+#define READ_ATTRIBUTES_TXT "read_attributes/"
+#define WRITE_ATTRIBUTES_TXT "write_attributes/"
+#define DELETE_TXT "delete/"
+#define DELETE_CHILD_TXT "delete_child/"
+#define WRITE_OWNER_TXT "write_owner/"
+#define READ_ACL_TXT "read_acl/"
+#define WRITE_ACL_TXT "write_acl/"
+#define APPEND_DATA_TXT "append_data/"
+#define READ_DIR_TXT "list_directory/read_data/"
+#define ADD_DIR_TXT "add_subdirectory/append_data/"
+#define ADD_FILE_TXT "add_file/write_data/"
+#define SYNCHRONIZE_TXT "synchronize" /* not slash on this one */
+
+char *
+ace_perm_txt(char *buf, char **endp, uint32_t mask,
+ uint32_t iflags, int isdir, int flags)
+{
+ char *lend = buf; /* local end */
+
+ if (buf == NULL)
+ return (NULL);
+
+ if (flags & ACL_COMPACT_FMT) {
+
+ if (mask & ACE_READ_DATA)
+ buf[0] = 'r';
+ else
+ buf[0] = '-';
+ if (mask & ACE_WRITE_DATA)
+ buf[1] = 'w';
+ else
+ buf[1] = '-';
+ if (mask & ACE_EXECUTE)
+ buf[2] = 'x';
+ else
+ buf[2] = '-';
+ if (mask & ACE_APPEND_DATA)
+ buf[3] = 'p';
+ else
+ buf[3] = '-';
+ if (mask & ACE_DELETE)
+ buf[4] = 'd';
+ else
+ buf[4] = '-';
+ if (mask & ACE_DELETE_CHILD)
+ buf[5] = 'D';
+ else
+ buf[5] = '-';
+ if (mask & ACE_READ_ATTRIBUTES)
+ buf[6] = 'a';
+ else
+ buf[6] = '-';
+ if (mask & ACE_WRITE_ATTRIBUTES)
+ buf[7] = 'A';
+ else
+ buf[7] = '-';
+ if (mask & ACE_READ_NAMED_ATTRS)
+ buf[8] = 'R';
+ else
+ buf[8] = '-';
+ if (mask & ACE_WRITE_NAMED_ATTRS)
+ buf[9] = 'W';
+ else
+ buf[9] = '-';
+ if (mask & ACE_READ_ACL)
+ buf[10] = 'c';
+ else
+ buf[10] = '-';
+ if (mask & ACE_WRITE_ACL)
+ buf[11] = 'C';
+ else
+ buf[11] = '-';
+ if (mask & ACE_WRITE_OWNER)
+ buf[12] = 'o';
+ else
+ buf[12] = '-';
+ if (mask & ACE_SYNCHRONIZE)
+ buf[13] = 's';
+ else
+ buf[13] = '-';
+ buf[14] = '\0';
+ *endp = buf + 14;
+ return (buf);
+ } else {
+ /*
+ * If ACE is a directory, but inheritance indicates its
+ * for a file then print permissions for file rather than
+ * dir.
+ */
+ if (isdir) {
+ if (mask & ACE_LIST_DIRECTORY) {
+ if (iflags == ACE_FILE_INHERIT_ACE) {
+ strcpy(lend, READ_DATA_TXT);
+ lend += sizeof (READ_DATA_TXT) - 1;
+ } else {
+ strcpy(lend, READ_DIR_TXT);
+ lend += sizeof (READ_DIR_TXT) - 1;
+ }
+ }
+ if (mask & ACE_ADD_FILE) {
+ if (iflags == ACE_FILE_INHERIT_ACE) {
+ strcpy(lend, WRITE_DATA_TXT);
+ lend += sizeof (WRITE_DATA_TXT) - 1;
+ } else {
+ strcpy(lend, ADD_FILE_TXT);
+ lend +=
+ sizeof (ADD_FILE_TXT) -1;
+ }
+ }
+ if (mask & ACE_ADD_SUBDIRECTORY) {
+ if (iflags == ACE_FILE_INHERIT_ACE) {
+ strcpy(lend, APPEND_DATA_TXT);
+ lend += sizeof (APPEND_DATA_TXT) - 1;
+ } else {
+ strcpy(lend, ADD_DIR_TXT);
+ lend += sizeof (ADD_DIR_TXT) - 1;
+ }
+ }
+ } else {
+ if (mask & ACE_READ_DATA) {
+ strcpy(lend, READ_DATA_TXT);
+ lend += sizeof (READ_DATA_TXT) - 1;
+ }
+ if (mask & ACE_WRITE_DATA) {
+ strcpy(lend, WRITE_DATA_TXT);
+ lend += sizeof (WRITE_DATA_TXT) - 1;
+ }
+ if (mask & ACE_APPEND_DATA) {
+ strcpy(lend, APPEND_DATA_TXT);
+ lend += sizeof (APPEND_DATA_TXT) - 1;
+ }
+ }
+ if (mask & ACE_READ_NAMED_ATTRS) {
+ strcpy(lend, READ_XATTR_TXT);
+ lend += sizeof (READ_XATTR_TXT) - 1;
+ }
+ if (mask & ACE_WRITE_NAMED_ATTRS) {
+ strcpy(lend, WRITE_XATTR_TXT);
+ lend += sizeof (WRITE_XATTR_TXT) - 1;
+ }
+ if (mask & ACE_EXECUTE) {
+ strcpy(lend, EXECUTE_TXT);
+ lend += sizeof (EXECUTE_TXT) - 1;
+ }
+ if (mask & ACE_DELETE_CHILD) {
+ strcpy(lend, DELETE_CHILD_TXT);
+ lend += sizeof (DELETE_CHILD_TXT) - 1;
+ }
+ if (mask & ACE_READ_ATTRIBUTES) {
+ strcpy(lend, READ_ATTRIBUTES_TXT);
+ lend += sizeof (READ_ATTRIBUTES_TXT) - 1;
+ }
+ if (mask & ACE_WRITE_ATTRIBUTES) {
+ strcpy(lend, WRITE_ATTRIBUTES_TXT);
+ lend += sizeof (WRITE_ATTRIBUTES_TXT) - 1;
+ }
+ if (mask & ACE_DELETE) {
+ strcpy(lend, DELETE_TXT);
+ lend += sizeof (DELETE_TXT) - 1;
+ }
+ if (mask & ACE_READ_ACL) {
+ strcpy(lend, READ_ACL_TXT);
+ lend += sizeof (READ_ACL_TXT) - 1;
+ }
+ if (mask & ACE_WRITE_ACL) {
+ strcpy(lend, WRITE_ACL_TXT);
+ lend += sizeof (WRITE_ACL_TXT) - 1;
+ }
+ if (mask & ACE_WRITE_OWNER) {
+ strcpy(lend, WRITE_OWNER_TXT);
+ lend += sizeof (WRITE_OWNER_TXT) - 1;
+ }
+ if (mask & ACE_SYNCHRONIZE) {
+ strcpy(lend, SYNCHRONIZE_TXT);
+ lend += sizeof (SYNCHRONIZE_TXT) - 1;
+ }
+
+ if (*(lend - 1) == '/')
+ *--lend = '\0';
+ }
+
+ *endp = lend;
+ return (buf);
+}
+
+#define ALLOW_TXT "allow"
+#define DENY_TXT "deny"
+#define ALARM_TXT "alarm"
+#define AUDIT_TXT "audit"
+#define UNKNOWN_TXT "unknown"
+char *
+ace_access_txt(char *buf, char **endp, int type)
+{
+
+ if (buf == NULL)
+ return (NULL);
+
+ if (type == ACE_ACCESS_ALLOWED_ACE_TYPE) {
+ strcpy(buf, ALLOW_TXT);
+ *endp += sizeof (ALLOW_TXT) - 1;
+ } else if (type == ACE_ACCESS_DENIED_ACE_TYPE) {
+ strcpy(buf, DENY_TXT);
+ *endp += sizeof (DENY_TXT) - 1;
+ } else if (type == ACE_SYSTEM_AUDIT_ACE_TYPE) {
+ strcpy(buf, AUDIT_TXT);
+ *endp += sizeof (AUDIT_TXT) - 1;
+ } else if (type == ACE_SYSTEM_ALARM_ACE_TYPE) {
+ strcpy(buf, ALARM_TXT);
+ *endp += sizeof (ALARM_TXT) - 1;
+ } else {
+ strcpy(buf, UNKNOWN_TXT);
+ *endp += sizeof (UNKNOWN_TXT) - 1;
+ }
+
+ return (buf);
+}
+
+static char *
+ace_inherit_txt(char *buf, char **endp, uint32_t iflags, int flags)
+{
+
+ char *lend = buf;
+
+ if (buf == NULL) {
+ return (NULL);
+ }
+
+ if (flags & ACL_COMPACT_FMT) {
+ if (iflags & ACE_FILE_INHERIT_ACE)
+ buf[0] = 'f';
+ else
+ buf[0] = '-';
+ if (iflags & ACE_DIRECTORY_INHERIT_ACE)
+ buf[1] = 'd';
+ else
+ buf[1] = '-';
+ if (iflags & ACE_INHERIT_ONLY_ACE)
+ buf[2] = 'i';
+ else
+ buf[2] = '-';
+ if (iflags & ACE_NO_PROPAGATE_INHERIT_ACE)
+ buf[3] = 'n';
+ else
+ buf[3] = '-';
+ if (iflags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
+ buf[4] = 'S';
+ else
+ buf[4] = '-';
+ if (iflags & ACE_FAILED_ACCESS_ACE_FLAG)
+ buf[5] = 'F';
+ else
+ buf[5] = '-';
+ buf[6] = '\0';
+ *endp = buf + 6;
+ } else {
+ if (iflags & ACE_FILE_INHERIT_ACE) {
+ strcpy(lend, "file_inherit/");
+ lend += sizeof ("file_inherit/") - 1;
+ }
+ if (iflags & ACE_DIRECTORY_INHERIT_ACE) {
+ strcpy(lend, "dir_inherit/");
+ lend += sizeof ("dir_inherit/") - 1;
+ }
+ if (iflags & ACE_NO_PROPAGATE_INHERIT_ACE) {
+ strcpy(lend, "no_propagate/");
+ lend += sizeof ("no_propagate/") - 1;
+ }
+ if (iflags & ACE_INHERIT_ONLY_ACE) {
+ strcpy(lend, "inherit_only/");
+ lend += sizeof ("inherit_only/") - 1;
+ }
+
+ if (*(lend - 1) == '/')
+ *--lend = '\0';
+ *endp = lend;
+ }
+
+ return (buf);
}
/*
@@ -99,8 +574,29 @@ acl_str_to_id(char *str, int *id)
* The LOGNAME_MAX, ENTRYTYPELEN and PERMS limits are otherwise always
* adhered to.
*/
+
+/*
+ * acltotext() converts each ACL entry to look like this:
+ *
+ * entry_type:uid^gid^name:perms[:id]
+ *
+ * The maximum length of entry_type is 14 ("defaultgroup::" and
+ * "defaultother::") hence ENTRYTYPELEN is set to 14.
+ *
+ * The max length of a uid^gid^name entry (in theory) is 8, hence we use,
+ * however the ID could be a number so we therefore use ID_STR_MAX
+ *
+ * The length of a perms entry is 4 to allow for the comma appended to each
+ * to each acl entry. Hence PERMS is set to 4.
+ */
+
+#define ENTRYTYPELEN 14
+#define PERMS 4
+#define ACL_ENTRY_SIZE (ENTRYTYPELEN + ID_STR_MAX + PERMS + APPENDED_ID_MAX)
+#define UPDATE_WHERE where = dstr->aclexport + strlen(dstr->aclexport)
+
char *
-acltotext(aclent_t *aclp, int aclcnt)
+aclent_acltotext(aclent_t *aclp, int aclcnt, int flags)
{
char *aclexport;
char *where;
@@ -109,6 +605,7 @@ acltotext(aclent_t *aclp, int aclcnt)
struct dynaclstr *dstr;
int i, rtn;
size_t excess = 0;
+ char id[20], *idstr;
if (aclp == NULL)
return (NULL);
@@ -218,241 +715,34 @@ acltotext(aclent_t *aclp, int aclcnt)
return (NULL);
}
+
+ if ((flags & ACL_APPEND_ID) && ((aclp->a_type == USER) ||
+ (aclp->a_type == DEF_USER) || (aclp->a_type == GROUP) ||
+ (aclp->a_type == DEF_GROUP))) {
+ where = strappend(where, ":");
+ id[ID_STR_MAX - 1] = '\0'; /* null terminate buffer */
+ idstr = lltostr(aclp->a_id, &id[ID_STR_MAX - 1]);
+ where = strappend(where, idstr);
+ }
if (i < aclcnt - 1)
where = strappend(where, ",");
}
aclexport = dstr->aclexport;
free(dstr);
return (aclexport);
-}
-
-/*
- * 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.
- */
-static int
-aclent_aclfromtext(char *aclstr, acl_t **ret_aclp)
-{
- char *fieldp;
- char *tp;
- char *nextp;
- char *allocp;
- char *aclimport;
- int entry_type;
- int id;
- int len;
- int error;
- o_mode_t perm;
- aclent_t *tmpaclp;
- acl_t *aclp;
- struct group *groupp;
- struct passwd *passwdp;
-
- 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) {
- 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 = (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);
- acl_free(aclp);
- return (EACL_MEM_ERROR);
- }
- 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(allocp);
- if (aclp)
- acl_free(aclp);
- return (EACL_ENTRY_ERROR);
- } else
- *tp = '\0';
- if (strcmp(aclimport, "user") == 0) {
- if (*(tp+1) == ':')
- entry_type = USER_OBJ;
- else
- entry_type = USER;
- } else if (strcmp(aclimport, "group") == 0) {
- if (*(tp+1) == ':')
- entry_type = GROUP_OBJ;
- else
- entry_type = GROUP;
- } else if (strcmp(aclimport, "other") == 0)
- entry_type = OTHER_OBJ;
- else if (strcmp(aclimport, "mask") == 0)
- entry_type = CLASS_OBJ;
- else if (strcmp(aclimport, "defaultuser") == 0) {
- if (*(tp+1) == ':')
- entry_type = DEF_USER_OBJ;
- else
- entry_type = DEF_USER;
- } else if (strcmp(aclimport, "defaultgroup") == 0) {
- if (*(tp+1) == ':')
- entry_type = DEF_GROUP_OBJ;
- else
- entry_type = DEF_GROUP;
- } else if (strcmp(aclimport, "defaultmask") == 0)
- entry_type = DEF_CLASS_OBJ;
- else if (strcmp(aclimport, "defaultother") == 0)
- entry_type = DEF_OTHER_OBJ;
- else {
- free(allocp);
- acl_free(aclp);
- return (EACL_ENTRY_ERROR);
- }
-
- /* look for user/group name */
- if (entry_type != CLASS_OBJ && entry_type != OTHER_OBJ &&
- entry_type != DEF_CLASS_OBJ &&
- entry_type != DEF_OTHER_OBJ) {
- 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 == USER ||
- entry_type == DEF_USER) {
- /*
- * 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 == GROUP ||
- entry_type == DEF_GROUP) {
- groupp = getgrnam(fieldp);
- if (groupp == NULL) {
- error = acl_str_to_id(
- fieldp, &id);
- }
- if (error == 0)
- id = groupp->gr_gid;
- }
- if (error) {
- free(allocp);
- acl_free(aclp);
- return (error);
- }
- }
- } else {
- /*
- * The second field is empty.
- * Treat it as undefined (-1)
- */
- id = -1;
- }
- } else {
- /*
- * Let's not break the old applications
- * that use mask::rwx, other::rwx format,
- * though they violate the man pages.
- */
- if (*(tp + 1) == ':')
- *++tp = 0;
- }
- /* next field: permission */
- fieldp = tp + 1;
- if (strlen(fieldp) != 3) {
- /* not "rwx" format */
- free(allocp);
- acl_free(aclp);
- return (EACL_PERM_MASK_ERROR);
- } else {
- char s[] = "rwx";
- int mask = 0x04;
- int i;
- perm = 0;
-
- for (i = 0; i < 3; i++, mask /= 2) {
- if (fieldp[i] == s[i])
- perm |= mask;
- else if (fieldp[i] != '-') {
- free(allocp);
- acl_free(aclp);
- return (EACL_PERM_MASK_ERROR);
- }
- }
- }
+}
- tmpaclp->a_type = entry_type;
- tmpaclp->a_id = id;
- tmpaclp->a_perm = perm;
- aclimport = nextp;
- }
- free(allocp);
- *ret_aclp = aclp;
- return (0);
+char *
+acltotext(aclent_t *aclp, int aclcnt)
+{
+ return (aclent_acltotext(aclp, aclcnt, 0));
}
+
aclent_t *
aclfromtext(char *aclstr, int *aclcnt)
{
@@ -460,15 +750,15 @@ aclfromtext(char *aclstr, int *aclcnt)
aclent_t *aclentp;
int error;
- error = aclent_aclfromtext(aclstr, &aclp);
+ error = acl_fromtext(aclstr, &aclp);
if (error)
return (NULL);
aclentp = aclp->acl_aclp;
aclp->acl_aclp = NULL;
- acl_free(aclp);
-
*aclcnt = aclp->acl_cnt;
+
+ acl_free(aclp);
return (aclentp);
}
@@ -483,15 +773,15 @@ strappend(char *where, char *newstr)
static char *
convert_perm(char *where, o_mode_t perm)
{
- if (perm & 04)
+ if (perm & S_IROTH)
where = strappend(where, "r");
else
where = strappend(where, "-");
- if (perm & 02)
+ if (perm & S_IWOTH)
where = strappend(where, "w");
else
where = strappend(where, "-");
- if (perm & 01)
+ if (perm & S_IXOTH)
where = strappend(where, "x");
else
where = strappend(where, "-");
@@ -499,129 +789,6 @@ 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.
@@ -643,14 +810,14 @@ increase_length(struct dynaclstr *dacl, size_t increase)
}
/*
- * ace_acltotext() conver each ace formatted acl to look like this:
+ * ace_acltotext() convert each ace formatted acl to look like this:
*
- * entry_type:uid^gid^name:perms:allow^deny[:flags][,]
+ * entry_type:uid^gid^name:perms[:flags]:<allow|deny>[:id][,]
*
* 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 max length of a uid^gid^name entry (in theory) is 8,
+ * however id could be a number so we therefore use ID_STR_MAX
*
* The length of a perms entry is 144 i.e read_data/write_data...
* to each acl entry.
@@ -661,517 +828,397 @@ increase_length(struct dynaclstr *dacl, size_t increase)
#define ACE_ENTRYTYPLEN 6
#define IFLAGS_SIZE 51
-#define ACCESS_TYPE_SIZE 5
+#define ACCESS_TYPE_SIZE 7 /* if unknown */
#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)
+#define ACE_ENTRY_SIZE (ACE_ENTRYTYPLEN + ID_STR_MAX + PERMS_LEN +\
+ ACCESS_TYPE_SIZE + IFLAGS_SIZE + COLON_CNT + APPENDED_ID_MAX)
static char *
-ace_acltotext(acl_t *aceaclp)
+ace_acltotext(acl_t *aceaclp, int flags)
{
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;
+ char *endp;
+ int i;
+ char id[ID_STR_MAX], *idstr;
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)
+ if ((aclexport = malloc(aclcnt * ACE_ENTRY_SIZE)) == NULL)
return (NULL);
- *dstr->aclexport = '\0';
- where = dstr->aclexport;
+ aclexport[0] = '\0';
+ endp = 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);
+ (void) ace_type_txt(endp, &endp, aclp);
+ *endp++ = ':';
+ *endp = '\0';
+ (void) ace_perm_txt(endp, &endp, aclp->a_access_mask,
+ aclp->a_flags, isdir, flags);
+ *endp++ = ':';
+ *endp = '\0';
+ (void) ace_inherit_txt(endp, &endp, aclp->a_flags, flags);
+ if (flags & ACL_COMPACT_FMT || aclp->a_flags &
+ (ACE_FILE_INHERIT_ACE | ACE_DIRECTORY_INHERIT_ACE |
+ (ACE_INHERIT_ONLY_ACE | ACE_NO_PROPAGATE_INHERIT_ACE))) {
+ *endp++ = ':';
+ *endp = '\0';
}
- 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);
- }
+ (void) ace_access_txt(endp, &endp, aclp->a_type);
+
+ if ((flags & ACL_APPEND_ID) &&
+ (((aclp->a_flags & ACE_TYPE_FLAGS) == 0) ||
+ ((aclp->a_flags & ACE_TYPE_FLAGS) ==
+ ACE_IDENTIFIER_GROUP))) {
+ *endp++ = ':';
+ *endp = '\0';
+ id[ID_STR_MAX -1] = '\0'; /* null terminate buffer */
+ idstr = lltostr(aclp->a_who, &id[ID_STR_MAX - 1]);
+ strcpy(endp, idstr);
+ endp += strlen(idstr);
+ }
+ if (i < aclcnt - 1) {
+ *endp++ = ',';
+ *(endp + 1) = '\0';
}
- if (i < aclcnt - 1)
- where = strappend(where, ",");
}
- aclexport = dstr->aclexport;
- free(dstr);
return (aclexport);
}
-static int
-build_iflags(char *str, int *iflags)
+char *
+acl_totext(acl_t *aclp, int flags)
{
- char *tok;
- *iflags = 0;
+ char *txtp;
- tok = strtok(str, "/");
+ if (aclp == NULL)
+ return (NULL);
- if (tok == NULL)
- return (1);
+ switch (aclp->acl_type) {
+ case ACE_T:
+ txtp = ace_acltotext(aclp, flags);
+ break;
+ case ACLENT_T:
+ txtp = aclent_acltotext(aclp->acl_aclp, aclp->acl_cnt, flags);
+ break;
+ }
- 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);
+ return (txtp);
}
-/*
- * 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
+acl_fromtext(const char *acltextp, acl_t **ret_aclp)
+{
+ int error;
+ char *buf;
+
+ buf = malloc(strlen(acltextp) + 2);
+ if (buf == NULL)
+ return (EACL_MEM_ERROR);
+ strcpy(buf, acltextp);
+ strcat(buf, "\n");
+ yybuf = buf;
+ yyreset();
+ error = yyparse();
+ free(buf);
+
+ if (yyacl) {
+ if (error == 0)
+ *ret_aclp = yyacl;
+ else {
+ acl_free(yyacl);
+ }
+ yyacl = NULL;
+ }
+ return (error);
+}
int
-ace_aclfromtext(char *aclstr, acl_t **ret_aclp)
+acl_parse(const char *acltextp, acl_t **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;
+ int error;
- if (! aclstr)
- return (EACL_INVALID_STR);
+ yyinteractive = 1;
+ error = acl_fromtext(acltextp, aclp);
+ yyinteractive = 0;
+ return (error);
+}
- len = strlen(aclstr);
+static void
+ace_compact_printacl(acl_t *aclp)
+{
+ int cnt;
+ ace_t *acep;
+ char *endp;
+ char buf[ACE_ENTRY_SIZE];
+
+ for (cnt = 0, acep = aclp->acl_aclp;
+ cnt != aclp->acl_cnt; cnt++, acep++) {
+ buf[0] = '\0';
+ (void) printf(" %14s:", ace_type_txt(buf, &endp, acep));
+ (void) printf("%s:", ace_perm_txt(endp, &endp,
+ acep->a_access_mask, acep->a_flags,
+ aclp->acl_flags & ACL_IS_DIR, ACL_COMPACT_FMT));
+ (void) printf("%s:",
+ ace_inherit_txt(endp, &endp, acep->a_flags,
+ ACL_COMPACT_FMT));
+ (void) printf("%s\n", ace_access_txt(endp, &endp,
+ acep->a_type));
+ }
+}
- aclp = acl_alloc(ACE_T);
- if (aclp == NULL) {
- return (EACL_MEM_ERROR);
+static void
+ace_printacl(acl_t *aclp, int cols, int compact)
+{
+ int slot = 0;
+ char *token;
+ char *acltext;
+
+ if (compact) {
+ ace_compact_printacl(aclp);
+ return;
}
- *ret_aclp = NULL;
+ acltext = acl_totext(aclp, 0);
- if ((aclimport = allocp = strdup(aclstr)) == NULL) {
- return (EACL_MEM_ERROR);
+ if (acltext == NULL)
+ return;
+
+ token = strtok(acltext, ",");
+ if (token == NULL) {
+ free(acltext);
+ return;
}
+ do {
+ (void) printf(" %d:", slot++);
+ split_line(token, cols - 5);
+ } while (token = strtok(NULL, ","));
+ free(acltext);
+}
- if (aclimport[len - 1] == ',')
- aclimport[len - 1] = '\0';
+/*
+ * pretty print an ACL.
+ * For aclent_t ACL's the format is
+ * similar to the old format used by getfacl,
+ * with the addition of adding a "slot" number
+ * before each entry.
+ *
+ * for ace_t ACL's the cols variable will break up
+ * the long lines into multiple lines and will also
+ * print a "slot" number.
+ */
+void
+acl_printacl(acl_t *aclp, int cols, int compact)
+{
- for (; aclimport; ) {
- /* look for an ACL entry */
- tp = strchr(aclimport, ',');
- if (tp == NULL) {
- nextp = NULL;
- } else {
- *tp = '\0';
- nextp = tp + 1;
- }
+ switch (aclp->acl_type) {
+ case ACLENT_T:
+ aclent_printacl(aclp);
+ break;
+ case ACE_T:
+ ace_printacl(aclp, cols, compact);
+ break;
+ }
+}
- aclp->acl_cnt += 1;
+typedef struct value_table {
+ char p_letter; /* perm letter such as 'r' */
+ uint32_t p_value; /* value for perm when pletter found */
+} value_table_t;
- /*
- * 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);
- }
+#define ACE_PERM_COUNT 14
- /*
- * If not an abstraction owner@, group@ or everyone@
- * then we must have a user/group name next
- */
+/*
+ * The permission tables are layed out in positional order
+ * a '-' character will indicate a permission at a given
+ * position is not specified. The '-' is not part of the
+ * table, but will be checked for in the permission computation
+ * routine.
+ */
+value_table_t ace_perm_table[ACE_PERM_COUNT] = {
+ { 'r', ACE_READ_DATA},
+ { 'w', ACE_WRITE_DATA},
+ { 'x', ACE_EXECUTE},
+ { 'p', ACE_APPEND_DATA},
+ { 'd', ACE_DELETE},
+ { 'D', ACE_DELETE_CHILD},
+ { 'a', ACE_READ_ATTRIBUTES},
+ { 'A', ACE_WRITE_ATTRIBUTES},
+ { 'R', ACE_READ_NAMED_ATTRS},
+ { 'W', ACE_WRITE_NAMED_ATTRS},
+ { 'c', ACE_READ_ACL},
+ { 'C', ACE_WRITE_ACL},
+ { 'o', ACE_WRITE_OWNER},
+ { 's', ACE_SYNCHRONIZE}
+};
- 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;
- }
+#define ACLENT_PERM_COUNT 3
- 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;
- }
+value_table_t aclent_perm_table[ACLENT_PERM_COUNT] = {
+ { 'r', S_IROTH},
+ { 'w', S_IWOTH},
+ { 'x', S_IXOTH}
+};
- if (error) {
- free(allocp);
- acl_free(aclp);
- return (error);
- }
- }
- }
- } else {
- id = -1;
- }
+#define IFLAG_COUNT 6
+value_table_t inherit_table[IFLAG_COUNT] = {
+ {'f', ACE_FILE_INHERIT_ACE},
+ {'d', ACE_DIRECTORY_INHERIT_ACE},
+ {'i', ACE_INHERIT_ONLY_ACE},
+ {'n', ACE_NO_PROPAGATE_INHERIT_ACE},
+ {'S', ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
+ {'F', ACE_FAILED_ACCESS_ACE_FLAG}
+};
- /* 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, "/"));
- }
+/*
+ * compute value from a permission table or inheritance table
+ * based on string passed in. If positional is set then
+ * string must match order in permtab, otherwise any order
+ * is allowed.
+ */
+int
+compute_values(value_table_t *permtab, int count,
+ char *permstr, int positional, uint32_t *mask)
+{
+ uint32_t perm_val = 0;
+ char *pstr;
+ int i, found;
- /* grab allow/deny */
- fieldp = tp + 1;
- tp = strchr(fieldp, ':');
- if (tp != NULL)
- *tp = '\0';
+ if (count < 0)
+ return (1);
- 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);
+ if (positional) {
+ for (i = 0, pstr = permstr; i != count && pstr &&
+ *pstr; i++, pstr++) {
+ if (*pstr == permtab[i].p_letter) {
+ perm_val |= permtab[i].p_value;
+ } else if (*pstr != '-') {
+ return (1);
+ }
}
-
- /* 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 { /* random order single letters with no '-' */
+ for (pstr = permstr; pstr && *pstr; pstr++) {
+ for (found = 0, i = 0; i != count; i++) {
+ if (*pstr == permtab[i].p_letter) {
+ perm_val |= permtab[i].p_value;
+ found = 1;
+ break;
}
- } else {
- free(allocp);
- acl_free(aclp);
- return (EACL_UNKNOWN_DATA);
}
+ if (found == 0)
+ return (1);
}
- /* 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;
+
+ *mask = perm_val;
return (0);
}
-char
-*acl_totext(acl_t *aclp)
+/*
+ * compute value for inheritance flags.
+ */
+int
+compute_ace_inherit(char *str, uint32_t *imask)
{
- if (aclp == NULL)
- return (NULL);
+ int error;
+ int positional = 0;
- switch (aclp->acl_type) {
- case ACE_T:
- return (ace_acltotext(aclp));
- case ACLENT_T:
- return (acltotext(aclp->acl_aclp, aclp->acl_cnt));
- }
- return (NULL);
+ if (strlen(str) == IFLAG_COUNT)
+ positional = 1;
+
+ error = compute_values(inherit_table, IFLAG_COUNT,
+ str, positional, imask);
+
+ if (error)
+ return (EACL_INHERIT_ERROR);
+
+ return (error);
}
+
+/*
+ * compute value for ACE permissions.
+ */
int
-acl_fromtext(const char *acltextp, acl_t **ret_aclp)
+compute_ace_perms(char *str, uint32_t *mask)
{
- acl_t *aclp;
- char *token;
- char *ptr;
- char *textp;
- enum acl_type flavor;
- int colon_cnt = 0;
+ int positional = 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);
- }
+ if (strlen(str) == ACE_PERM_COUNT)
+ positional = 1;
- for (ptr = token; *ptr; ptr++) {
- if (*ptr == ':')
- colon_cnt++;
- }
+ error = compute_values(ace_perm_table, ACE_PERM_COUNT,
+ str, positional, mask);
- 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);
+ if (error && positional) {
+ /*
+ * If positional was set, then make sure permissions
+ * aren't actually valid in non positional case where
+ * all permissions are specified, just in random order.
+ */
+ error = compute_values(ace_perm_table,
+ ACE_PERM_COUNT, str, 0, mask);
}
+ if (error)
+ error = EACL_PERM_MASK_ERROR;
+ return (error);
+}
- free(textp);
- if (flavor == ACLENT_T)
- error = aclent_aclfromtext((char *)acltextp, &aclp);
- else
- error = ace_aclfromtext((char *)acltextp, &aclp);
- *ret_aclp = aclp;
+/*
+ * compute values for aclent permissions.
+ */
+int
+compute_aclent_perms(char *str, o_mode_t *mask)
+{
+ int error;
+ uint32_t pmask;
+
+ if (strlen(str) != ACLENT_PERM_COUNT)
+ return (EACL_PERM_MASK_ERROR);
+
+ *mask = 0;
+ error = compute_values(aclent_perm_table, ACLENT_PERM_COUNT,
+ str, 1, &pmask);
+ if (error == 0) {
+ *mask = (o_mode_t)pmask;
+ } else
+ error = EACL_PERM_MASK_ERROR;
return (error);
}
+
+/*
+ * determine ACE permissions.
+ */
+int
+ace_perm_mask(struct acl_perm_type *aclperm, uint32_t *mask)
+{
+ int error;
+
+ if (aclperm->perm_style == PERM_TYPE_EMPTY) {
+ *mask = 0;
+ return (0);
+ }
+
+ if (aclperm->perm_style == PERM_TYPE_ACE) {
+ *mask = aclperm->perm_val;
+ return (0);
+ }
+
+ error = compute_ace_perms(aclperm->perm_str, mask);
+ if (error) {
+ acl_error(gettext("Invalid permission(s) '%s' specified\n"),
+ aclperm->perm_str);
+ return (EACL_PERM_MASK_ERROR);
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/libsec/common/aclutils.c b/usr/src/lib/libsec/common/aclutils.c
index 700cefa9a9..e3f651e641 100644
--- a/usr/src/lib/libsec/common/aclutils.c
+++ b/usr/src/lib/libsec/common/aclutils.c
@@ -36,6 +36,7 @@
#include <sys/acl.h>
#include <errno.h>
#include <sys/stat.h>
+#include <sys/varargs.h>
#include <locale.h>
#include <aclutils.h>
#include <acl_common.h>
@@ -1136,226 +1137,6 @@ acl_addentries(acl_t *acl1, acl_t *acl2, int where)
return (0);
}
-static void
-aclent_perms(int perm, char *txt_perms)
-{
- if (perm & S_IROTH)
- txt_perms[0] = 'r';
- else
- txt_perms[0] = '-';
- if (perm & S_IWOTH)
- txt_perms[1] = 'w';
- else
- txt_perms[1] = '-';
- if (perm & S_IXOTH)
- txt_perms[2] = 'x';
- else
- txt_perms[2] = '-';
- txt_perms[3] = '\0';
-}
-
-static char *
-pruname(uid_t uid)
-{
- struct passwd *passwdp;
- static char uidp[10]; /* big enough */
-
- passwdp = getpwuid(uid);
- if (passwdp == (struct passwd *)NULL) {
- /* could not get passwd information: display uid instead */
- (void) sprintf(uidp, "%ld", (long)uid);
- return (uidp);
- } else
- return (passwdp->pw_name);
-}
-
-static char *
-prgname(gid_t gid)
-{
- struct group *groupp;
- static char gidp[10]; /* big enough */
-
- groupp = getgrgid(gid);
- if (groupp == (struct group *)NULL) {
- /* could not get group information: display gid instead */
- (void) sprintf(gidp, "%ld", (long)gid);
- return (gidp);
- } else
- return (groupp->gr_name);
-}
-static void
-aclent_printacl(acl_t *aclp)
-{
- aclent_t *tp;
- int aclcnt;
- int mask;
- int slot = 0;
- char perm[4];
-
- /* display ACL: assume it is sorted. */
- aclcnt = aclp->acl_cnt;
- for (tp = aclp->acl_aclp; aclcnt--; tp++) {
- if (tp->a_type == CLASS_OBJ)
- mask = tp->a_perm;
- }
- aclcnt = aclp->acl_cnt;
- for (tp = aclp->acl_aclp; aclcnt--; tp++) {
- (void) printf(" %d:", slot++);
- switch (tp->a_type) {
- case USER:
- aclent_perms(tp->a_perm, perm);
- (void) printf("user:%s:%s\t\t",
- pruname(tp->a_id), perm);
- aclent_perms((tp->a_perm & mask), perm);
- (void) printf("#effective:%s\n", perm);
- break;
- case USER_OBJ:
- /* no need to display uid */
- aclent_perms(tp->a_perm, perm);
- (void) printf("user::%s\n", perm);
- break;
- case GROUP:
- aclent_perms(tp->a_perm, perm);
- (void) printf("group:%s:%s\t\t",
- prgname(tp->a_id), perm);
- aclent_perms(tp->a_perm & mask, perm);
- (void) printf("#effective:%s\n", perm);
- break;
- case GROUP_OBJ:
- aclent_perms(tp->a_perm, perm);
- (void) printf("group::%s\t\t", perm);
- aclent_perms(tp->a_perm & mask, perm);
- (void) printf("#effective:%s\n", perm);
- break;
- case CLASS_OBJ:
- aclent_perms(tp->a_perm, perm);
- (void) printf("mask:%s\n", perm);
- break;
- case OTHER_OBJ:
- aclent_perms(tp->a_perm, perm);
- (void) printf("other:%s\n", perm);
- break;
- case DEF_USER:
- aclent_perms(tp->a_perm, perm);
- (void) printf("default:user:%s:%s\n",
- pruname(tp->a_id), perm);
- break;
- case DEF_USER_OBJ:
- aclent_perms(tp->a_perm, perm);
- (void) printf("default:user::%s\n", perm);
- break;
- case DEF_GROUP:
- aclent_perms(tp->a_perm, perm);
- (void) printf("default:group:%s:%s\n",
- prgname(tp->a_id), perm);
- break;
- case DEF_GROUP_OBJ:
- aclent_perms(tp->a_perm, perm);
- (void) printf("default:group::%s\n", perm);
- break;
- case DEF_CLASS_OBJ:
- aclent_perms(tp->a_perm, perm);
- (void) printf("default:mask:%s\n", perm);
- break;
- case DEF_OTHER_OBJ:
- aclent_perms(tp->a_perm, perm);
- (void) printf("default:other:%s\n", perm);
- break;
- default:
- (void) fprintf(stderr,
- gettext("unrecognized entry\n"));
- break;
- }
- }
-}
-
-static void
-split_line(char *str, int cols)
-{
- char *ptr;
- int len;
- int i;
- int last_split;
- char pad[11];
- int pad_len;
-
- len = strlen(str);
- ptr = str;
- (void) strcpy(pad, "");
- pad_len = 0;
-
- ptr = str;
- last_split = 0;
- for (i = 0; i != len; i++) {
- if ((i + pad_len + 4) >= cols) {
- (void) printf("%s%.*s\n", pad, last_split, ptr);
- ptr = &ptr[last_split];
- len = strlen(ptr);
- i = 0;
- pad_len = 4;
- (void) strcpy(pad, " ");
- } else {
- if (ptr[i] == '/' || ptr[i] == ':') {
- last_split = i;
- }
- }
- }
- if (i == len) {
- (void) printf("%s%s\n", pad, ptr);
- }
-}
-
-static void
-ace_printacl(acl_t *aclp, int cols)
-{
- int slot = 0;
- char *token;
- char *acltext;
-
- acltext = acl_totext(aclp);
-
- if (acltext == NULL)
- return;
-
- token = strtok(acltext, ",");
- if (token == NULL) {
- free(acltext);
- return;
- }
-
- do {
- (void) printf(" %d:", slot++);
- split_line(token, cols - 5);
- } while (token = strtok(NULL, ","));
- free(acltext);
-}
-
-/*
- * pretty print an ACL.
- * For aclent_t ACL's the format is
- * similar to the old format used by getfacl,
- * with the addition of adding a "slot" number
- * before each entry.
- *
- * for ace_t ACL's the cols variable will break up
- * the long lines into multiple lines and will also
- * print a "slot" number.
- */
-void
-acl_printacl(acl_t *aclp, int cols)
-{
-
- switch (aclp->acl_type) {
- case ACLENT_T:
- aclent_printacl(aclp);
- break;
- case ACE_T:
- ace_printacl(aclp, cols);
- break;
- }
-}
-
-
/*
* return text for an ACL error.
*/
@@ -1365,10 +1146,10 @@ acl_strerror(int errnum)
switch (errnum) {
case EACL_GRP_ERROR:
return (dgettext(TEXT_DOMAIN,
- "There is more than one user group owner entry"));
+ "There is more than one group or default group entry"));
case EACL_USER_ERROR:
return (dgettext(TEXT_DOMAIN,
- "There is more than one user owner entry"));
+ "There is more than one user or default user entry"));
case EACL_OTHER_ERROR:
return (dgettext(TEXT_DOMAIN,
"There is more than one other entry"));
@@ -1431,3 +1212,19 @@ acl_strerror(int errnum)
return (dgettext(TEXT_DOMAIN, "Unknown error"));
}
}
+
+extern int yyinteractive;
+
+/* PRINTFLIKE1 */
+void
+acl_error(const char *fmt, ...)
+{
+ va_list va;
+
+ if (yyinteractive == 0)
+ return;
+
+ va_start(va, fmt);
+ (void) vfprintf(stderr, fmt, va);
+ va_end(va);
+}
diff --git a/usr/src/lib/libsec/common/aclutils.h b/usr/src/lib/libsec/common/aclutils.h
index b8e95dfe80..80a6e98c96 100644
--- a/usr/src/lib/libsec/common/aclutils.h
+++ b/usr/src/lib/libsec/common/aclutils.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -30,6 +30,11 @@
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
+#include <strings.h>
+#include <locale.h>
+#include <ctype.h>
+#include <grp.h>
+#include <pwd.h>
#ifdef __cplusplus
extern "C" {
@@ -67,16 +72,41 @@ struct acl_info {
};
+#define PERM_TYPE_ACE 0x1 /* permissions are of ACE type */
+#define PERM_TYPE_UNKNOWN 0x2 /* permission type not yet known */
+#define PERM_TYPE_EMPTY 0x4 /* no permissions are specified */
+
+struct acl_perm_type {
+ int perm_style; /* type of perm style, see above */
+ char *perm_str; /* string value being returned */
+ uint32_t perm_val; /* numeric value being returned */
+};
+
+extern char *yybuf;
+extern acl_t *yyacl;
+
+extern int yyerror(const char *);
+extern int get_id(int entry_type, char *name, int *id);
+extern int ace_entry_type(int entry_type);
+extern int aclent_entry_type(int type, int owning, int *ret);
+extern int ace_perm_mask(struct acl_perm_type *, uint32_t *mask);
+extern int compute_aclent_perms(char *str, o_mode_t *mask);
+extern int compute_ace_inherit(char *str, uint32_t *imask);
extern int acl_addentries(acl_t *, acl_t *, int);
extern int acl_removeentries(acl_t *, acl_t *, int, int);
extern int acl_modifyentries(acl_t *, acl_t *, int);
-extern void acl_printacl(acl_t *, int);
+extern void acl_printacl(acl_t *, int, int);
extern char *acl_strerror(int);
extern acl_t *acl_dup(acl_t *);
extern int acl_type(acl_t *);
extern int acl_cnt(acl_t *);
extern int acl_flags(acl_t *);
extern void *acl_data(acl_t *);
+extern void acl_error(const char *, ...);
+extern int acl_parse(const char *, acl_t **);
+extern int yyparse(void);
+extern void yyreset(void);
+extern acl_t *acl_alloc(enum acl_type);
#ifdef __cplusplus
}
diff --git a/usr/src/lib/libsec/spec/acl.spec b/usr/src/lib/libsec/spec/acl.spec
index afedf74f34..cf58a04504 100644
--- a/usr/src/lib/libsec/spec/acl.spec
+++ b/usr/src/lib/libsec/spec/acl.spec
@@ -1,5 +1,5 @@
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# CDDL HEADER START
@@ -136,7 +136,7 @@ end
function acl_totext
include <sys/acl.h>
-declaration char *acl_totext(acl_t *acl);
+declaration char *acl_totext(acl_t *acl, int flags);
version SUNW_1.2
exception $return == 0
end
@@ -167,7 +167,7 @@ end
function acl_printacl
include <sys/acl.h>
-declaration void acl_printacl(acl_t *aclp, int cols);
+declaration void acl_printacl(acl_t *aclp, int cols, int compact);
version SUNWprivate_1.1
end
@@ -219,3 +219,15 @@ include <aclutils.h>
declaration void *acl_data(acl_t *);
version SUNWprivate_1.1
end
+
+function acl_error
+include <aclutils.h>
+declaration void acl_error(const char *, ...)
+version SUNWprivate_1.1
+end
+
+function acl_parse
+include <aclutils.h>
+declaration void acl_parse(char *textp, acl_t **);
+version SUNWprivate_1.1
+end
diff --git a/usr/src/uts/common/sys/acl.h b/usr/src/uts/common/sys/acl.h
index 7c34d88753..503b1ddf00 100644
--- a/usr/src/uts/common/sys/acl.h
+++ b/usr/src/uts/common/sys/acl.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -126,6 +126,8 @@ typedef struct acl_info acl_t;
ACE_INHERIT_ONLY_ACE | \
ACE_IDENTIFIER_GROUP)
+#define ACE_TYPE_FLAGS (ACE_OWNER|ACE_GROUP|ACE_EVERYONE|ACE_IDENTIFIER_GROUP)
+
/* cmd args to acl(2) for aclent_t */
#define GETACL 1
#define SETACL 2
@@ -167,6 +169,14 @@ typedef struct acl_info acl_t;
*/
#define ACL_NO_TRIVIAL 0x2
+
+/*
+ * Flags to control acl_totext()
+ */
+
+#define ACL_APPEND_ID 0x1 /* append uid/gid to user/group entries */
+#define ACL_COMPACT_FMT 0x2 /* build ACL in ls -V format */
+
/*
* Legacy aclcheck errors for aclent_t ACLs
*/
@@ -210,7 +220,7 @@ extern int acl_set(const char *, acl_t *acl);
extern int facl_set(int, acl_t *acl);
extern int acl_strip(const char *, uid_t, gid_t, mode_t);
extern int acl_trivial(const char *);
-extern char *acl_totext(acl_t *);
+extern char *acl_totext(acl_t *, int);
extern int acl_fromtext(const char *, acl_t **);
extern int acl_check(acl_t *, int);