diff options
Diffstat (limited to 'usr/src')
| -rw-r--r-- | usr/src/cmd/bart/create.c | 4 | ||||
| -rw-r--r-- | usr/src/cmd/chmod/chmod.c | 8 | ||||
| -rw-r--r-- | usr/src/cmd/cmd-inet/usr.bin/rcp.c | 4 | ||||
| -rw-r--r-- | usr/src/cmd/cpio/cpio.c | 2 | ||||
| -rw-r--r-- | usr/src/cmd/ls/ls.c | 17 | ||||
| -rw-r--r-- | usr/src/cmd/tar/tar.c | 3 | ||||
| -rw-r--r-- | usr/src/lib/libsec/Makefile | 6 | ||||
| -rw-r--r-- | usr/src/lib/libsec/Makefile.com | 19 | ||||
| -rw-r--r-- | usr/src/lib/libsec/common/acl.y | 484 | ||||
| -rw-r--r-- | usr/src/lib/libsec/common/acl_lex.l | 719 | ||||
| -rw-r--r-- | usr/src/lib/libsec/common/acltext.c | 1693 | ||||
| -rw-r--r-- | usr/src/lib/libsec/common/aclutils.c | 241 | ||||
| -rw-r--r-- | usr/src/lib/libsec/common/aclutils.h | 34 | ||||
| -rw-r--r-- | usr/src/lib/libsec/spec/acl.spec | 18 | ||||
| -rw-r--r-- | usr/src/uts/common/sys/acl.h | 14 |
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); |
