diff options
Diffstat (limited to 'usr/src')
90 files changed, 2689 insertions, 2167 deletions
diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile index 333c49f8e4..23dbcf9156 100644 --- a/usr/src/cmd/Makefile +++ b/usr/src/cmd/Makefile @@ -292,6 +292,7 @@ COMMON_SUBDIRS= \ pcidr \ pcitool \ pfexec \ + pfexecd \ pgrep \ picl \ plimit \ diff --git a/usr/src/cmd/auditrecord/audit_record_attr.txt b/usr/src/cmd/auditrecord/audit_record_attr.txt index c9fd667ba2..24dd6b5791 100644 --- a/usr/src/cmd/auditrecord/audit_record_attr.txt +++ b/usr/src/cmd/auditrecord/audit_record_attr.txt @@ -2,8 +2,7 @@ # Two "#" are comments that are copied to audit_record_attr # other comments are removed. ## -## Copyright 2010 Sun Microsystems, Inc. All rights reserved. -## Use is subject to license terms. +## Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. ## ## CDDL HEADER START ## @@ -705,6 +704,14 @@ label=AUE_EXECVE # return,failure: No such file or directory,-1 # trailer,86 +label=AUE_PFEXEC + format=path1:path2:[privileges]3:[privileges]3:[proc]4:exec_args:[exec_env]5 + comment=pathname of the executable: + comment=pathname of working directory: + comment=privileges if the limit or inheritable set are changed: + comment=process if ruid, euid, rgid or egid is changed: + comment=output if arge policy is set + label=AUE_EXIT format=arg1:[text]2 comment=1, exit status, "exit status": diff --git a/usr/src/cmd/auths/auths.c b/usr/src/cmd/auths/auths.c index 82416e0017..98141feb88 100644 --- a/usr/src/cmd/auths/auths.c +++ b/usr/src/cmd/auths/auths.c @@ -19,12 +19,9 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <stdio.h> #include <stdlib.h> #include <unistd.h> @@ -37,10 +34,6 @@ #include <prof_attr.h> #include <auth_attr.h> - -#define ALL_AUTHS "All" -#define ALL_SUN_AUTHS "solaris.*" - #define EXIT_OK 0 #define EXIT_FATAL 1 #define EXIT_NON_FATAL 2 @@ -49,71 +42,57 @@ #define TEXT_DOMAIN "SYS_TEST" #endif -#define PROFLIST_SEP "," -#define AUTH_SEP "," -#define MAXAUTHS 4096 +#define INCRAUTHS 512 +typedef struct cbs { + int auth_cnt; + int auth_max; + char **auths; +} cbs_t; -static int show_auths(char *, char **, int, int); -static int list_auths(userattr_t *, char **, int *); -static void get_default_auths(char *, char **, int *); -static void getProfiles(char *, char **, int *, char **, int *); -static void add_auths(char *, char **, int *); -static void free_auths(char **, int *); +static int show_auths(char *, int); +static int add_auth(const char *, void *, void *); +static void free_auths(cbs_t *); +static void simplify(cbs_t *); static char *progname = "auths"; - int main(int argc, char *argv[]) { int status = EXIT_OK; - char *defauths[MAXAUTHS]; - int defauth_cnt = 0; (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); switch (argc) { case 1: - get_default_auths(NULL, defauths, &defauth_cnt); - status = show_auths(NULL, defauths, defauth_cnt, 0); + status = show_auths(NULL, 0); break; case 2: - get_default_auths(argv[argc-1], defauths, &defauth_cnt); - status = show_auths(argv[argc-1], defauths, defauth_cnt, 0); + status = show_auths(argv[argc-1], 0); break; default: while (*++argv) { - get_default_auths(*argv, defauths, &defauth_cnt); - status = show_auths(*argv, defauths, defauth_cnt, 1); + status = show_auths(*argv, 1); if (status == EXIT_FATAL) { break; } - /* free memory allocated for default authorizations */ - free_auths(defauths, &defauth_cnt); - (void) printf("\n"); } break; } - /* free memory allocated for default authorizations */ - free_auths(defauths, &defauth_cnt); status = (status == EXIT_OK) ? status : EXIT_FATAL; - return (status); } - static int -show_auths(char *username, char **defauths, int defauth_cnt, int print_name) +show_auths(char *username, int print_name) { int status = EXIT_OK; struct passwd *pw; - userattr_t *user; - char *userauths[MAXAUTHS]; - int userauth_cnt = 0, old_userauth_cnt; - int i, j, have_allauths, duplicate; + int i; + cbs_t cbs = { 0, 0, NULL }; if (username == NULL) { if ((pw = getpwuid(getuid())) == NULL) { @@ -130,221 +109,120 @@ show_auths(char *username, char **defauths, int defauth_cnt, int print_name) return (status); } - have_allauths = 0; - if (username != NULL) { - /* if ALL_AUTHS is default, don't need to look at other auths */ - for (i = 0; i < defauth_cnt; i++) { - if (strcmp(defauths[i], ALL_AUTHS) == 0) { - have_allauths = 1; - break; - } - } - if (have_allauths) { - status = EXIT_OK; - } else if ((user = getusernam(username)) != NULL) { - status = list_auths(user, userauths, &userauth_cnt); - /* check if any profiles have ALL_AUTHS */ - for (i = 0; i < userauth_cnt; i++) { - if (strcmp(userauths[i], ALL_AUTHS) == 0) { - have_allauths = 1; - break; - } - } - } - if ((defauth_cnt + userauth_cnt) == 0) { - status = EXIT_NON_FATAL; - } - } + (void) _enum_auths(username, add_auth, NULL, &cbs); + + if (cbs.auth_cnt == 0) + status = EXIT_NON_FATAL; + if (status == EXIT_NON_FATAL) { - (void) fprintf(stderr, "%s: %s : ", progname, username); + (void) fprintf(stderr, "%s: %s: ", progname, username); (void) fprintf(stderr, gettext("No authorizations\n")); } else { - if (print_name) { - (void) printf("%s : ", username); - } - - if (have_allauths) { - (void) printf("%s\n", ALL_SUN_AUTHS); - } else { - /* - * combine the user auths and default auths, - * and eliminate duplicates from the two - */ - old_userauth_cnt = userauth_cnt; - for (i = 0; i < defauth_cnt; i++) { - duplicate = 0; - for (j = 0; j < old_userauth_cnt; j++) { - if (strcmp(userauths[j], defauths[i]) == - 0) { - duplicate = 1; - break; - } - } - if (!duplicate) { - userauths[userauth_cnt] = - strdup(defauths[i]); - userauth_cnt++; - } - } - - /* print out the auths */ - for (i = 0; i < (userauth_cnt - 1); i++) { - (void) printf("%s,", userauths[i]); - } - - /* print out the last entry, without the comma */ - (void) printf("%s\n", userauths[userauth_cnt - 1]); - } - } + simplify(&cbs); - /* free memory allocated for authorizations */ - free_auths(userauths, &userauth_cnt); + if (print_name) + (void) printf("%s: ", username); - return (status); -} + /* print out the auths */ + for (i = 0; i < cbs.auth_cnt - 1; i++) + (void) printf("%s,", cbs.auths[i]); + /* print out the last entry, without the comma */ + (void) printf("%s\n", cbs.auths[cbs.auth_cnt - 1]); -static int -list_auths(userattr_t *user, char **authArray, int *authcnt) -{ - int status = EXIT_OK; - char *authlist = NULL; - char *proflist = NULL; - char *profArray[MAXPROFS]; - int profcnt = 0; - - authlist = kva_match(user->attr, USERATTR_AUTHS_KW); - if (authlist != NULL) { - add_auths(authlist, authArray, authcnt); - } - if ((proflist = kva_match(user->attr, USERATTR_PROFILES_KW)) == NULL) { - if (authcnt == 0) { - status = EXIT_NON_FATAL; - } - } else { - getProfiles(proflist, profArray, &profcnt, - authArray, authcnt); - free_proflist(profArray, profcnt); + /* free memory allocated for authorizations */ + free_auths(&cbs); } - if (authcnt == 0) { - status = EXIT_NON_FATAL; - } - free_userattr(user); return (status); } - -static void -get_default_auths(char *user, char **authArray, int *authcnt) +/*ARGSUSED*/ +static int +add_auth(const char *authname, void *ctxt, void *res) { - char *auths = NULL; - char *profs = NULL; - char *profArray[MAXPROFS]; - int profcnt = 0; + cbs_t *cbs = res; - if (user == NULL) { - struct passwd *pw; + if (cbs->auth_cnt >= cbs->auth_max) { + cbs->auth_max += INCRAUTHS; + cbs->auths = realloc(cbs->auths, + cbs->auth_max * sizeof (char *)); - if ((pw = getpwuid(getuid())) != NULL) { - user = pw->pw_name; + if (cbs->auths == NULL) { + (void) fprintf(stderr, "%s: ", progname); + (void) fprintf(stderr, gettext("Out of memory\n")); + exit(1); } } - if (_get_user_defs(user, &auths, &profs) == 0) { - if (auths != NULL) { - add_auths(auths, authArray, authcnt); - } + cbs->auths[cbs->auth_cnt] = strdup(authname); + cbs->auth_cnt++; - /* get authorizations from default profiles */ - if (profs != NULL) { - getProfiles(profs, profArray, &profcnt, - authArray, authcnt); - free_proflist(profArray, profcnt); - } - _free_user_defs(auths, profs); - } + return (0); } -void -add_auths(char *auths, char **authArray, int *authcnt) +static void +free_auths(cbs_t *cbs) { - char *authname, *lasts, *real_authname; - int i; + int i; - for (authname = (char *)strtok_r(auths, AUTH_SEP, &lasts); - authname != NULL; - authname = (char *)strtok_r(NULL, AUTH_SEP, &lasts)) { + for (i = 0; i < cbs->auth_cnt; i++) + free(cbs->auths[i]); - if ((strcmp(authname, KV_WILDCARD) == 0) || - (strcmp(authname, ALL_SUN_AUTHS) == 0)) { - real_authname = ALL_AUTHS; - } else { - real_authname = authname; - } + free(cbs->auths); +} - /* check to see if authorization is already in list */ - for (i = 0; i < *authcnt; i++) { - if (strcmp(real_authname, authArray[i]) == 0) { - break; /* already in list */ - } - } +/* We have always ignored .grant in auths(1) */ +static boolean_t +auth_match(const char *pattern, const char *auth) +{ + size_t len = strlen(pattern); - /* not in list, add it in */ - if (i == *authcnt) { - authArray[i] = strdup(real_authname); - *authcnt = i + 1; - } - } + if (pattern[len - 1] != KV_WILDCHAR) + return (B_FALSE); + return (strncmp(pattern, auth, len - 1) == 0); } -static void -free_auths(char *auths[], int *auth_cnt) +static int +mstrptr(const void *a, const void *b) { - int i; + char *const *ap = a; + char *const *bp = b; - for (i = 0; i < *auth_cnt; i++) { - free(auths[i]); - } - *auth_cnt = 0; + return (strcmp(*ap, *bp)); } +/* + * Simplify the returned authorizations: sort and match wildcards; + * we're using here that "*" sorts before any other character. + */ static void -getProfiles(char *profiles, char **profArray, int *profcnt, - char **authArray, int *authcnt) +simplify(cbs_t *cbs) { - - char *prof; - char *lasts; - profattr_t *pa; - char *auths; - int i; - - for (prof = (char *)strtok_r(profiles, PROFLIST_SEP, &lasts); - prof != NULL; - prof = (char *)strtok_r(NULL, PROFLIST_SEP, &lasts)) { - - getproflist(prof, profArray, profcnt); - } - - /* get authorizations from list of profiles */ - for (i = 0; i < *profcnt; i++) { - - if ((pa = getprofnam(profArray[i])) == NULL) { - /* - * this should never happen. - * unless the database has an undefined profile - */ - continue; - } - - /* get auths this profile */ - auths = kva_match(pa->attr, PROFATTR_AUTHS_KW); - if (auths != NULL) { - add_auths(auths, authArray, authcnt); + int rem, i; + + /* First we sort */ + qsort(cbs->auths, cbs->auth_cnt, sizeof (cbs->auths[0]), mstrptr); + + /* + * Then we remove the entries which match a later entry. + * We walk the list, with "i + rem + 1" the cursor for the possible + * candidate for removal. With "rem" we count the removed entries + * and we copy while we're looking for duplicate/superfluous entries. + */ + for (i = 0, rem = 0; i < cbs->auth_cnt - rem - 1; ) { + if (strcmp(cbs->auths[i], cbs->auths[i + rem + 1]) == 0 || + strchr(cbs->auths[i], KV_WILDCHAR) != NULL && + auth_match(cbs->auths[i], cbs->auths[i + rem + 1])) { + free(cbs->auths[i + rem + 1]); + rem++; + } else { + i++; + if (rem > 0) + cbs->auths[i] = cbs->auths[i + rem]; } - - free_profattr(pa); } + + cbs->auth_cnt -= rem; } diff --git a/usr/src/cmd/csh/i386/Makefile b/usr/src/cmd/csh/i386/Makefile index c580f9f0b4..36ee788fc0 100644 --- a/usr/src/cmd/csh/i386/Makefile +++ b/usr/src/cmd/csh/i386/Makefile @@ -1,5 +1,4 @@ -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved. # # Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T # All Rights Reserved @@ -8,8 +7,6 @@ # All rights reserved. The Berkeley Software License Agreement # specifies the terms and conditions for redistribution. -# ident "%Z%%M% %I% %E% SMI" - # # C Shell with process control; VM/UNIX VAX Makefile # Bill Joy UC Berkeley; Jim Kulp IIASA, Austria @@ -17,8 +14,6 @@ CSH_PROG = csh PROG = $(CSH_PROG) -PFCSH_PROG= pfcsh -ROOTPFCSH= $(ROOTBIN)/$(PFCSH_PROG) include ../../Makefile.cmd @@ -27,13 +22,11 @@ DEFS = -DVFORK -DFILEC -DBSD_COMP -DFIVE # No TELL when MBCHAR CPPFLAGS= -I. $(DEFS) $(MBCHAR) $(CPPFLAGS.master) CPPFLAGS += -I../../sh CPPFLAGS += -D_FILE_OFFSET_BITS=64 -LDLIBS += -lcurses -lsecdb +LDLIBS += -lcurses MAPFILES = ../mapfile-intf $(MAPFILE.NGB) LDFLAGS += $(MAPFILES:%=-M%) -PFOBJS = sh_policy.o - HDDEP = sh.o sh.dir.o sh.dol.o sh.err.o sh.exec.o sh.exp.o sh.file.o \ sh.func.o sh.glob.o sh.hist.o sh.init.o sh.lex.o sh.misc.o \ sh.parse.o sh.proc.o sh.sem.o sh.set.o sh.time.o @@ -42,12 +35,11 @@ COMMONOBJS= printf.o sh.char.o sh.dir.o sh.dol.o sh.err.o \ sh.exec.o sh.exp.o sh.file.o sh.func.o sh.glob.o sh.hist.o sh.init.o \ sh.lex.o sh.misc.o sh.parse.o sh.print.o sh.proc.o sh.sem.o sh.set.o \ sh.time.o sh.tchar.o sh.tconst.o sh.o \ - wait3.o + wait3.o LOCALOBJS= signal.o COMMONSRCS= $(COMMONOBJS:%.o=../%.c) -PFSRCS= $(PFOBJS:%=pfcsh_objs/%) .KEEP_STATE: @@ -64,23 +56,19 @@ all: $(PROG) $(COMPILE.c) $< $(POST_PROCESS_O) -$(CSH_PROG): $(COMMONOBJS) $(PFOBJS) $(LOCALOBJS) $(MAPFILES) - $(LINK.c) $(COMMONOBJS) $(PFOBJS) $(LOCALOBJS) -o $@ $(LDLIBS) +$(CSH_PROG): $(COMMONOBJS) $(LOCALOBJS) $(MAPFILES) + $(LINK.c) $(COMMONOBJS) $(LOCALOBJS) -o $@ $(LDLIBS) $(POST_PROCESS) -$(ROOTPFCSH): $(ROOTPROG) - $(RM) $@ - $(LN) $(ROOTPROG) $@ - $(HDDEP): ../sh.tconst.h -install: all $(ROOTBINPROG) $(ROOTPROG) $(ROOTPFCSH) +install: all $(ROOTBINPROG) $(ROOTPROG) lint: ../sh.tconst.h - $(LINT.c) $(COMMONSRCS) $(PFSRCS) signal.c + $(LINT.c) $(COMMONSRCS) signal.c $(LDLIBS) clean: - $(RM) $(LOCALOBJS) $(COMMONOBJS) $(PFOBJS) + $(RM) $(LOCALOBJS) $(COMMONOBJS) clobber: clean $(RM) $(PROG) diff --git a/usr/src/cmd/csh/sh.c b/usr/src/cmd/csh/sh.c index da000b4c14..631a75d39d 100644 --- a/usr/src/cmd/csh/sh.c +++ b/usr/src/cmd/csh/sh.c @@ -1,6 +1,5 @@ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ @@ -12,8 +11,6 @@ * specifies the terms and conditions for redistribution. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <locale.h> #include "sh.h" /* #include <sys/ioctl.h> */ @@ -22,7 +19,6 @@ #include "sh.tconst.h" #include <pwd.h> #include <stdlib.h> -#include "sh_policy.h" /* for pfcsh */ #ifdef TRACE #include <stdio.h> #endif @@ -38,7 +34,8 @@ tchar *pathlist[] = { S_usrbin /* "/usr/bin" */, S_DOT /* "." */, 0 }; tchar *dumphist[] = { S_history /* "history" */, S_h /* "-h" */, 0, 0 }; -tchar *loadhist[] = { S_source /* "source" */, S_h /* "-h" */, S_NDOThistory /* "~/.history" */, 0 }; +tchar *loadhist[] = { S_source /* "source" */, S_h /* "-h" */, + S_NDOThistory /* "~/.history" */, 0 }; tchar HIST = '!'; tchar HISTSUB = '^'; int nofile; @@ -76,7 +73,6 @@ void initdesc(int, char *[]); void initdesc_x(int, char *[], int); void closem(void); void unsetfd(int); -void secpolicy_print(int, const char *); void phup(void); #ifdef TRACE @@ -119,7 +115,7 @@ tprintf(fmt, a, b, c, d, e, f, g, h, i, j) int main(int c, char **av) { - tchar **v, *cp, *p, *q, *r; + tchar **v, *cp, *r; int f; struct sigvec osv; struct sigaction sa; @@ -127,8 +123,6 @@ main(int c, char **av) char *c_max_var_len; int c_max_var_len_size; - pfcshflag = 0; - /* * set up the error exit, if there is an error before * this is done, it will core dump, and we don't @@ -153,29 +147,6 @@ main(int c, char **av) #endif (void) textdomain(TEXT_DOMAIN); - /* - * This is a profile shell if the simple name of argv[0] is - * pfcsh or -pfcsh - */ - p = strtots(NOSTR, "pfcsh"); - r = strtots(NOSTR, "-pfcsh"); - if ((p != NOSTR) && (r != NOSTR) && - ((q = strtots(NOSTR, *av)) != NOSTR)) { - if (c > 0 && (eq(p, simple(q)) || eq(r, simple(q)))) { - pfcshflag = 1; - } - xfree(q); - } - - if (p != NOSTR) - xfree(p); - if (r != NOSTR) - xfree(r); - - if (pfcshflag == 1) { - secpolicy_init(); - } - /* Copy arguments */ v = strblktotsblk(av, c); @@ -250,8 +221,7 @@ main(int c, char **av) if (pw != NULL) { set(S_user, strtots((tchar *)0, pw->pw_name)); local_setenv(S_USER, strtots((tchar *)0, pw->pw_name)); - } - else if (loginsh) { /* Give up setting USER variable. */ + } else if (loginsh) { /* Give up setting USER variable. */ printf("Warning: USER environment variable could not be set.\n"); } } @@ -428,7 +398,8 @@ main(int c, char **av) */ if (prompt) { gethostname_(s_prompt, MAXHOSTNAMELEN); - strcat_(s_prompt, uid == 0 ? S_SHARPSP /* "# " */ : S_PERSENTSP /* "% " */); + strcat_(s_prompt, + uid == 0 ? S_SHARPSP /* "# " */ : S_PERSENTSP /* "% " */); set(S_prompt /* "prompt" */, s_prompt); } @@ -478,7 +449,8 @@ retry: if (ioctl(f, TIOCGPGRP, (char *)&tpgrp) == 0 && tpgrp != -1) { if (tpgrp != shpgrp) { - void (*old)() = (void (*)())signal(SIGTTIN, SIG_DFL); + void (*old)() = (void (*)()) + signal(SIGTTIN, SIG_DFL); (void) kill(0, SIGTTIN); (void) signal(SIGTTIN, old); goto retry; @@ -530,7 +502,8 @@ printf("Warning: no access to tty; thus no job control in this shell...\n"); } /* Will have value("home") here because set fast if don't */ - srccat(value(S_home /* "home" */), S_SLADOTcshrc /* "/.cshrc" */); + srccat(value(S_home /* "home" */), + S_SLADOTcshrc /* "/.cshrc" */); /* Hash path */ if (!fast && !arginp && !onelflg && !havhash) @@ -543,7 +516,8 @@ printf("Warning: no access to tty; thus no job control in this shell...\n"); */ dosource(loadhist); if (loginsh) { - srccat_inlogin(value(S_home /* "home" */), S_SLADOTlogin /* "/.login" */); + srccat_inlogin(value(S_home /* "home" */), + S_SLADOTlogin /* "/.login" */); } /* @@ -726,7 +700,7 @@ srcunit(int unit, bool onlyown, bool hflg) reenter++; if (reenter == 1) { /* Setup the new values of the state stuff saved above */ - copy((char *)&saveB, (char *)&B, sizeof saveB); + copy((char *)&saveB, (char *)&B, sizeof (saveB)); fbuf = (tchar **) 0; fseekp = feobp = fblocks = 0; oSHIN = SHIN, SHIN = unit, arginp = 0, onelflg = 0; @@ -758,7 +732,7 @@ srcunit(int unit, bool onlyown, bool hflg) xfree((char *)fbuf); /* Reset input arena */ - copy((char *)&B, (char *)&saveB, sizeof B); + copy((char *)&B, (char *)&saveB, sizeof (B)); (void) close(SHIN), SHIN = oSHIN; unsetfd(SHIN); @@ -819,7 +793,8 @@ goodbye(void) (void) signal(SIGTERM, SIG_IGN); setintr = 0; /* No interrupts after "logout" */ if (adrof(S_home /* "home" */)) - srccat(value(S_home /* "home" */), S_SLADOTlogout /* "/.logout" */); + srccat(value(S_home /* "home" */), + S_SLADOTlogout /* "/.logout" */); } rechist(); exitstat(); @@ -1215,7 +1190,7 @@ tchar ** strblktotsblk(char **v, int num) { tchar **newv = - (tchar **)xcalloc((unsigned)(num+ 1), sizeof (tchar **)); + (tchar **)xcalloc((unsigned)(num+ 1), sizeof (tchar **)); tchar **onewv = newv; while (*v && num--) @@ -1332,15 +1307,15 @@ initdesc_x(int argc, char *argv[], int is_reinit) * in the form /dev/fd/X. */ if (argc >= 3) - if (sscanf(argv[2], "/dev/fd/%d", &script_fd) != 1) - script_fd = -1; - else - fcntl(script_fd, F_SETFD, 1); /* Make sure to close - * this file on exec. - */ + if (sscanf(argv[2], "/dev/fd/%d", &script_fd) != 1) + script_fd = -1; + else + /* Make sure to close this file on exec. */ + fcntl(script_fd, F_SETFD, 1); if (fdinuse == NULL) { - nbytesused = sizeof (int) * howmany(NoFile, sizeof (int) * NBBY); + nbytesused = sizeof (int) * + howmany(NoFile, sizeof (int) * NBBY); fdinuse = (int *)xalloc(nbytesused); } @@ -1474,22 +1449,3 @@ unsetfd(int fd) max_fd = 0; } } - -/* - * A generic call back routine to output error messages from the - * policy backing functions called by pfcsh. - */ -void -secpolicy_print(int level, const char *msg) -{ - switch (level) { - case SECPOLICY_WARN: - default: - haderr = 1; - printf("%s: ", msg); /* printf() does gettext() */ - break; - case SECPOLICY_ERROR: - bferr((char *)msg); /* bferr() does gettext() */ - break; - } -} diff --git a/usr/src/cmd/csh/sh.exec.c b/usr/src/cmd/csh/sh.exec.c index e80bfec8dc..eee2d16440 100644 --- a/usr/src/cmd/csh/sh.exec.c +++ b/usr/src/cmd/csh/sh.exec.c @@ -1,6 +1,5 @@ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ @@ -12,13 +11,10 @@ * specifies the terms and conditions for redistribution. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include "sh.h" #include <dirent.h> #include <string.h> #include "sh.tconst.h" -#include "sh_policy.h" /* @@ -123,7 +119,8 @@ doexec(struct command *t) pv = justabs; else pv = v->vec; - sav = strspl(S_SLASH /* "/" */, *av); /* / command name for postpending */ + /* / command name for postpending */ + sav = strspl(S_SLASH /* "/" */, *av); #ifdef VFORK Vsav = sav; #endif @@ -140,7 +137,8 @@ doexec(struct command *t) goto cont; } - if (pv[0][0] == 0 || eq(pv[0], S_DOT /* "." */)) { /* don't make ./xxx */ + /* don't make ./xxx */ + if (pv[0][0] == 0 || eq(pv[0], S_DOT /* "." */)) { texec(t, *av, av); } else { dp = strspl(*pv, sav); @@ -193,7 +191,6 @@ pexerr(void) void texec(struct command *cmd, tchar *f, tchar **t) { - int pfstatus = 0; struct varent *v; tchar **vp; tchar *lastsh[2]; @@ -204,16 +201,7 @@ texec(struct command *cmd, tchar *f, tchar **t) /* convert cfname and cargs from tchar to char */ tconvert(cmd, f, t); - if (pfcshflag == 1) { - pfstatus = secpolicy_pfexec((const char *)(cmd->cfname), - cmd->cargs, (const char **)NULL); - if (pfstatus != NOATTRS) { - errno = pfstatus; - } - } - if ((pfcshflag == 0) || (pfstatus == NOATTRS)) { - execv(cmd->cfname, cmd->cargs); - } + execv(cmd->cfname, cmd->cargs); /* * exec returned, free up allocations from above @@ -257,7 +245,9 @@ texec(struct command *cmd, tchar *f, tchar **t) #endif vp = lastsh; - vp[0] = adrof(S_shell /* "shell" */) ? value(S_shell /* "shell" */) : S_SHELLPATH /* SHELLPATH */; + vp[0] = adrof(S_shell /* "shell" */) ? + value(S_shell /* "shell" */) : + S_SHELLPATH /* SHELLPATH */; vp[1] = (tchar *) NULL; #ifdef OTHERSH if (ff != -1 && read_(ff, ch, 1) == 1 && ch[0] != '#') @@ -314,7 +304,7 @@ tconvert(struct command *cmd, tchar *fname, tchar **list) len = blklen(list); rc = cmd->cargs = (char **) - xcalloc((uint_t)(len + 1), sizeof (char **)); + xcalloc((uint_t)(len + 1), sizeof (char **)); while (len--) *rc++ = tstostr(NULL, *list++); *rc = NULL; @@ -399,9 +389,7 @@ dohash(char cachearray[]) for (cnt = 0; cnt < (HSHSIZ / 8); cnt++) cachearray[cnt] = 0; if (v == 0) - { return; - } for (pv = v->vec; *pv; pv++, i++) { if (pv[0][0] != '/') continue; @@ -420,7 +408,8 @@ dohash(char cachearray[]) (dp->d_name[1] == '\0' || dp->d_name[1] == '.' && dp->d_name[2] == '\0')) continue; - hashval = hash(hashname(strtots(curdir_, dp->d_name)), i); + hashval = hash(hashname(strtots(curdir_, dp->d_name)), + i); bis(cachearray, hashval); } unsetfd(dirp->dd_fd); @@ -449,7 +438,7 @@ hashstat(void) if (hits+misses) printf("%d hits, %d misses, %d%%\n", - hits, misses, 100 * hits / (hits + misses)); + hits, misses, 100 * hits / (hits + misses)); } #endif diff --git a/usr/src/cmd/csh/sparc/Makefile b/usr/src/cmd/csh/sparc/Makefile index 8a5bf81e4c..37c536f83e 100644 --- a/usr/src/cmd/csh/sparc/Makefile +++ b/usr/src/cmd/csh/sparc/Makefile @@ -1,5 +1,4 @@ -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T # All Rights Reserved @@ -8,8 +7,6 @@ # All rights reserved. The Berkeley Software License Agreement # specifies the terms and conditions for redistribution. -# ident "%Z%%M% %I% %E% SMI" - # # C Shell with process control; VM/UNIX VAX Makefile # Bill Joy UC Berkeley; Jim Kulp IIASA, Austria @@ -17,8 +14,6 @@ CSH_PROG = csh PROG = $(CSH_PROG) -PFCSH_PROG= pfcsh -ROOTPFCSH= $(ROOTBIN)/$(PFCSH_PROG) include ../../Makefile.cmd @@ -27,7 +22,7 @@ DEFS = -DVFORK -DFILEC -DBSD_COMP -DFIVE # No TELL when MBCHAR CPPFLAGS= -I. $(DEFS) $(MBCHAR) $(CPPFLAGS.master) CPPFLAGS += -I../../sh CPPFLAGS += -D_FILE_OFFSET_BITS=64 -LDLIBS += -lcurses -lsecdb +LDLIBS += -lcurses MAPFILES = ../mapfile-intf $(MAPFILE.NGB) LDFLAGS += $(MAPFILES:%=-M%) @@ -42,12 +37,11 @@ COMMONOBJS= printf.o sh.char.o sh.dir.o sh.dol.o sh.err.o \ sh.exec.o sh.exp.o sh.file.o sh.func.o sh.glob.o sh.hist.o sh.init.o \ sh.lex.o sh.misc.o sh.parse.o sh.print.o sh.proc.o sh.sem.o sh.set.o \ sh.time.o sh.tchar.o sh.tconst.o sh.o \ - wait3.o + wait3.o LOCALOBJS= signal.o COMMONSRCS= $(COMMONOBJS:%.o=../%.c) -PFSRCS= ../../sh/sh_policy.c .KEEP_STATE: @@ -64,23 +58,19 @@ all: $(PROG) $(COMPILE.c) $< $(POST_PROCESS_O) -$(CSH_PROG): $(COMMONOBJS) $(PFOBJS) $(LOCALOBJS) $(MAPFILES) - $(LINK.c) $(COMMONOBJS) $(PFOBJS) $(LOCALOBJS) -o $@ $(LDLIBS) +$(CSH_PROG): $(COMMONOBJS) $(LOCALOBJS) $(MAPFILES) + $(LINK.c) $(COMMONOBJS) $(LOCALOBJS) -o $@ $(LDLIBS) $(POST_PROCESS) -$(ROOTPFCSH): $(ROOTPROG) - $(RM) $@ - $(LN) $(ROOTPROG) $@ - $(HDDEP): ../sh.tconst.h -install: all $(ROOTBINPROG) $(ROOTPROG) $(ROOTPFCSH) +install: all $(ROOTBINPROG) $(ROOTPROG) lint: ../sh.tconst.h - $(LINT.c) $(COMMONSRCS) $(PFSRCS) signal.c $(LDLIBS) + $(LINT.c) $(COMMONSRCS) signal.c $(LDLIBS) clean: - $(RM) $(LOCALOBJS) $(COMMONOBJS) $(PFOBJS) + $(RM) $(LOCALOBJS) $(COMMONOBJS) clobber: clean $(RM) $(PROG) diff --git a/usr/src/cmd/fs.d/ufs/newfs/newfs.c b/usr/src/cmd/fs.d/ufs/newfs/newfs.c index d517971873..a59b8584f1 100644 --- a/usr/src/cmd/fs.d/ufs/newfs/newfs.c +++ b/usr/src/cmd/fs.d/ufs/newfs/newfs.c @@ -22,8 +22,7 @@ /* * newfs: friendly front end to mkfs * - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/param.h> @@ -622,7 +621,7 @@ main(int argc, char *argv[]) * If alternates-per-cylinder is ever implemented: * need to get apc from dp->d_apc if no -a switch??? */ - (void) snprintf(cmd, sizeof (cmd), "pfexec mkfs -F ufs " + (void) snprintf(cmd, sizeof (cmd), "mkfs -F ufs " "%s%s%s%s %lld %d %d %d %d %d %d %d %d %s %d %d %d %d %s", Nflag ? "-o N " : "", binary_sb ? "-o calcbinsb " : "", text_sb ? "-o calcsb " : "", special, diff --git a/usr/src/cmd/ksh/Makefile b/usr/src/cmd/ksh/Makefile index bc4e80bd43..a2eb19cde9 100644 --- a/usr/src/cmd/ksh/Makefile +++ b/usr/src/cmd/ksh/Makefile @@ -20,16 +20,14 @@ # # -# Copyright 2010 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. # SHELL=/usr/bin/ksh93 PROG= ksh -USRKSH_ALIAS_LIST=ksh ksh93 rksh rksh93 pfksh pfksh93 pfrksh pfrksh93 - +USRKSH_ALIAS_LIST=ksh ksh93 rksh rksh93 include ../Makefile.cmd @@ -82,10 +80,6 @@ install: $(ISAEXEC) $(SUBDIRS) $(SYMLINK) ../usr/bin/ksh93 $(ROOTSBIN)/jsh $(RM) $(ROOTBIN)/jsh $(SYMLINK) ksh93 $(ROOTBIN)/jsh - $(RM) $(ROOTSBIN)/pfsh - $(SYMLINK) ../usr/bin/ksh93 $(ROOTSBIN)/pfsh - $(RM) $(ROOTBIN)/pfsh - $(SYMLINK) ksh93 $(ROOTBIN)/pfsh $(RM) $(ROOTBIN)/sh $(SYMLINK) $(ARCH32)/ksh93 $(ROOTBIN)/sh $(RM) $(ROOTLIB)/rsh diff --git a/usr/src/cmd/ksh/Makefile.com b/usr/src/cmd/ksh/Makefile.com index 519ce850fd..75685dfa18 100644 --- a/usr/src/cmd/ksh/Makefile.com +++ b/usr/src/cmd/ksh/Makefile.com @@ -20,15 +20,14 @@ # # -# Copyright 2010 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. # SHELL=/usr/bin/ksh93 PROG= ksh -USRKSH_ALIAS_LIST=ksh ksh93 rksh rksh93 pfksh pfksh93 pfrksh pfrksh93 +USRKSH_ALIAS_LIST=ksh ksh93 rksh rksh93 OBJECTS= \ pmain.o diff --git a/usr/src/cmd/perl/contrib/Sun/Solaris/Privilege/Privilege.pm b/usr/src/cmd/perl/contrib/Sun/Solaris/Privilege/Privilege.pm index 10c6cd02b4..0965ef925e 100644 --- a/usr/src/cmd/perl/contrib/Sun/Solaris/Privilege/Privilege.pm +++ b/usr/src/cmd/perl/contrib/Sun/Solaris/Privilege/Privilege.pm @@ -19,8 +19,7 @@ # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. # # @@ -33,14 +32,15 @@ use warnings; package Sun::Solaris::Privilege; -our $VERSION = '1.3'; +our $VERSION = '1.4'; use XSLoader; XSLoader::load(__PACKAGE__, $VERSION); our (@EXPORT_OK, %EXPORT_TAGS); my @constants = qw(PRIV_STR_SHORT PRIV_STR_LIT PRIV_STR_PORT PRIV_ON PRIV_OFF - PRIV_SET PRIV_AWARE PRIV_AWARE_RESET PRIV_DEBUG); + PRIV_SET PRIV_AWARE PRIV_AWARE_RESET PRIV_DEBUG PRIV_PFEXEC + PRIV_XPOLICY NET_MAC_AWARE NET_MAC_AWARE_INHERIT __PROC_PROTECT); my @syscalls = qw(setppriv getppriv setpflags getpflags); my @libcalls = qw(priv_addset priv_copyset priv_delset priv_emptyset priv_fillset priv_intersect priv_inverse priv_ineffect diff --git a/usr/src/cmd/pfexec/Makefile b/usr/src/cmd/pfexec/Makefile index 4f60f15ddd..08bfd04df6 100644 --- a/usr/src/cmd/pfexec/Makefile +++ b/usr/src/cmd/pfexec/Makefile @@ -19,30 +19,38 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" +# Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. # PROG= pfexec SRCS= $(PROG:%=%.c) PFEXEC= pfexec +BINSHELLS = bash csh ksh ksh93 rksh rksh93 sh tcsh zsh + include ../Makefile.cmd -FILEMODE = 04555 +FILEMODE = 0555 ROOTBINPFEXEC = $(PFEXEC:%=$(ROOTBIN)/%) .KEEP_STATE: -CPPFLAGS += -D_REENTRANT -LDLIBS += -lsecdb -lbsm - all: $(PROG) install: all $(ROOTBINPFEXEC) + for s in $(BINSHELLS); do \ + $(RM) $(ROOTBIN)/pf$$s; \ + $(LN) $(ROOTBIN)/pfexec $(ROOTBIN)/pf$$s; \ + done + $(RM) $(ROOTXPG4BIN)/pfsh + $(LN) $(ROOTBIN)/pfexec $(ROOTXPG4BIN)/pfsh + $(RM) $(ROOTSBIN)/pfsh + $(SYMLINK) ../usr/bin/pfexec $(ROOTSBIN)/pfsh + $(RM) $(ROOTHASBIN)/pfsh + $(LN) $(ROOTBIN)/pfexec $(ROOTHASBIN)/pfsh + $(RM) $(ROOTHASBIN)/pfksh + $(LN) $(ROOTBIN)/pfexec $(ROOTHASBIN)/pfksh clean: diff --git a/usr/src/cmd/pfexec/pfexec.c b/usr/src/cmd/pfexec/pfexec.c index 206055d431..a0025d26a7 100644 --- a/usr/src/cmd/pfexec/pfexec.c +++ b/usr/src/cmd/pfexec/pfexec.c @@ -19,397 +19,68 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - +/* + * New implementation of pfexec(1) and all of the profile shells. + * + * The algorithm is as follows: + * first try to derive the shell's path from getexecname(); + * note that this requires a *hard* link to the program, so + * if we find that we are actually executing pfexec, we start + * looking at argv[0]. + * argv[0] is also our fallback in case getexecname doesn't find it. + */ +#include <sys/param.h> +#include <alloca.h> #include <errno.h> -#include <deflt.h> #include <locale.h> -#include <sys/types.h> -#include <sys/param.h> -#include <sys/stat.h> +#include <priv.h> +#include <stdio.h> #include <stdlib.h> -#include <unistd.h> -#include <ctype.h> -#include <pwd.h> -#include <grp.h> #include <string.h> -#include <exec_attr.h> -#include <user_attr.h> -#include <auth_attr.h> -#include <prof_attr.h> -#include <errno.h> -#include <priv.h> - -#include <bsm/adt.h> -#include <bsm/adt_event.h> +#include <unistd.h> -#ifndef TEXT_DOMAIN /* Should be defined by cc -D */ +#define PFEXEC "pfexec" +#ifndef TEXT_DOMAIN #define TEXT_DOMAIN "SYS_TEST" #endif -extern int cannot_audit(int); - -static char *pathsearch(char *); -static int getrealpath(const char *, char *); -static int checkattrs(char *, int, char *[]); -static void sanitize_environ(); -static uid_t get_uid(char *); -static gid_t get_gid(char *); -static priv_set_t *get_privset(const char *); -static priv_set_t *get_granted_privs(uid_t); -static void get_default_privs(const char *, priv_set_t *); -static void get_profile_privs(char *, char **, int *, priv_set_t *); - -static int isnumber(char *); -static void usage(void); - -extern char **environ; - -#define PROFLIST_SEP "," - -int -main(int argc, char *argv[]) -{ - char *cmd; - char **cmdargs; - char cmd_realpath[MAXPATHLEN]; - int c; - char *pset = NULL; - - (void) setlocale(LC_ALL, ""); - (void) textdomain(TEXT_DOMAIN); - - while ((c = getopt(argc, argv, "P:")) != EOF) { - switch (c) { - case 'P': - if (pset == NULL) { - pset = optarg; - break; - } - /* FALLTHROUGH */ - default: - usage(); - } - } - argc -= optind; - argv += optind; - - if (argc < 1) - usage(); - - cmd = argv[0]; - cmdargs = &argv[0]; - - if (pset != NULL) { - uid_t uid = getuid(); - priv_set_t *wanted = get_privset(pset); - priv_set_t *granted; - - adt_session_data_t *ah; /* audit session handle */ - adt_event_data_t *event; /* event to be generated */ - char cwd[MAXPATHLEN]; - - granted = get_granted_privs(uid); - - /* Audit use */ - if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) { - perror("pfexec: adt_start_session"); - exit(EXIT_FAILURE); - } - if ((event = adt_alloc_event(ah, ADT_prof_cmd)) == NULL) { - perror("pfexec: adt_alloc_event"); - exit(EXIT_FAILURE); - } - if ((event->adt_prof_cmd.cwdpath = - getcwd(cwd, sizeof (cwd))) == NULL) { - (void) fprintf(stderr, - gettext("pfexec: can't add cwd path\n")); - exit(EXIT_FAILURE); - } - - event->adt_prof_cmd.cmdpath = cmd; - event->adt_prof_cmd.argc = argc - 1; - event->adt_prof_cmd.argv = &argv[1]; - event->adt_prof_cmd.envp = environ; - - if (granted != NULL) { - priv_intersect(granted, wanted); - event->adt_prof_cmd.inherit_set = wanted; - if (adt_put_event(event, ADT_SUCCESS, - ADT_SUCCESS) != 0) { - perror("pfexec: adt_put_event"); - exit(EXIT_FAILURE); - } - if (setppriv(PRIV_ON, PRIV_INHERITABLE, wanted) != 0) { - (void) fprintf(stderr, - gettext("setppriv(): %s\n"), - strerror(errno)); - exit(EXIT_FAILURE); - } - /* Trick exec into thinking we're not suid */ - (void) setppriv(PRIV_ON, PRIV_PERMITTED, wanted); - priv_freeset(event->adt_prof_cmd.inherit_set); - } else { - if (adt_put_event(event, ADT_SUCCESS, - ADT_SUCCESS) != 0) { - perror("pfexec: adt_put_event"); - exit(EXIT_FAILURE); - } - } - adt_free_event(event); - (void) adt_end_session(ah); - (void) setreuid(uid, uid); - (void) execvp(cmd, cmdargs); - (void) fprintf(stderr, - gettext("pfexec: can't execute %s: %s\n"), - cmd, strerror(errno)); - exit(EXIT_FAILURE); - } - - if ((cmd = pathsearch(cmd)) == NULL) - exit(EXIT_FAILURE); - - if (getrealpath(cmd, cmd_realpath) == 0) - exit(EXIT_FAILURE); - - if (checkattrs(cmd_realpath, argc, argv) == 0) - exit(EXIT_FAILURE); - - (void) execv(cmd, cmdargs); - /* - * We'd be here only if execv fails. - */ - (void) fprintf(stderr, gettext("pfexec: can't execute %s: %s\n"), - cmd, strerror(errno)); - exit(EXIT_FAILURE); -/* LINTED */ -} - - -/* - * gets realpath for cmd. - * return 1 on success, 0 on failure. - */ -static int -getrealpath(const char *cmd, char *cmd_realpath) -{ - if (realpath(cmd, cmd_realpath) == NULL) { - (void) fprintf(stderr, - gettext("pfexec: can't get real path of ``%s''\n"), cmd); - return (0); - } - return (1); -} - -/* - * gets execution attributed for cmd, sets uids/gids, checks environ. - * returns 1 on success, 0 on failure. - */ -static int -checkattrs(char *cmd_realpath, int argc, char *argv[]) -{ - char *value; - uid_t uid, euid; - gid_t gid = (gid_t)-1; - gid_t egid = (gid_t)-1; - struct passwd *pwent; - execattr_t *exec; - priv_set_t *lset = NULL; - priv_set_t *iset = NULL; - - adt_session_data_t *ah; /* audit session handle */ - adt_event_data_t *event; /* event to be generated */ - char cwd[MAXPATHLEN]; - - uid = euid = getuid(); - if ((pwent = getpwuid(uid)) == NULL) { - (void) fprintf(stderr, "%d: ", (int)uid); - (void) fprintf(stderr, gettext("can't get passwd entry\n")); - return (0); - } - /* Set up to audit use */ - if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) { - perror("pfexec: adt_start_session"); - return (0); - } - if ((event = adt_alloc_event(ah, ADT_prof_cmd)) == NULL) { - perror("pfexec: adt_alloc_event"); - return (0); - } - if ((event->adt_prof_cmd.cwdpath = getcwd(cwd, sizeof (cwd))) == NULL) { - (void) fprintf(stderr, gettext("pfexec: can't add cwd path\n")); - return (0); - } - /* - * Get the exec attrs: uid, gid, euid and egid - */ - if ((exec = getexecuser(pwent->pw_name, - KV_COMMAND, (char *)cmd_realpath, GET_ONE)) == NULL) { - (void) fprintf(stderr, "%s: ", cmd_realpath); - (void) fprintf(stderr, - gettext("can't get execution attributes\n")); - return (0); - } - if ((value = kva_match(exec->attr, EXECATTR_UID_KW)) != NULL) { - euid = uid = get_uid(value); - event->adt_prof_cmd.proc_euid = uid; - event->adt_prof_cmd.proc_ruid = uid; - } - if ((value = kva_match(exec->attr, EXECATTR_GID_KW)) != NULL) { - egid = gid = get_gid(value); - event->adt_prof_cmd.proc_egid = gid; - event->adt_prof_cmd.proc_rgid = gid; - } - if ((value = kva_match(exec->attr, EXECATTR_EUID_KW)) != NULL) { - event->adt_prof_cmd.proc_euid = euid = get_uid(value); - } - if ((value = kva_match(exec->attr, EXECATTR_EGID_KW)) != NULL) { - event->adt_prof_cmd.proc_egid = egid = get_gid(value); - } - if ((value = kva_match(exec->attr, EXECATTR_LPRIV_KW)) != NULL) { - lset = get_privset(value); - event->adt_prof_cmd.limit_set = lset; - } - if ((value = kva_match(exec->attr, EXECATTR_IPRIV_KW)) != NULL) { - iset = get_privset(value); - event->adt_prof_cmd.inherit_set = iset; - } - if (euid == uid || iset != NULL) { - sanitize_environ(); - } - - /* Finish audit info */ - event->adt_prof_cmd.cmdpath = cmd_realpath; - event->adt_prof_cmd.argc = argc - 1; - event->adt_prof_cmd.argv = &argv[1]; - event->adt_prof_cmd.envp = environ; - if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) { - perror("pfexec: adt_put_event"); - return (0); - } - adt_free_event(event); - (void) adt_end_session(ah); - -set_attrs: - /* - * Set gids/uids and privileges. - * - */ - if ((gid != (gid_t)-1) || (egid != (gid_t)-1)) { - if ((setregid(gid, egid) == -1)) { - (void) fprintf(stderr, "%s: ", cmd_realpath); - (void) fprintf(stderr, gettext("can't set gid\n")); - return (0); - } - } - if (lset != NULL && setppriv(PRIV_SET, PRIV_LIMIT, lset) != 0 || - iset != NULL && setppriv(PRIV_ON, PRIV_INHERITABLE, iset) != 0) { - (void) fprintf(stderr, gettext("%s: can't set privileges\n"), - cmd_realpath); - return (0); - } - if (setreuid(uid, euid) == -1) { - (void) fprintf(stderr, "%s: ", cmd_realpath); - (void) fprintf(stderr, gettext("can't set uid\n")); - return (0); - } - if (iset != NULL && getppriv(PRIV_INHERITABLE, iset) == 0) - (void) setppriv(PRIV_SET, PRIV_PERMITTED, iset); - - free_execattr(exec); - - return (1); -} - +#define RES_PFEXEC 1 +#define RES_OK 0 +#define RES_FAILURE -1 /* - * cleans up environ. code from su.c + * Return the shellname */ -static void -sanitize_environ() -{ - char **pp = environ; - char **qq, *p; - - while ((p = *pp) != NULL) { - if (*p == 'L' && p[1] == 'D' && p[2] == '_') { - for (qq = pp; (*qq = qq[1]) != NULL; qq++) { - ; - } - } else { - pp++; - } - } -} - - -static uid_t -get_uid(char *value) -{ - struct passwd *passwd_ent; - - if ((passwd_ent = getpwnam(value)) != NULL) - return (passwd_ent->pw_uid); - - if (isnumber(value)) - return (atoi(value)); - - (void) fprintf(stderr, "pfexec: %s: ", value); - (void) fprintf(stderr, gettext("can't get user entry\n")); - exit(EXIT_FAILURE); - /*NOTREACHED*/ -} - - -static uid_t -get_gid(char *value) +int +shellname(const char *name, char buf[MAXPATHLEN]) { - struct group *group_ent; + const char *cmd = strrchr(name, '/'); - if ((group_ent = getgrnam(value)) != NULL) - return (group_ent->gr_gid); + if (cmd == NULL) + cmd = name; + else + cmd++; - if (isnumber(value)) - return (atoi(value)); + if (strncmp(cmd, "pf", 2) != 0) + return (RES_FAILURE); - (void) fprintf(stderr, "pfexec: %s: ", value); - (void) fprintf(stderr, gettext("can't get group entry\n")); - exit(EXIT_FAILURE); - /*NOTREACHED*/ -} + if (strcmp(cmd, PFEXEC) == 0) + return (RES_PFEXEC); + if (strlen(name) >= MAXPATHLEN) + return (RES_FAILURE); -static int -isnumber(char *s) -{ - int c; - - if (*s == '\0') - return (0); - - while ((c = *s++) != '\0') { - if (!isdigit(c)) { - return (0); - } + if (cmd == name) { + (void) strlcpy(buf, cmd + 2, MAXPATHLEN); + } else { + (void) strncpy(buf, name, cmd - name); + (void) strcpy(buf + (cmd - name), cmd + 2); } + return (RES_OK); - return (1); -} - -static priv_set_t * -get_privset(const char *s) -{ - priv_set_t *res; - - if ((res = priv_str_to_set(s, ",", NULL)) == NULL) { - (void) fprintf(stderr, "%s: bad privilege set\n", s); - exit(EXIT_FAILURE); - } - return (res); } static void @@ -419,171 +90,77 @@ usage(void) exit(EXIT_FAILURE); } - -/* - * This routine exists on failure and returns NULL if no granted privileges - * are set. - */ -static priv_set_t * -get_granted_privs(uid_t uid) -{ - struct passwd *pwent; - userattr_t *ua; - char *profs; - priv_set_t *res; - char *profArray[MAXPROFS]; - int profcnt = 0; - - res = priv_allocset(); - if (res == NULL) { - perror("priv_allocset"); - exit(EXIT_FAILURE); - } - - priv_emptyset(res); - - if ((pwent = getpwuid(uid)) == NULL) { - (void) fprintf(stderr, "%d: ", (int)uid); - (void) fprintf(stderr, gettext("can't get passwd entry\n")); - exit(EXIT_FAILURE); - } - - ua = getusernam(pwent->pw_name); - - if (ua != NULL && ua->attr != NULL && - (profs = kva_match(ua->attr, USERATTR_PROFILES_KW)) != NULL) { - get_profile_privs(profs, profArray, &profcnt, res); - free_proflist(profArray, profcnt); - } - - get_default_privs(pwent->pw_name, res); - - if (ua != NULL) - free_userattr(ua); - - return (res); -} - -static void -get_default_privs(const char *user, priv_set_t *pset) -{ - char *profs = NULL; - char *profArray[MAXPROFS]; - int profcnt = 0; - - if (_get_user_defs(user, NULL, &profs) == 0) { - /* get privileges from default profiles */ - if (profs != NULL) { - get_profile_privs(profs, profArray, &profcnt, pset); - free_proflist(profArray, profcnt); - _free_user_defs(NULL, profs); - } - } -} - -static void -get_profile_privs(char *profiles, char **profArray, int *profcnt, - priv_set_t *pset) +int +main(int argc, char **argv) { - - char *prof; - char *lasts; - profattr_t *pa; - char *privs; - int i; - - for (prof = strtok_r(profiles, PROFLIST_SEP, &lasts); - prof != NULL; - prof = strtok_r(NULL, PROFLIST_SEP, &lasts)) - getproflist(prof, profArray, profcnt); - - /* get the privileges from list of profiles */ - for (i = 0; i < *profcnt; i++) { - - if ((pa = getprofnam(profArray[i])) == NULL) { - /* - * this should never happen. - * unless the database has an undefined profile - */ - continue; + char *cmd; + char *pset = NULL; + char pathbuf[MAXPATHLEN]; + int c; + priv_set_t *wanted; + int oflag; + + oflag = getpflags(PRIV_PFEXEC); + if (setpflags(PRIV_PFEXEC, 1) != 0) { + perror("setpflags(PRIV_PFEXEC)"); + exit(1); + } + + if (*argv[0] == '-') + cmd = argv[0] + 1; + else + cmd = argv[0]; + + /* Strip "pf" from argv[0], it confuses some shells. */ + if (strncmp(cmd, "pf", 2) == 0) { + argv[0] += 2; + /* argv[0] will need to start with '-' again. */ + if (argv[0][-2] == '-') + *argv[0] = '-'; + } + + /* If this fails, we just continue with plan B */ + if (shellname(getexecname(), pathbuf) == RES_OK) + (void) execv(pathbuf, argv); + + switch (shellname(cmd, pathbuf)) { + case RES_OK: + (void) execv(pathbuf, argv); + perror(pathbuf); + return (1); + case RES_PFEXEC: + case RES_FAILURE: + while ((c = getopt(argc, argv, "P:")) != EOF) { + switch (c) { + case 'P': + if (pset == NULL) { + pset = optarg; + break; + } + /* FALLTHROUGH */ + default: + usage(); + } } + argc -= optind; + argv += optind; + if (argc < 1) + usage(); - /* get privs from this profile */ - privs = kva_match(pa->attr, PROFATTR_PRIVS_KW); - if (privs != NULL) { - priv_set_t *tmp = priv_str_to_set(privs, ",", NULL); - if (tmp != NULL) { - priv_union(tmp, pset); - priv_freeset(tmp); + if (pset != NULL) { + wanted = priv_str_to_set(pset, ",", NULL); + if (setppriv(PRIV_ON, PRIV_INHERITABLE, wanted) != 0) { + (void) fprintf(stderr, + gettext("setppriv(): %s\n"), + strerror(errno)); + exit(EXIT_FAILURE); } + (void) setpflags(PRIV_PFEXEC, oflag); } - free_profattr(pa); - } -} - -/* - * True if someone (user, group, other) can execute this file. - */ -#define S_ISEXEC(mode) (((mode)&(S_IXUSR|S_IXGRP|S_IXOTH)) != 0) - -/* - * This function can return either the first argument or dynamically - * allocated memory. Reuse with care. - */ -static char * -pathsearch(char *cmd) -{ - char *path, *dir, *result; - char buf[MAXPATHLEN]; - struct stat stbuf; - - /* - * Implement shell like PATH searching; if the pathname contains - * one or more slashes, don't search the path, even if the '/' - * isn't the first character. (E.g., ./command or dir/command) - * No path equals to a search in ".", just like the shell. - */ - if (strchr(cmd, '/') != NULL) - return (cmd); - - path = getenv("PATH"); - if (path == NULL) - return (cmd); - - /* - * We need to copy $PATH because our sub processes may need it. - */ - path = strdup(path); - if (path == NULL) { - perror("pfexec: strdup $PATH"); - exit(EXIT_FAILURE); + (void) execvp(argv[0], argv); + perror(argv[0]); + return (1); } - - result = NULL; - for (dir = strtok(path, ":"); dir; dir = strtok(NULL, ":")) { - if (snprintf(buf, sizeof (buf), "%s/%s", dir, cmd) >= - sizeof (buf)) { - continue; - } - if (stat(buf, &stbuf) < 0) - continue; - /* - * Shells typically call access() with E_OK flag - * to determine if the effective uid can execute - * the file. We don't know what the eventual euid - * will be; it is determined by the exec_attr - * attributes which depend on the full pathname of - * the command. Therefore, we match the first regular - * file we find that is executable by someone. - */ - if (S_ISREG(stbuf.st_mode) && S_ISEXEC(stbuf.st_mode)) { - result = strdup(buf); - break; - } - } - free(path); - if (result == NULL) - (void) fprintf(stderr, gettext("%s: Command not found\n"), cmd); - return (result); + return (1); } diff --git a/usr/src/cmd/pfexecd/Makefile b/usr/src/cmd/pfexecd/Makefile new file mode 100644 index 0000000000..262bef7054 --- /dev/null +++ b/usr/src/cmd/pfexecd/Makefile @@ -0,0 +1,62 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +# +# Makefile for the pfexec daemon. +# + +PROG= pfexecd +MANIFEST= pfexecd.xml +SRCS= $(PROG:%=%.c) +lint: lint_SRCS + +include ../Makefile.cmd + +TARGET= all + +ROOTMANIFESTDIR= $(ROOTSVCSYSTEM) + +LDLIBS += -lsecdb + +# install macros and rule +# +GROUP= bin +ROOTPROG= $(ROOTLIB)/$(PROG) +$(ROOTPROG) := FILEMODE= 555 + +.KEEP_STATE: + +all: $(PROG) + +install: all .WAIT $(ROOTPROG) $(ROOTMANIFEST) $(ROOTSVCMETHOD) + +clean: + +check: $(CHKMANIFEST) + +${ROOTLIB}/%: % + ${INS.file} + +lint: lint_SRCS + +include ../Makefile.targ diff --git a/usr/src/cmd/pfexecd/pfexecd.c b/usr/src/cmd/pfexecd/pfexecd.c new file mode 100644 index 0000000000..b043c33e9c --- /dev/null +++ b/usr/src/cmd/pfexecd/pfexecd.c @@ -0,0 +1,525 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (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 (c) 2010, Oracle and/or its affiliates. All rights reserved. + * + */ + +#define _POSIX_PTHREAD_SEMANTICS 1 + +#include <sys/param.h> +#include <sys/klpd.h> +#include <sys/syscall.h> +#include <sys/systeminfo.h> + +#include <alloca.h> +#include <ctype.h> +#include <deflt.h> +#include <door.h> +#include <errno.h> +#include <grp.h> +#include <priv.h> +#include <pwd.h> +#include <regex.h> +#include <secdb.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> + +#include <auth_attr.h> +#include <exec_attr.h> +#include <prof_attr.h> +#include <user_attr.h> + +static int doorfd = -1; + +static size_t repsz, setsz; + +static uid_t get_uid(const char *, boolean_t *, char *); +static gid_t get_gid(const char *, boolean_t *, char *); +static priv_set_t *get_privset(const char *, boolean_t *, char *); +static priv_set_t *get_granted_privs(uid_t); + +/* + * Remove the isaexec path of an executable if we can't find the + * executable at the first attempt. + */ + +static regex_t regc; +static boolean_t cansplice = B_TRUE; + +static void +init_isa_regex(void) +{ + char *isalist; + size_t isalen = 255; /* wild guess */ + size_t len; + long ret; + char *regexpr; + char *p; + + /* + * Extract the isalist(5) for userland from the kernel. + */ + isalist = malloc(isalen); + do { + ret = sysinfo(SI_ISALIST, isalist, isalen); + if (ret == -1l) { + free(isalist); + return; + } + if (ret > isalen) { + isalen = ret; + isalist = realloc(isalist, isalen); + } else + break; + } while (isalist != NULL); + + + if (isalist == NULL) + return; + + /* allocate room for the regex + (/())/[^/]*$ + needed \\. */ +#define LEFT "(/(" +#define RIGHT "))/[^/]*$" + + regexpr = alloca(ret * 2 + sizeof (LEFT RIGHT)); + (void) strcpy(regexpr, LEFT); + len = strlen(regexpr); + + for (p = isalist; *p; p++) { + switch (*p) { + case '+': + case '|': + case '*': + case '[': + case ']': + case '{': + case '}': + case '\\': + regexpr[len++] = '\\'; + default: + regexpr[len++] = *p; + break; + case ' ': + case '\t': + regexpr[len++] = '|'; + break; + } + } + + free(isalist); + regexpr[len] = '\0'; + (void) strcat(regexpr, RIGHT); + + if (regcomp(®c, regexpr, REG_EXTENDED) != 0) + return; + + cansplice = B_TRUE; +} + +#define NMATCH 2 + +static boolean_t +removeisapath(char *path) +{ + regmatch_t match[NMATCH]; + + if (!cansplice || regexec(®c, path, NMATCH, match, 0) != 0) + return (B_FALSE); + + /* + * The first match includes the whole matched expression including the + * end of the string. The second match includes the "/" + "isa" and + * that is the part we need to remove. + */ + + if (match[1].rm_so == -1) + return (B_FALSE); + + /* match[0].rm_eo == strlen(path) */ + (void) memmove(path + match[1].rm_so, path + match[1].rm_eo, + match[0].rm_eo - match[1].rm_eo + 1); + + return (B_TRUE); +} + +static int +register_pfexec(int fd) +{ + int ret = syscall(SYS_privsys, PRIVSYS_PFEXEC_REG, fd); + + return (ret); +} + +/* ARGSUSED */ +static void +unregister_pfexec(int sig) +{ + if (doorfd != -1) + (void) syscall(SYS_privsys, PRIVSYS_PFEXEC_UNREG, doorfd); + _exit(0); +} + +static int +alldigits(const char *s) +{ + int c; + + if (*s == '\0') + return (0); + + while ((c = *s++) != '\0') { + if (!isdigit(c)) { + return (0); + } + } + + return (1); +} + +static uid_t +get_uid(const char *v, boolean_t *ok, char *path) +{ + struct passwd *pwd, pwdm; + char buf[1024]; + + if (getpwnam_r(v, &pwdm, buf, sizeof (buf), &pwd) == 0 && pwd != NULL) + return (pwd->pw_uid); + + if (alldigits(v)) + return (atoi(v)); + + *ok = B_FALSE; + syslog(LOG_ERR, "%s: %s: unknown username\n", path, v); + return ((uid_t)-1); +} + +static uid_t +get_gid(const char *v, boolean_t *ok, char *path) +{ + struct group *grp, grpm; + char buf[1024]; + + if (getgrnam_r(v, &grpm, buf, sizeof (buf), &grp) == 0 && grp != NULL) + return (grp->gr_gid); + + if (alldigits(v)) + return (atoi(v)); + + *ok = B_FALSE; + syslog(LOG_ERR, "%s: %s: unknown groupname\n", path, v); + return ((gid_t)-1); +} + +static priv_set_t * +get_privset(const char *s, boolean_t *ok, char *path) +{ + priv_set_t *res; + + if ((res = priv_str_to_set(s, ",", NULL)) == NULL) { + syslog(LOG_ERR, "%s: %s: bad privilege set\n", path, s); + if (ok != NULL) + *ok = B_FALSE; + } + return (res); +} + +/*ARGSUSED*/ +static int +ggp_callback(const char *prof, kva_t *attr, void *ctxt, void *vres) +{ + priv_set_t *res = vres; + char *privs; + + if (attr == NULL) + return (0); + + /* get privs from this profile */ + privs = kva_match(attr, PROFATTR_PRIVS_KW); + if (privs != NULL) { + priv_set_t *tmp = priv_str_to_set(privs, ",", NULL); + if (tmp != NULL) { + priv_union(tmp, res); + priv_freeset(tmp); + } + } + + return (0); +} + +/* + * This routine exists on failure and returns NULL if no granted privileges + * are set. + */ +static priv_set_t * +get_granted_privs(uid_t uid) +{ + priv_set_t *res; + struct passwd *pwd, pwdm; + char buf[1024]; + + if (getpwuid_r(uid, &pwdm, buf, sizeof (buf), &pwd) != 0 || pwd == NULL) + return (NULL); + + res = priv_allocset(); + if (res == NULL) + return (NULL); + + priv_emptyset(res); + + (void) _enum_profs(pwd->pw_name, ggp_callback, NULL, res); + + return (res); +} + +static void +callback_forced_privs(pfexec_arg_t *pap) +{ + execattr_t *exec; + char *value; + priv_set_t *fset; + void *res = alloca(setsz); + + /* Empty set signifies no forced privileges. */ + priv_emptyset(res); + + exec = getexecprof("Forced Privilege", KV_COMMAND, pap->pfa_path, + GET_ONE); + + if (exec == NULL && removeisapath(pap->pfa_path)) { + exec = getexecprof("Forced Privilege", KV_COMMAND, + pap->pfa_path, GET_ONE); + } + + if (exec == NULL) { + (void) door_return(res, setsz, NULL, 0); + return; + } + + if ((value = kva_match(exec->attr, EXECATTR_IPRIV_KW)) == NULL || + (fset = get_privset(value, NULL, pap->pfa_path)) == NULL) { + free_execattr(exec); + (void) door_return(res, setsz, NULL, 0); + return; + } + + priv_copyset(fset, res); + priv_freeset(fset); + + free_execattr(exec); + (void) door_return(res, setsz, NULL, 0); +} + +static void +callback_user_privs(pfexec_arg_t *pap) +{ + priv_set_t *gset, *wset; + uint32_t res; + + wset = (priv_set_t *)&pap->pfa_buf; + gset = get_granted_privs(pap->pfa_uid); + + res = priv_issubset(wset, gset); + priv_freeset(gset); + + (void) door_return((char *)&res, sizeof (res), NULL, 0); +} + +static void +callback_pfexec(pfexec_arg_t *pap) +{ + pfexec_reply_t *res = alloca(repsz); + uid_t uid, euid, uuid; + gid_t gid, egid; + struct passwd pw, *pwd; + char buf[1024]; + execattr_t *exec; + char *value; + priv_set_t *lset, *iset; + size_t mysz = repsz - 2 * setsz; + char *path = pap->pfa_path; + + uuid = pap->pfa_uid; + + if (getpwuid_r(uuid, &pw, buf, sizeof (buf), &pwd) != 0 || pwd == NULL) + goto stdexec; + + exec = getexecuser(pwd->pw_name, KV_COMMAND, path, GET_ONE); + + if (exec == NULL && removeisapath(path)) + exec = getexecuser(pwd->pw_name, KV_COMMAND, path, GET_ONE); + + if (exec == NULL) { + res->pfr_allowed = B_FALSE; + goto ret; + } + + if (exec->attr == NULL) + goto stdexec; + + /* Found in execattr, so clearly we can use it */ + res->pfr_allowed = B_TRUE; + + uid = euid = (uid_t)-1; + gid = egid = (gid_t)-1; + lset = iset = NULL; + + /* + * If there's an error in parsing uid, gid, privs, then return + * failure. + */ + if ((value = kva_match(exec->attr, EXECATTR_UID_KW)) != NULL) + euid = uid = get_uid(value, &res->pfr_allowed, path); + + if ((value = kva_match(exec->attr, EXECATTR_GID_KW)) != NULL) + egid = gid = get_gid(value, &res->pfr_allowed, path); + + if ((value = kva_match(exec->attr, EXECATTR_EUID_KW)) != NULL) + euid = get_uid(value, &res->pfr_allowed, path); + + if ((value = kva_match(exec->attr, EXECATTR_EGID_KW)) != NULL) + egid = get_gid(value, &res->pfr_allowed, path); + + if ((value = kva_match(exec->attr, EXECATTR_LPRIV_KW)) != NULL) + lset = get_privset(value, &res->pfr_allowed, path); + + if ((value = kva_match(exec->attr, EXECATTR_IPRIV_KW)) != NULL) + iset = get_privset(value, &res->pfr_allowed, path); + + /* + * Remove LD_* variables in the kernel when the runtime linker might + * use them later on because the uids are equal. + */ + res->pfr_scrubenv = (uid != (uid_t)-1 && euid == uid) || + (gid != (gid_t)-1 && egid == gid) || iset != NULL; + + res->pfr_euid = euid; + res->pfr_ruid = uid; + res->pfr_egid = egid; + res->pfr_rgid = gid; + + /* Now add the privilege sets */ + res->pfr_ioff = res->pfr_loff = 0; + if (iset != NULL) { + res->pfr_ioff = mysz; + priv_copyset(iset, PFEXEC_REPLY_IPRIV(res)); + mysz += setsz; + priv_freeset(iset); + } + if (lset != NULL) { + res->pfr_loff = mysz; + priv_copyset(lset, PFEXEC_REPLY_LPRIV(res)); + mysz += setsz; + priv_freeset(lset); + } + + res->pfr_setcred = uid != (uid_t)-1 || euid != (uid_t)-1 || + egid != (gid_t)-1 || gid != (gid_t)-1 || iset != NULL || + lset != NULL; + + /* If the real uid changes, we stop running under a profile shell */ + res->pfr_clearflag = uid != (uid_t)-1 && uid != uuid; + free_execattr(exec); +ret: + (void) door_return((char *)res, mysz, NULL, 0); + return; + +stdexec: + res->pfr_scrubenv = B_FALSE; + res->pfr_setcred = B_FALSE; + res->pfr_allowed = B_TRUE; + + (void) door_return((char *)res, mysz, NULL, 0); +} + +/* ARGSUSED */ +static void +callback(void *cookie, char *argp, size_t asz, door_desc_t *dp, uint_t ndesc) +{ + /* LINTED ALIGNMENT */ + pfexec_arg_t *pap = (pfexec_arg_t *)argp; + + if (asz < sizeof (pfexec_arg_t) || pap->pfa_vers != PFEXEC_ARG_VERS) { + (void) door_return(NULL, 0, NULL, 0); + return; + } + + switch (pap->pfa_call) { + case PFEXEC_EXEC_ATTRS: + callback_pfexec(pap); + break; + case PFEXEC_FORCED_PRIVS: + callback_forced_privs(pap); + break; + case PFEXEC_USER_PRIVS: + callback_user_privs(pap); + break; + default: + syslog(LOG_ERR, "Bad Call: %d\n", pap->pfa_call); + break; + } + + /* + * If the door_return(ptr, size, NULL, 0) fails, make sure we + * don't lose server threads. + */ + (void) door_return(NULL, 0, NULL, 0); +} + +int +main(void) +{ + const priv_impl_info_t *info; + + (void) signal(SIGINT, unregister_pfexec); + (void) signal(SIGQUIT, unregister_pfexec); + (void) signal(SIGTERM, unregister_pfexec); + (void) signal(SIGHUP, unregister_pfexec); + + info = getprivimplinfo(); + if (info == NULL) + exit(1); + + if (fork() > 0) + _exit(0); + + openlog("pfexecd", LOG_PID, LOG_DAEMON); + setsz = info->priv_setsize * sizeof (priv_chunk_t); + repsz = 2 * setsz + sizeof (pfexec_reply_t); + + init_isa_regex(); + + doorfd = door_create(callback, NULL, DOOR_REFUSE_DESC); + + if (doorfd == -1 || register_pfexec(doorfd) != 0) { + perror("doorfd"); + exit(1); + } + + /* LINTED CONSTCOND */ + while (1) + (void) sigpause(SIGINT); + + return (0); +} diff --git a/usr/src/cmd/pfexecd/pfexecd.xml b/usr/src/cmd/pfexecd/pfexecd.xml new file mode 100644 index 0000000000..c13249e4b6 --- /dev/null +++ b/usr/src/cmd/pfexecd/pfexecd.xml @@ -0,0 +1,86 @@ +<?xml version="1.0"?> +<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> +<!-- + + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (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 (c) 2010, Oracle and/or its affiliates. All rights reserved. + + NOTE: This service manifest is not editable; its contents will + be overwritten by package or patch operations, including + operating system upgrade. Make customizations in a different + file. +--> + +<service_bundle type='manifest' name='SUNWcs:pfexec'> + +<service + name='system/pfexec' + type='service' + version='1'> + + <create_default_instance enabled='true' /> + + <single_instance /> + + <dependency + name='usr' + type='service' + grouping='require_all' + restart_on='none'> + <service_fmri value='svc:/system/filesystem/usr' /> + </dependency> + + <exec_method + type='method' + name='start' + exec='/usr/lib/pfexecd' + timeout_seconds='60'> + </exec_method> + + <exec_method + type='method' + name='stop' + exec=':kill' + timeout_seconds='60'> + </exec_method> + + <exec_method + type='method' + name='refresh' + exec=':kill' + timeout_seconds='60'> + </exec_method> + + <property_group name='options' type='application'> + </property_group> + + <stability value='Unstable' /> + + <template> + <common_name> + <loctext xml:lang='C'> + Supports in-kernel pfexec and forced privileges. + </loctext> + </common_name> + </template> +</service> + +</service_bundle> diff --git a/usr/src/cmd/profiles/profiles.c b/usr/src/cmd/profiles/profiles.c index 8ac26920a4..265fd0c22e 100644 --- a/usr/src/cmd/profiles/profiles.c +++ b/usr/src/cmd/profiles/profiles.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <stdio.h> @@ -51,17 +50,10 @@ #define TEXT_DOMAIN "SYS_TEST" #endif -#define PROFLIST_SEP "," - - static void usage(); static int show_profs(char *, int); -static int list_profs(userattr_t *, int); static void print_profs_long(execattr_t *); -static void print_profs(char **, int, int); -static void getProfiles(char *, char **, int *); -static void getDefaultProfiles(char *, char **, int *); -static void print_profile_privs(const char *); +static void print_profile_privs(kva_t *); static char *progname = "profiles"; @@ -110,15 +102,31 @@ main(int argc, char *argv[]) return (status); } +static int +show_profs_callback(const char *prof, kva_t *pa, void *pflag, void *vcnt) +{ + char *indent = ""; + const int *print_flag = pflag; + int *pcnt = vcnt; + + (*pcnt)++; + + if ((*print_flag) & PRINT_NAME) { + indent = " "; + } + + (void) printf("%s%s", indent, prof); + print_profile_privs(pa); + (void) printf("\n"); + + return (0); +} static int show_profs(char *username, int print_flag) { int status = EXIT_OK; struct passwd *pw; - userattr_t *user; - char *profArray[MAXPROFS]; - int profcnt = 0; execattr_t *exec; if (username == NULL) { @@ -135,76 +143,33 @@ show_profs(char *username, int print_flag) (void) fprintf(stderr, gettext("No such user\n")); return (status); } - if (username != NULL) { - if ((user = getusernam(username)) != NULL) { - status = list_profs(user, print_flag); - } else { - getDefaultProfiles(username, profArray, &profcnt); - if (profcnt == 0) { - status = EXIT_NON_FATAL; - } else { - if (print_flag & PRINT_LONG) { - exec = getexecuser(username, KV_COMMAND, - NULL, GET_ALL|__SEARCH_ALL_POLS); - print_profs_long(exec); - free_execattr(exec); - } else { - print_profs(profArray, print_flag, - profcnt); - } - } - } - } - - if (status == EXIT_NON_FATAL) { - (void) fprintf(stderr, "%s: %s: ", progname, username); - (void) fprintf(stderr, gettext("No profiles\n")); - } - - return (status); -} - - -static int -list_profs(userattr_t *user, int print_flag) -{ - int status = EXIT_OK; - char *proflist = (char *)NULL; - execattr_t *exec = (execattr_t *)NULL; - char *profArray[MAXPROFS]; - int profcnt = 0; if (print_flag & PRINT_LONG) { - exec = getexecuser(user->name, KV_COMMAND, NULL, + exec = getexecuser(username, KV_COMMAND, NULL, GET_ALL|__SEARCH_ALL_POLS); - if (exec == NULL) { + if (exec != NULL) { + print_profs_long(exec); + free_execattr(exec); + } else { status = EXIT_NON_FATAL; } } else { - proflist = kva_match(user->attr, USERATTR_PROFILES_KW); - if (proflist != NULL) { - getProfiles(proflist, profArray, &profcnt); - } - /* Also get any default profiles */ - getDefaultProfiles(user->name, profArray, &profcnt); - if (profcnt == 0) { + int cnt = 0; + (void) _enum_profs(username, show_profs_callback, &print_flag, + &cnt); + + if (cnt == 0) status = EXIT_NON_FATAL; - } } - if (status == EXIT_OK) { - if (print_flag & PRINT_LONG) { - print_profs_long(exec); - free_execattr(exec); - } else { - print_profs(profArray, print_flag, profcnt); - } + + if (status == EXIT_NON_FATAL) { + (void) fprintf(stderr, "%s: %s: ", progname, username); + (void) fprintf(stderr, gettext("No profiles\n")); } - free_userattr(user); return (status); } - /* * print extended profile information. * @@ -242,9 +207,16 @@ print_profs_long(execattr_t *exec) for (curprofile = ""; exec != NULL; exec = exec->next) { /* print profile name if it is a new one */ if (strcmp(curprofile, exec->name) != 0) { + profattr_t *pa; curprofile = exec->name; + (void) printf(" %s", curprofile); - print_profile_privs(curprofile); + + pa = getprofnam(curprofile); + if (pa != NULL) { + print_profile_privs(pa->attr); + free_profattr(pa); + } (void) printf("\n"); } len = printf(" %s ", exec->id); @@ -289,66 +261,13 @@ usage() } static void -getProfiles(char *profiles, char **profArray, int *profcnt) { - - char *prof; - char *lasts; - - for (prof = (char *)strtok_r(profiles, PROFLIST_SEP, &lasts); - prof != NULL; - prof = (char *)strtok_r(NULL, PROFLIST_SEP, &lasts)) { - - getproflist(prof, profArray, profcnt); - - } -} - -static void -print_profile_privs(const char *profile) +print_profile_privs(kva_t *attr) { - profattr_t *prof_entry = getprofnam(profile); char *privs; - if (prof_entry) { - privs = kva_match(prof_entry->attr, PROFATTR_PRIVS_KW); + if (attr) { + privs = kva_match(attr, PROFATTR_PRIVS_KW); if (privs) (void) printf(" privs=%s", privs); - free_profattr(prof_entry); - } -} - -static void -print_profs(char **profnames, int print_flag, int profcnt) -{ - - int i; - char *indent = ""; - - if (print_flag & PRINT_NAME) { - indent = " "; - } - - for (i = 0; i < profcnt; i++) { - (void) printf("%s%s", indent, profnames[i]); - print_profile_privs(profnames[i]); - (void) printf("\n"); - } - - free_proflist(profnames, profcnt); -} - -/* - * Get the list of default profiles from /etc/security/policy.conf - */ -static void -getDefaultProfiles(char *user, char **profArray, int *profcnt) -{ - char *profs = NULL; - - if (_get_user_defs(user, NULL, &profs) == 0) { - if (profs != NULL) { - getProfiles(profs, profArray, profcnt); - _free_user_defs(NULL, profs); - } } } diff --git a/usr/src/cmd/ptools/ppriv/ppriv.c b/usr/src/cmd/ptools/ppriv/ppriv.c index d9a155a959..a695c1a09b 100644 --- a/usr/src/cmd/ptools/ppriv/ppriv.c +++ b/usr/src/cmd/ptools/ppriv/ppriv.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * * Program to examine or set process privileges. */ @@ -60,6 +59,7 @@ static boolean_t Don = B_FALSE; static boolean_t Doff = B_FALSE; static boolean_t list = B_FALSE; static boolean_t mac_aware = B_FALSE; +static boolean_t pfexec = B_FALSE; static boolean_t xpol = B_FALSE; static int mode = PRIV_STR_PORT; @@ -78,7 +78,7 @@ main(int argc, char **argv) else command = argv[0]; - while ((opt = getopt(argc, argv, "lDMNevs:xS")) != EOF) { + while ((opt = getopt(argc, argv, "lDMNPevs:xS")) != EOF) { switch (opt) { case 'l': list = B_TRUE; @@ -94,6 +94,10 @@ main(int argc, char **argv) set = B_TRUE; Doff = B_TRUE; break; + case 'P': + set = B_TRUE; + pfexec = B_TRUE; + break; case 'e': exec = B_TRUE; break; @@ -493,7 +497,7 @@ privupdate(prpriv_t *pr, const char *arg) } } - if (Doff || Don || xpol) { + if (Doff || Don || pfexec || xpol) { priv_info_uint_t *pii; int sz = PRIV_PRPRIV_SIZE(pr); char *x = (char *)pr + PRIV_PRPRIV_INFO_OFFSET(pr); @@ -530,6 +534,8 @@ done: fl |= PRIV_DEBUG; if (Doff) fl &= ~PRIV_DEBUG; + if (pfexec) + fl |= PRIV_PFEXEC; if (xpol) fl |= PRIV_XPOLICY; @@ -552,6 +558,10 @@ privupdate_self(void) if (setpflags(NET_MAC_AWARE_INHERIT, 1) != 0) fatal("setpflags(NET_MAC_AWARE_INHERIT)"); } + if (pfexec) { + if (setpflags(PRIV_PFEXEC, 1) != 0) + fatal("setpflags(PRIV_PFEXEC)"); + } if (sets != NULL) { priv_set_t *target = priv_allocset(); @@ -592,6 +602,8 @@ privupdate_self(void) (void) setpflags(PRIV_DEBUG, Don ? 1 : 0); if (xpol) (void) setpflags(PRIV_XPOLICY, 1); + if (pfexec) + (void) setpflags(PRIV_PFEXEC, 1); } static int @@ -649,6 +661,7 @@ static struct { { PRIV_AWARE_INHERIT, "PRIV_AWARE_INHERIT" }, { PRIV_AWARE_RESET, "PRIV_AWARE_RESET" }, { PRIV_XPOLICY, "PRIV_XPOLICY" }, + { PRIV_PFEXEC, "PRIV_PFEXEC" }, { NET_MAC_AWARE, "NET_MAC_AWARE" }, { NET_MAC_AWARE_INHERIT, "NET_MAC_AWARE_INHERIT" }, }; diff --git a/usr/src/cmd/sh/Makefile b/usr/src/cmd/sh/Makefile index a2660213d0..78db168423 100644 --- a/usr/src/cmd/sh/Makefile +++ b/usr/src/cmd/sh/Makefile @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved. # PROG = sh @@ -29,7 +28,7 @@ USR_PROG = $(PROG) OBJS= args.o blok.o cmd.o defs.o error.o fault.o hash.o hashserv.o \ io.o msg.o print.o stak.o string.o word.o xec.o \ ctype.o echo.o expand.o func.o macro.o pwd.o setbrk.o test.o \ - bltin.o jobs.o ulimit.o sh_policy.o main.o name.o service.o + bltin.o jobs.o ulimit.o main.o name.o service.o SRCS= $(OBJS:%.o=%.c) include ../Makefile.cmd @@ -47,7 +46,7 @@ XGETFLAGS += -a -x sh.xcl CPPFLAGS += -D_FILE_OFFSET_BITS=64 -DACCT MAPFILES = $(MAPFILE.INT) $(MAPFILE.NGB) LDFLAGS += $(MAPFILES:%=-M%) -LDLIBS += -lgen -lsecdb +LDLIBS += -lgen .KEEP_STATE: @@ -66,8 +65,6 @@ $(POFILE): $(POFILES) install: all $(ROOTHASBINPROG) $(RM) $(ROOTHASBIN)/jsh $(SYMLINK) sh $(ROOTHASBIN)/jsh - $(RM) $(ROOTHASBIN)/pfsh - $(SYMLINK) sh $(ROOTHASBIN)/pfsh $(RM) $(ROOTHASLIB)/rsh $(SYMLINK) ../bin/sh $(ROOTHASLIB)/rsh diff --git a/usr/src/cmd/sh/main.c b/usr/src/cmd/sh/main.c index 9533e793cc..df42009b5b 100644 --- a/usr/src/cmd/sh/main.c +++ b/usr/src/cmd/sh/main.c @@ -20,14 +20,12 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ -#pragma ident "%Z%%M% %I% %E% SMI" /* * UNIX shell */ @@ -40,7 +38,6 @@ #include <sys/stat.h> #include <sys/wait.h> #include "dup.h" -#include "sh_policy.h" #ifdef RES #include <sgtty.h> @@ -141,15 +138,6 @@ main(int c, char *v[], char *e[]) (void) textdomain(TEXT_DOMAIN); /* - * This is a profile shell if the simple name of argv[0] is - * pfsh or -pfsh - */ - if (c > 0 && (eq("pfsh", simple(*v)) || eq("-pfsh", simple(*v)))) { - flags |= pfshflg; - secpolicy_init(); - } - - /* * 'rsflag' is zero if SHELL variable is * set in environment and * the simple file part of the value. @@ -600,23 +588,3 @@ setmode(int prof) flags &= ~prompt; } } - -/* - * A generic call back routine to output error messages from the - * policy backing functions called by pfsh. - * - * msg must contain '\n' if a new line is to be printed. - */ -void -secpolicy_print(int level, const char *msg) -{ - switch (level) { - case SECPOLICY_WARN: - default: - prs(_gettext(msg)); - return; - case SECPOLICY_ERROR: - error(msg); - break; - } -} diff --git a/usr/src/cmd/sh/service.c b/usr/src/cmd/sh/service.c index e666aafc65..e74a35b471 100644 --- a/usr/src/cmd/sh/service.c +++ b/usr/src/cmd/sh/service.c @@ -20,15 +20,12 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * UNIX shell */ @@ -36,7 +33,6 @@ #include "defs.h" #include <errno.h> #include <fcntl.h> -#include "sh_policy.h" #define ARGMK 01 @@ -202,7 +198,8 @@ catpath(unsigned char *path, unsigned char *name) if (argp >= brkend) growstak(argp); } - while (*argp++ = *scanp++); + while (*argp++ = *scanp++) + ; return (path); } @@ -253,7 +250,6 @@ execa(unsigned char *at[], short pos) static unsigned char * execs(unsigned char *ap, unsigned char *t[]) { - int pfstatus = NOATTRS; unsigned char *p, *prefix; unsigned char *savptr; @@ -261,28 +257,8 @@ execs(unsigned char *ap, unsigned char *t[]) trim(p = curstak()); sigchk(); - if (flags & pfshflg) { - /* - * Need to save the stack information, or the - * first memory allocation in secpolicy_profile_lookup() - * will clobber it. - */ - savptr = endstak(p + strlen((const char *)p) + 1); - - pfstatus = secpolicy_pfexec((const char *)p, - (char **)t, (const char **)xecenv); - - if (pfstatus != NOATTRS) { - errno = pfstatus; - } - - tdystak(savptr); - } - - if (pfstatus == NOATTRS) { - execve((const char *)p, (char *const *)&t[0], - (char *const *)xecenv); - } + execve((const char *)p, (char *const *)&t[0], + (char *const *)xecenv); switch (errno) { case ENOEXEC: /* could be a shell script */ @@ -351,7 +327,7 @@ trim(unsigned char *at) last = at; while (c = *current) { if ((len = mbtowc(&wc, (char *)current, - MB_LEN_MAX)) <= 0) { + MB_LEN_MAX)) <= 0) { *last++ = c; current++; continue; @@ -369,7 +345,7 @@ trim(unsigned char *at) current++; if (c = *current) { if ((len = mbtowc(&wc, (char *)current, - MB_LEN_MAX)) <= 0) { + MB_LEN_MAX)) <= 0) { *last++ = c; current++; continue; @@ -676,7 +652,7 @@ doacct(void) sabuf.ac_etime = compress(after - before); if ((fd = open((char *)acctnod.namval, - O_WRONLY | O_APPEND | O_CREAT, 0666)) != -1) { + O_WRONLY | O_APPEND | O_CREAT, 0666)) != -1) { write(fd, &sabuf, sizeof (sabuf)); close(fd); } diff --git a/usr/src/cmd/sh/sh_policy.c b/usr/src/cmd/sh/sh_policy.c deleted file mode 100644 index d9102e3381..0000000000 --- a/usr/src/cmd/sh/sh_policy.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - * - * Policy backing functions for kpolicy=suser,profiles=yes - * - */ - -#include <sys/param.h> -#include <grp.h> -#include <pwd.h> -#include <strings.h> -#include <string.h> -#include <errno.h> -#include <unistd.h> -#include <stdlib.h> -#include "sh_policy.h" - - -static char *username; - -/* - * get the ruid and passwd name - */ -void -secpolicy_init(void) -{ - uid_t ruid; - struct passwd *passwd_ent; - - if (username != NULL) { - free(username); - username = NULL; - } - - ruid = getuid(); - - if ((passwd_ent = getpwuid(ruid)) == NULL) { - secpolicy_print(SECPOLICY_ERROR, ERR_PASSWD); - } else if ((username = strdup(passwd_ent->pw_name)) == NULL) { - secpolicy_print(SECPOLICY_ERROR, ERR_MEM); - } -} - - -/* - * stuff pfexec full path at the begining of the argument vector - * for the command to be pfexec'd - * - * return newly allocated argv on success, else return NULL. - */ -static char ** -secpolicy_set_argv(char **arg_v) -{ - int i; - int arg_c = 0; - char **pfarg_v = NULL; - - if (*arg_v == NULL) { - return (pfarg_v); - } - for (i = 0; arg_v[i] != NULL; i++) { - arg_c++; - } - /* +2 for PFEXEC and null termination */ - if ((pfarg_v = calloc(arg_c + 2, sizeof (char *))) == NULL) { - return (pfarg_v); - } - pfarg_v[0] = PFEXEC; - for (i = 0; i < arg_c; i++) { - pfarg_v[i + 1] = arg_v[i]; - } - - return (pfarg_v); -} - - -/* - * gets realpath for cmd. - * return 0 on success, else return ENOENT. - */ -static int -secpolicy_getrealpath(const char *cmd, char *cmd_realpath) -{ - register char *mover; - char cwd[MAXPATHLEN]; - - /* - * What about relative paths? Were we passed one? - */ - mover = (char *)cmd; - if (*mover != '/') { - /* - * Everything in here will be considered a relative - * path, and therefore we need to prepend cwd to it. - */ - if (getcwd(cwd, MAXPATHLEN) == NULL) { - secpolicy_print(SECPOLICY_ERROR, ERR_CWD); - } - strcat(cwd, "/"); - if (strlcat(cwd, cmd, MAXPATHLEN) >= MAXPATHLEN) { - return (ENOENT); - } - mover = cwd; - } - /* - * Resolve ".." and other such nonsense. - * Now, is there *REALLY* a file there? - */ - if (realpath(mover, cmd_realpath) == NULL) { - return (ENOENT); - } - - return (0); -} - - -/* - * check if the command has execution attributes - * return - - * - NOATTRS : command in profile but has no execution attributes - * - ENOMEM : memory allocation errors - * - ENOENT : command not in profile - */ - -int -secpolicy_pfexec(const char *command, char **arg_v, const char **xecenv) -{ - register int status = NOATTRS; - char **pfarg_v = (char **)NULL; - char cmd_realpath[MAXPATHLEN + 1]; - execattr_t *exec; - - if ((status = secpolicy_getrealpath(command, cmd_realpath)) != 0) { - return (status); - } - if ((exec = getexecuser(username, KV_COMMAND, - (const char *)cmd_realpath, GET_ONE)) == NULL) { - /* - * command not in profile - */ - return (ENOENT); - } - /* - * In case of "All" profile, we'd go through pfexec - * if it had any attributes. - */ - if ((exec->attr != NULL) && (exec->attr->length != 0)) { - /* - * command in profile and has attributes - */ - free_execattr(exec); - arg_v[0] = (char *)command; - pfarg_v = secpolicy_set_argv(arg_v); - if (pfarg_v != NULL) { - errno = 0; - if (xecenv == NULL) { - execv(PFEXEC, (char *const *)pfarg_v); - } else { - execve(PFEXEC, (char *const *)pfarg_v, - (char *const *)xecenv); - } - free(pfarg_v); - status = errno; - } else { - status = ENOMEM; - } - } else { - /* - * command in profile, but has no attributes - */ - free_execattr(exec); - status = NOATTRS; - } - - - return (status); -} diff --git a/usr/src/cmd/sh/sh_policy.h b/usr/src/cmd/sh/sh_policy.h deleted file mode 100644 index 6efd47ca52..0000000000 --- a/usr/src/cmd/sh/sh_policy.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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 (c) 1999 by Sun Microsystems, Inc. - * All rights reserved. - */ - -#ifndef _SH_POLICY_H -#define _SH_POLICY_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -#include <exec_attr.h> - -#define PFEXEC "/usr/bin/pfexec" -#define ALL_PROFILE "All" - -#define ERR_PASSWD "can't get passwd entry" -#define ERR_MEM "can't allocate memory" -#define ERR_CWD "can't get current working directory" -#define ERR_PATH "resolved pathname too large" -#define ERR_PROFILE "not in profile" -#define ERR_REALPATH "can't get real path" - -#define NOATTRS 0 /* command in profile but w'out attributes */ - -#define SECPOLICY_WARN 1 -#define SECPOLICY_ERROR 2 - -/* - * Shell Policy Interface Functions - */ -extern void secpolicy_init(void); -extern int secpolicy_pfexec(const char *, char **, const char **); -extern void secpolicy_print(int, const char *); - - -#ifdef __cplusplus -} -#endif - -#endif /* _SH_POLICY_H */ diff --git a/usr/src/cmd/svc/configd/rc_node.c b/usr/src/cmd/svc/configd/rc_node.c index 5dbbce2091..a8aa4c32a7 100644 --- a/usr/src/cmd/svc/configd/rc_node.c +++ b/usr/src/cmd/svc/configd/rc_node.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -114,9 +113,7 @@ * proceed if the user has been assigned at least one of a set of * authorization strings. The set of enabling authorizations depends on the * operation and the target object. The set of authorizations assigned to - * a user is determined by reading /etc/security/policy.conf, querying the - * user_attr database, and possibly querying the prof_attr database, as per - * chkauthattr() in libsecdb. + * a user is determined by an algorithm defined in libsecdb. * * The fastest way to decide whether the two sets intersect is by entering the * strings into a hash table and detecting collisions, which takes linear time @@ -360,7 +357,6 @@ #include <libuutil.h> #include <libscf.h> #include <libscf_priv.h> -#include <prof_attr.h> #include <pthread.h> #include <pwd.h> #include <stdio.h> @@ -369,7 +365,7 @@ #include <sys/types.h> #include <syslog.h> #include <unistd.h> -#include <user_attr.h> +#include <secdb.h> #include "configd.h" @@ -388,8 +384,6 @@ #define AUTH_PROP_MODIFY "modify_authorization" #define AUTH_PROP_VALUE "value_authorization" #define AUTH_PROP_READ "read_authorization" -/* libsecdb should take care of this. */ -#define RBAC_AUTH_SEP "," #define MAX_VALID_CHILDREN 3 @@ -1498,29 +1492,24 @@ perm_add_enabling(permcheck_t *pcp, const char *auth) * perm_granted() returns PERM_GRANTED if the current door caller has one of * the enabling authorizations in pcp, PERM_DENIED if it doesn't, PERM_GONE if * the door client went away and PERM_FAIL if an error (usually lack of - * memory) occurs. check_auth_list() checks an RBAC_AUTH_SEP-separated - * list of authorizations for existence in pcp, and check_prof_list() - * checks the authorizations granted to an RBAC_AUTH_SEP-separated list of - * profiles. + * memory) occurs. auth_cb() checks each and every authorizations as + * enumerated by _enum_auths. When we find a result other than PERM_DENIED, + * we short-cut the enumeration and return non-zero. */ -static perm_status_t -check_auth_list(permcheck_t *pcp, char *authlist) -{ - char *auth, *lasts; - perm_status_t ret; - for (auth = (char *)strtok_r(authlist, RBAC_AUTH_SEP, &lasts); - auth != NULL; - auth = (char *)strtok_r(NULL, RBAC_AUTH_SEP, &lasts)) { - if (strchr(auth, KV_WILDCHAR) == NULL) - ret = pc_exists(pcp, auth); - else - ret = pc_match(pcp, auth); +static int +auth_cb(const char *auth, void *ctxt, void *vres) +{ + permcheck_t *pcp = ctxt; + int *pret = vres; - if (ret != PERM_DENIED) - return (ret); - } + if (strchr(auth, KV_WILDCHAR) == NULL) + *pret = pc_exists(pcp, auth); + else + *pret = pc_match(pcp, auth); + if (*pret != PERM_DENIED) + return (1); /* * If we failed, choose the most specific auth string for use in * the audit event. @@ -1528,40 +1517,7 @@ check_auth_list(permcheck_t *pcp, char *authlist) assert(pcp->pc_specific != NULL); pcp->pc_auth_string = pcp->pc_specific->pce_auth; - return (PERM_DENIED); -} - -static perm_status_t -check_prof_list(permcheck_t *pcp, char *proflist) -{ - char *prof, *lasts, *authlist, *subproflist; - profattr_t *pap; - perm_status_t ret = PERM_DENIED; - - for (prof = strtok_r(proflist, RBAC_AUTH_SEP, &lasts); - prof != NULL; - prof = strtok_r(NULL, RBAC_AUTH_SEP, &lasts)) { - pap = getprofnam(prof); - if (pap == NULL) - continue; - - authlist = kva_match(pap->attr, PROFATTR_AUTHS_KW); - if (authlist != NULL) - ret = check_auth_list(pcp, authlist); - - if (ret == PERM_DENIED) { - subproflist = kva_match(pap->attr, PROFATTR_PROFS_KW); - if (subproflist != NULL) - /* depth check to avoid infinite recursion? */ - ret = check_prof_list(pcp, subproflist); - } - - free_profattr(pap); - if (ret != PERM_DENIED) - return (ret); - } - - return (ret); + return (0); /* Tells that we need to continue */ } static perm_status_t @@ -1570,10 +1526,7 @@ perm_granted(permcheck_t *pcp) ucred_t *uc; perm_status_t ret = PERM_DENIED; - int rv; uid_t uid; - userattr_t *uap; - char *authlist, *userattr_authlist, *proflist, *def_prof = NULL; struct passwd pw; char pwbuf[1024]; /* XXX should be NSS_BUFLEN_PASSWD */ @@ -1606,51 +1559,12 @@ perm_granted(permcheck_t *pcp) } /* - * Get user's default authorizations from policy.conf + * Enumerate all the auths defined for the user and return the + * result in ret. */ - rv = _get_user_defs(pw.pw_name, &authlist, &def_prof); - - if (rv != 0) + if (_enum_auths(pw.pw_name, auth_cb, pcp, &ret) < 0) return (PERM_FAIL); - if (authlist != NULL) { - ret = check_auth_list(pcp, authlist); - - if (ret != PERM_DENIED) { - _free_user_defs(authlist, def_prof); - return (ret); - } - } - - /* - * Put off checking def_prof for later in an attempt to consolidate - * prof_attr accesses. - */ - - uap = getusernam(pw.pw_name); - if (uap != NULL) { - /* Get the authorizations from user_attr. */ - userattr_authlist = kva_match(uap->attr, USERATTR_AUTHS_KW); - if (userattr_authlist != NULL) { - ret = check_auth_list(pcp, userattr_authlist); - } - } - - if ((ret == PERM_DENIED) && (def_prof != NULL)) { - /* Check generic profiles. */ - ret = check_prof_list(pcp, def_prof); - } - - if ((ret == PERM_DENIED) && (uap != NULL)) { - proflist = kva_match(uap->attr, USERATTR_PROFILES_KW); - if (proflist != NULL) - ret = check_prof_list(pcp, proflist); - } - - _free_user_defs(authlist, def_prof); - if (uap != NULL) - free_userattr(uap); - return (ret); } diff --git a/usr/src/cmd/truss/actions.c b/usr/src/cmd/truss/actions.c index e04db7bdb5..2dda60fb3e 100644 --- a/usr/src/cmd/truss/actions.c +++ b/usr/src/cmd/truss/actions.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1988 AT&T */ @@ -973,7 +972,7 @@ showargs(private_t *pri, int raw) if (raw) showpaths(pri, &systable[SYS_execve]); - show_cred(pri, FALSE); + show_cred(pri, FALSE, FALSE); if (aflag || eflag) { /* dump args or environment */ diff --git a/usr/src/cmd/truss/main.c b/usr/src/cmd/truss/main.c index 736b8bc2ef..151c7492ad 100644 --- a/usr/src/cmd/truss/main.c +++ b/usr/src/cmd/truss/main.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -47,6 +46,7 @@ #include <sys/mman.h> #include <sys/resource.h> #include <libproc.h> +#include <priv.h> #include "ramdata.h" #include "proto.h" #include "htbl.h" @@ -603,7 +603,7 @@ main(int argc, char *argv[]) if (created) { per_proc_init(); procadd(created, NULL); - show_cred(pri, TRUE); + show_cred(pri, TRUE, FALSE); } else { /* grab the specified processes */ int gotone = FALSE; @@ -1127,6 +1127,7 @@ worker_thread(void *arg) exit_called = TRUE; break; case SYS_execve: + show_cred(pri, FALSE, TRUE); (void) sysentry(pri, dotrace); if (dotrace && !cflag && prismember(&trace, what)) { @@ -2307,18 +2308,31 @@ fetchstring(private_t *pri, long addr, int maxleng) return (pri->str_buffer); } +static priv_set_t * +getset(prpriv_t *p, priv_ptype_t set) +{ + return ((priv_set_t *) + &p->pr_sets[priv_getsetbyname(set) * p->pr_setsize]); +} + void -show_cred(private_t *pri, int new) +show_cred(private_t *pri, int new, int loadonly) { prcred_t cred; + prpriv_t *privs; if (proc_get_cred(Pstatus(Proc)->pr_pid, &cred, 0) < 0) { - perror("show_cred()"); + perror("show_cred() - credential"); (void) printf("%s\t*** Cannot get credentials\n", pri->pname); return; } + if ((privs = proc_get_priv(Pstatus(Proc)->pr_pid)) == NULL) { + perror("show_cred() - privileges"); + (void) printf("%s\t*** Cannot get privileges\n", pri->pname); + return; + } - if (!cflag && prismember(&trace, SYS_execve)) { + if (!loadonly && !cflag && prismember(&trace, SYS_execve)) { if (new) credentials = cred; if ((new && cred.pr_ruid != cred.pr_suid) || @@ -2339,9 +2353,29 @@ show_cred(private_t *pri, int new) (int)cred.pr_rgid, (int)cred.pr_egid, (int)cred.pr_sgid); + if (privdata != NULL && cred.pr_euid != 0) { + priv_set_t *npset = getset(privs, PRIV_PERMITTED); + priv_set_t *opset = getset(privdata, PRIV_PERMITTED); + char *s, *t; + if (!priv_issubset(npset, opset)) { + /* Use the to be freed privdata as scratch */ + priv_inverse(opset); + priv_intersect(npset, opset); + s = priv_set_to_str(opset, ',', PRIV_STR_SHORT); + t = priv_set_to_str(npset, ',', PRIV_STR_SHORT); + (void) printf("%s *** FPRIV: P/E: %s ***\n", + pri->pname, + strlen(s) > strlen(t) ? t : s); + free(s); + free(t); + } + } } + if (privdata != NULL) + free(privdata); credentials = cred; + privdata = privs; } /* @@ -2479,7 +2513,7 @@ grabit(private_t *pri, proc_set_t *set) else (void) Punsetflags(Proc, PR_FORK); procadd(set->pid, set->lwps); - show_cred(pri, TRUE); + show_cred(pri, TRUE, FALSE); return (TRUE); } diff --git a/usr/src/cmd/truss/print.c b/usr/src/cmd/truss/print.c index 2848fd1490..c4ba8b2abd 100644 --- a/usr/src/cmd/truss/print.c +++ b/usr/src/cmd/truss/print.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -2257,6 +2256,7 @@ prt_pfl(private_t *pri, int raw, long val) case PRIV_AWARE: s = "PRIV_AWARE"; break; case PRIV_XPOLICY: s = "PRIV_XPOLICY"; break; case PRIV_AWARE_RESET: s = "PRIV_AWARE_RESET"; break; + case PRIV_PFEXEC: s = "PRIV_PFEXEC"; break; case NET_MAC_AWARE: s = "NET_MAC_AWARE"; break; case NET_MAC_AWARE_INHERIT: s = "NET_MAC_AWARE_INHERIT"; diff --git a/usr/src/cmd/truss/proto.h b/usr/src/cmd/truss/proto.h index 25f92cef67..670fe95f1b 100644 --- a/usr/src/cmd/truss/proto.h +++ b/usr/src/cmd/truss/proto.h @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -110,7 +109,7 @@ extern int fdlist(char *, fileset_t *); extern int liblist(char *, int); extern char *fetchstring(private_t *, long, int); -extern void show_cred(private_t *, int); +extern void show_cred(private_t *, int, int); extern void errmsg(const char *, const char *); extern void abend(const char *, const char *); diff --git a/usr/src/cmd/truss/ramdata.c b/usr/src/cmd/truss/ramdata.c index bd02ab6e2a..abb8ee202b 100644 --- a/usr/src/cmd/truss/ramdata.c +++ b/usr/src/cmd/truss/ramdata.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -52,6 +51,7 @@ uid_t Egid; /* truss's effective gid */ uid_t Ruid; /* truss's real uid */ uid_t Rgid; /* truss's real gid */ prcred_t credentials; /* traced process credentials */ +prpriv_t *privdata; /* traced process privileges */ int istty; /* TRUE iff output is a tty */ time_t starttime; /* start time */ diff --git a/usr/src/cmd/truss/ramdata.h b/usr/src/cmd/truss/ramdata.h index ea2bbdda46..788422827e 100644 --- a/usr/src/cmd/truss/ramdata.h +++ b/usr/src/cmd/truss/ramdata.h @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -136,6 +135,7 @@ extern uid_t Egid; /* truss's effective gid */ extern uid_t Ruid; /* truss's real uid */ extern uid_t Rgid; /* truss's real gid */ extern prcred_t credentials; /* traced process credentials */ +extern prpriv_t *privdata; /* traced process privileges */ extern int istty; /* TRUE iff output is a tty */ extern time_t starttime; /* start time */ diff --git a/usr/src/head/prof_attr.h b/usr/src/head/prof_attr.h index 42ff2d8534..b1ad96e116 100644 --- a/usr/src/head/prof_attr.h +++ b/usr/src/head/prof_attr.h @@ -19,15 +19,12 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _PROF_ATTR_H #define _PROF_ATTR_H -#pragma ident "%Z%%M% %I% %E% SMI" - #ifdef __cplusplus extern "C" { #endif @@ -50,6 +47,8 @@ extern "C" { #define PROFATTR_COL3_KW "desc" #define PROFATTR_COL4_KW "attr" +#define PROFILE_STOP "Stop" + #define DEF_PROF "PROFS_GRANTED=" #define DEF_CONSUSER "CONSOLE_USER=" diff --git a/usr/src/head/secdb.h b/usr/src/head/secdb.h index 105e44c8d8..be346e7e04 100644 --- a/usr/src/head/secdb.h +++ b/usr/src/head/secdb.h @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SECDB_H @@ -49,6 +48,8 @@ extern "C" { #define KV_WILDCARD "*" #define KV_WILDCHAR '*' #define KV_ACTION_WILDCARD "*;*;*;*;*" +#define KV_SEPCHAR ',' +#define KV_SEPSTR "," #define KV_FLAG_NONE 0x0000 #define KV_FLAG_REQUIRED 0x0001 @@ -84,8 +85,12 @@ extern kva_t *_kva_dup(kva_t *); extern void _kva_free(kva_t *); extern kva_t *_new_kva(int size); extern kva_t *_str2kva(char *, char *, char *); -extern int _get_user_defs(const char *, char **, char **); -extern void _free_user_defs(char *, char *); +extern int _enum_auths(const char *, int (*)(const char *, void *, void *), + void *ctxt, void *pres); +extern int _enum_profs(const char *, + int (*)(const char *, kva_t *, void *, void *), void *ctxt, void *pres); +extern int _enum_attrs(const char *, + int (*)(const char *, kva_t *, void *, void *), void *ctxt, void *pres); #ifdef __cplusplus } diff --git a/usr/src/lib/libbsm/audit_event.txt b/usr/src/lib/libbsm/audit_event.txt index 8ee50ca320..06aa34a2fa 100644 --- a/usr/src/lib/libbsm/audit_event.txt +++ b/usr/src/lib/libbsm/audit_event.txt @@ -1,6 +1,5 @@ # -# Copyright 2010 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. # # # CDDL HEADER START @@ -183,6 +182,7 @@ 113:AUE_SYSTEMBOOT:system booted:na 114:AUE_ASYNC_DAEMON_EXIT:async_daemon(2) exited:no 115:AUE_NFSSVC_EXIT:nfssvc(2) exited:no +116:AUE_PFEXEC:execve(2) with pfexec enabled:ps,ex,ua,as 130:AUE_GETAUID:getauid(2):aa 131:AUE_SETAUID:setauid(2):aa 132:AUE_GETAUDIT:getaudit(2):aa diff --git a/usr/src/lib/libc/port/gen/getusershell.c b/usr/src/lib/libc/port/gen/getusershell.c index 368fa72a61..df10f2f6fd 100644 --- a/usr/src/lib/libc/port/gen/getusershell.c +++ b/usr/src/lib/libc/port/gen/getusershell.c @@ -1,6 +1,5 @@ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -12,8 +11,6 @@ * specifies the terms and conditions for redistribution. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include "lint.h" #include <sys/types.h> #include <sys/param.h> @@ -56,16 +53,25 @@ const char *okshells[] = { "/usr/bin/pfsh", "/usr/bin/pfcsh", "/usr/bin/pfksh", + "/usr/bin/pfksh93", "/usr/bin/bash", "/usr/bin/tcsh", "/usr/bin/zsh", + "/usr/bin/pfbash", + "/usr/bin/pftcsh", + "/usr/bin/pfzsh", "/bin/pfsh", "/bin/pfcsh", "/bin/pfksh", + "/bin/pfksh93", "/bin/bash", "/bin/tcsh", "/bin/zsh", + "/bin/pfbash", + "/bin/pftcsh", + "/bin/pfzsh", "/usr/xpg4/bin/sh", + "/usr/xpg4/bin/pfsh", "/sbin/pfsh", "/usr/sfw/bin/zsh", NULL diff --git a/usr/src/lib/libc/port/gen/privlib.c b/usr/src/lib/libc/port/gen/privlib.c index aecb11c3b4..b490434997 100644 --- a/usr/src/lib/libc/port/gen/privlib.c +++ b/usr/src/lib/libc/port/gen/privlib.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ #pragma weak _getprivimplinfo = getprivimplinfo @@ -871,11 +870,7 @@ priv_emptyset(priv_set_t *set) void priv_basicset(priv_set_t *set) { - priv_data_t *d; - - LOADPRIVDATA(d); - - priv_copyset(d->pd_basicset, set); + priv_copyset(priv_basic(), set); } void diff --git a/usr/src/lib/libsecdb/common/chkauthattr.c b/usr/src/lib/libsecdb/common/chkauthattr.c index e5f0093342..7f8be5aa4d 100644 --- a/usr/src/lib/libsecdb/common/chkauthattr.c +++ b/usr/src/lib/libsecdb/common/chkauthattr.c @@ -22,14 +22,11 @@ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ +#include <alloca.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sys/types.h> #include <sys/stat.h> -#include <fcntl.h> -#include <sys/mman.h> -#include <limits.h> #include <pwd.h> #include <nss_dbdefs.h> #include <deflt.h> @@ -37,115 +34,261 @@ #include <prof_attr.h> #include <user_attr.h> +#define COPYTOSTACK(dst, csrc) { \ + size_t len = strlen(csrc) + 1; \ + dst = alloca(len); \ + (void) memcpy(dst, csrc, len); \ + } + +static kva_t *get_default_attrs(const char *); +static void free_default_attrs(kva_t *); + +/* + * Enumeration functions for auths and profiles; the enumeration functions + * take a callback with four arguments: + * const char * profile name (or NULL unless wantattr is false) + * kva_t * attributes (or NULL unless wantattr is true) + * void * context + * void * pointer to the result + * When the call back returns non-zero, the enumeration ends. + * The function might be NULL but only for profiles as we are always collecting + * all the profiles. + * Both the auths and the profiles arguments may be NULL. + * + * These should be the only implementation of the algorithm of "finding me + * all the profiles/athorizations/keywords/etc. + */ -static int _is_authorized(const char *, char *); -static int _chk_policy_auth(const char *, const char *, char **, int *); -static int _chkprof_for_auth(const char *, const char *, char **, int *); +#define CONSUSER_PROFILE_KW "consprofile" +#define DEF_LOCK_AFTER_RETRIES "LOCK_AFTER_RETRIES=" + +static struct dfltplcy { + char *attr; + const char *defkw; +} dfltply[] = { + /* CONSUSER MUST BE FIRST! */ + { CONSUSER_PROFILE_KW, DEF_CONSUSER}, + { PROFATTR_AUTHS_KW, DEF_AUTH}, + { PROFATTR_PROFS_KW, DEF_PROF}, + { USERATTR_LIMPRIV_KW, DEF_LIMITPRIV}, + { USERATTR_DFLTPRIV_KW, DEF_DFLTPRIV}, + { USERATTR_LOCK_AFTER_RETRIES_KW, DEF_LOCK_AFTER_RETRIES} +}; + +#define NDFLTPLY (sizeof (dfltply)/sizeof (struct dfltplcy)) +#define GETCONSPROF(a) (kva_match((a), CONSUSER_PROFILE_KW)) +#define GETPROF(a) (kva_match((a), PROFATTR_PROFS_KW)) + +/* + * Enumerate profiles from listed profiles. + */ int -chkauthattr(const char *authname, const char *username) +_enum_common_p(const char *cprofiles, + int (*cb)(const char *, kva_t *, void *, void *), + void *ctxt, void *pres, boolean_t wantattr, + int *pcnt, char *profs[MAXPROFS]) { - int auth_granted = 0; - char *auths; - char *profiles; - userattr_t *user = NULL; - char *chkedprof[MAXPROFS]; - int chkedprof_cnt = 0; - int i; + char *prof, *last; + char *profiles; + profattr_t *pa; + int i; + int res = 0; - if (authname == NULL || username == NULL) + if (cprofiles == NULL) return (0); - /* Check against AUTHS_GRANTED and PROFS_GRANTED in policy.conf */ - auth_granted = _chk_policy_auth(authname, username, chkedprof, - &chkedprof_cnt); - if (auth_granted) - goto exit; + if (*pcnt > 0 && strcmp(profs[*pcnt - 1], PROFILE_STOP) == NULL) + return (0); - if ((user = getusernam(username)) == NULL) - goto exit; + COPYTOSTACK(profiles, cprofiles) - /* Check against authorizations listed in user_attr */ - if ((auths = kva_match(user->attr, USERATTR_AUTHS_KW)) != NULL) { - auth_granted = _is_authorized(authname, auths); - if (auth_granted) - goto exit; - } + while (prof = strtok_r(profiles, KV_SEPSTR, &last)) { - /* Check against authorizations specified by profiles */ - if ((profiles = kva_match(user->attr, USERATTR_PROFILES_KW)) != NULL) - auth_granted = _chkprof_for_auth(profiles, authname, - chkedprof, &chkedprof_cnt); + profiles = NULL; /* For next iterations of strtok_r */ -exit: - /* free memory allocated for checked array */ - for (i = 0; i < chkedprof_cnt; i++) { - free(chkedprof[i]); - } + for (i = 0; i < *pcnt; i++) + if (strcmp(profs[i], prof) == 0) + goto cont; - if (user != NULL) - free_userattr(user); + if (*pcnt >= MAXPROFS) /* oops: too many profs */ + return (-1); - return (auth_granted); + /* Add it */ + profs[(*pcnt)++] = strdup(prof); + + if (strcmp(profs[*pcnt - 1], PROFILE_STOP) == 0) + break; + + /* find the profiles for this profile */ + pa = getprofnam(prof); + + if (cb != NULL && (!wantattr || pa != NULL && pa->attr != NULL)) + res = cb(prof, pa ? pa->attr : NULL, ctxt, pres); + + if (pa != NULL) { + if (res == 0 && pa->attr != NULL) { + res = _enum_common_p(GETPROF(pa->attr), cb, + ctxt, pres, wantattr, pcnt, profs); + } + free_profattr(pa); + } + if (res != 0) + return (res); +cont: + continue; + } + return (res); } +/* + * Enumerate all attributes associated with a username and the profiles + * associated with the user. + */ static int -_chkprof_for_auth(const char *profs, const char *authname, - char **chkedprof, int *chkedprof_cnt) +_enum_common(const char *username, + int (*cb)(const char *, kva_t *, void *, void *), + void *ctxt, void *pres, boolean_t wantattr) { + userattr_t *ua; + int res = 0; + int cnt = 0; + char *profs[MAXPROFS]; + kva_t *kattrs; - char *prof, *lasts, *auths, *profiles; - profattr_t *pa; - int i; - int checked = 0; + if (cb == NULL) + return (-1); - for (prof = strtok_r((char *)profs, ",", &lasts); prof != NULL; - prof = strtok_r(NULL, ",", &lasts)) { + ua = getusernam(username); - checked = 0; - /* check if this profile has been checked */ - for (i = 0; i < *chkedprof_cnt; i++) { - if (strcmp(chkedprof[i], prof) == 0) { - checked = 1; - break; + if (ua != NULL) { + if (ua->attr != NULL) { + if (wantattr) + res = cb(NULL, ua->attr, ctxt, pres); + if (res == 0) { + res = _enum_common_p(GETPROF(ua->attr), + cb, ctxt, pres, wantattr, &cnt, profs); } } + free_userattr(ua); + if (res != 0) + return (res); + } - if (!checked) { - - chkedprof[*chkedprof_cnt] = strdup(prof); - *chkedprof_cnt = *chkedprof_cnt + 1; + if ((cnt == 0 || strcmp(profs[cnt-1], PROFILE_STOP) != 0) && + (kattrs = get_default_attrs(username)) != NULL) { - if ((pa = getprofnam(prof)) == NULL) - continue; + res = _enum_common_p(GETCONSPROF(kattrs), cb, ctxt, pres, + wantattr, &cnt, profs); - if ((auths = kva_match(pa->attr, - PROFATTR_AUTHS_KW)) != NULL) { - if (_is_authorized(authname, auths)) { - free_profattr(pa); - return (1); - } - } - if ((profiles = - kva_match(pa->attr, PROFATTR_PROFS_KW)) != NULL) { - /* Check for authorization in subprofiles */ - if (_chkprof_for_auth(profiles, authname, - chkedprof, chkedprof_cnt)) { - free_profattr(pa); - return (1); - } - } - free_profattr(pa); + if (res == 0) { + res = _enum_common_p(GETPROF(kattrs), cb, ctxt, pres, + wantattr, &cnt, profs); } + + if (res == 0 && wantattr) + res = cb(NULL, kattrs, ctxt, pres); + + free_default_attrs(kattrs); } - /* authorization not found in any profile */ - return (0); + + free_proflist(profs, cnt); + + return (res); +} + +/* + * Enumerate profiles with a username argument. + */ +int +_enum_profs(const char *username, + int (*cb)(const char *, kva_t *, void *, void *), + void *ctxt, void *pres) +{ + return (_enum_common(username, cb, ctxt, pres, B_FALSE)); +} + +/* + * Enumerate attributes with a username argument. + */ +int +_enum_attrs(const char *username, + int (*cb)(const char *, kva_t *, void *, void *), + void *ctxt, void *pres) +{ + return (_enum_common(username, cb, ctxt, pres, B_TRUE)); +} + + +/* + * Enumerate authorizations in the "auths" argument. + */ +static int +_enum_auths_a(const char *cauths, int (*cb)(const char *, void *, void *), + void *ctxt, void *pres) +{ + char *auth, *last, *auths; + int res = 0; + + if (cauths == NULL || cb == NULL) + return (0); + + COPYTOSTACK(auths, cauths) + + while (auth = strtok_r(auths, KV_SEPSTR, &last)) { + auths = NULL; /* For next iterations of strtok_r */ + + res = cb(auth, ctxt, pres); + + if (res != 0) + return (res); + } + return (res); +} + +/* + * Magic struct and function to allow using the _enum_attrs functions to + * enumerate the authorizations. + */ +typedef struct ccomm2auth { + int (*cb)(const char *, void *, void *); + void *ctxt; +} ccomm2auth; + +/*ARGSUSED*/ +static int +comm2auth(const char *name, kva_t *attr, void *ctxt, void *pres) +{ + ccomm2auth *ca = ctxt; + char *auths; + + /* Note: PROFATTR_AUTHS_KW is equal to USERATTR_AUTHS_KW */ + auths = kva_match(attr, PROFATTR_AUTHS_KW); + return (_enum_auths_a(auths, ca->cb, ca->ctxt, pres)); +} + +/* + * Enumerate authorizations for username. + */ +int +_enum_auths(const char *username, + int (*cb)(const char *, void *, void *), + void *ctxt, void *pres) +{ + ccomm2auth c2a; + + if (cb == NULL) + return (-1); + + c2a.cb = cb; + c2a.ctxt = ctxt; + + return (_enum_common(username, comm2auth, &c2a, pres, B_TRUE)); } int _auth_match(const char *pattern, const char *auth) { size_t len; - char wildcard = KV_WILDCHAR; char *grant; len = strlen(pattern); @@ -154,7 +297,7 @@ _auth_match(const char *pattern, const char *auth) * If the wildcard is not in the last position in the string, don't * match against it. */ - if (pattern[len-1] != wildcard) + if (pattern[len-1] != KV_WILDCHAR) return (0); /* @@ -173,66 +316,32 @@ _auth_match(const char *pattern, const char *auth) } static int -_is_authorized(const char *authname, char *auths) +_is_authorized(const char *auth, void *authname, void *res) { - int found = 0; /* have we got a match, yet */ - char wildcard = '*'; - char *auth; /* current authorization being compared */ - char *buf; - char *lasts; - - buf = strdup(auths); - for (auth = strtok_r(auths, ",", &lasts); auth != NULL && !found; - auth = strtok_r(NULL, ",", &lasts)) { - if (strcmp((char *)authname, auth) == 0) { - /* Exact match. We're done. */ - found = 1; - } else if (strchr(auth, wildcard) != NULL) { - if (_auth_match(auth, authname)) { - found = 1; - break; - } - } - } + int *resp = res; - free(buf); + if (strcmp(authname, auth) == 0 || + (strchr(auth, KV_WILDCHAR) != NULL && + _auth_match(auth, authname))) { + *resp = 1; + return (1); + } - return (found); + return (0); } - -/* - * read /etc/security/policy.conf for AUTHS_GRANTED. - * return 1 if found matching authname. - * Otherwise, read PROFS_GRANTED to see if authname exists in any - * default profiles. - */ -static int -_chk_policy_auth(const char *authname, const char *username, char **chkedprof, - int *chkedprof_cnt) +int +chkauthattr(const char *authname, const char *username) { - char *auths = NULL; - char *profs = NULL; - int ret = 1; + int auth_granted = 0; - if (_get_user_defs(username, &auths, &profs) != 0) + if (authname == NULL || username == NULL) return (0); - if (auths != NULL) { - if (_is_authorized(authname, auths)) - goto exit; - } - - if (profs != NULL) { - if (_chkprof_for_auth(profs, authname, chkedprof, - chkedprof_cnt)) - goto exit; - } - ret = 0; + (void) _enum_auths(username, _is_authorized, (char *)authname, + &auth_granted); -exit: - _free_user_defs(auths, profs); - return (ret); + return (auth_granted); } #define CONSOLE_USER_LINK "/dev/vt/console_user" @@ -257,77 +366,58 @@ is_cons_user(const char *user) return (pw.pw_uid == cons.st_uid); } +static void +free_default_attrs(kva_t *kva) +{ + int i; + + for (i = 0; i < kva->length; i++) + free(kva->data[i].value); -int -_get_user_defs(const char *user, char **def_auth, char **def_prof) + free(kva); +} + +/* + * Return the default attributes; this are ignored when a STOP profile + * was found. + */ +static kva_t * +get_default_attrs(const char *user) { - char *cp; - char *profs; - void *defp; + void *defp; + kva_t *kva; + int i; - if ((defp = defopen_r(AUTH_POLICY)) == NULL) { - if (def_auth != NULL) { - *def_auth = NULL; - } - if (def_prof != NULL) { - *def_prof = NULL; - } - return (-1); - } + kva = malloc(sizeof (kva_t) + sizeof (kv_t) * NDFLTPLY); - if (def_auth != NULL) { - if ((cp = defread_r(DEF_AUTH, defp)) != NULL) { - if ((*def_auth = strdup(cp)) == NULL) { - defclose_r(defp); - return (-1); - } - } else { - *def_auth = NULL; - } - } - if (def_prof != NULL) { - if (is_cons_user(user) && - (cp = defread_r(DEF_CONSUSER, defp)) != NULL) { - if ((*def_prof = strdup(cp)) == NULL) { - defclose_r(defp); - return (-1); - } - } - if ((cp = defread_r(DEF_PROF, defp)) != NULL) { - int prof_len; - - if (*def_prof == NULL) { - if ((*def_prof = strdup(cp)) == NULL) { - defclose_r(defp); - return (-1); - } - defclose_r(defp); - return (0); - } + if (kva == NULL) + return (NULL); - /* concatenate def profs with "," separator */ - prof_len = strlen(*def_prof) + strlen(cp) + 2; - if ((profs = malloc(prof_len)) == NULL) { - free(*def_prof); - *def_prof = NULL; - defclose_r(defp); - return (-1); - } - (void) snprintf(profs, prof_len, "%s,%s", *def_prof, - cp); - free(*def_prof); - *def_prof = profs; - } + kva->data = (kv_t *)(void *)&kva[1]; + kva->length = 0; + + if ((defp = defopen_r(AUTH_POLICY)) == NULL) + goto return_null; + + for (i = is_cons_user(user) ? 0 : 1; i < NDFLTPLY; i++) { + char *cp = defread_r(dfltply[i].defkw, defp); + + if (cp == NULL) + continue; + if ((cp = strdup(cp)) == NULL) + goto return_null; + + kva->data[kva->length].key = dfltply[i].attr; + kva->data[kva->length++].value = cp; } - defclose_r(defp); - return (0); -} + (void) defclose_r(defp); + return (kva); +return_null: + if (defp != NULL) + (void) defclose_r(defp); -void -_free_user_defs(char *def_auth, char *def_prof) -{ - free(def_auth); - free(def_prof); + free_default_attrs(kva); + return (NULL); } diff --git a/usr/src/lib/libsecdb/common/getexecattr.c b/usr/src/lib/libsecdb/common/getexecattr.c index b6ffb1dab3..f4c48f1023 100644 --- a/usr/src/lib/libsecdb/common/getexecattr.c +++ b/usr/src/lib/libsecdb/common/getexecattr.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/types.h> @@ -220,88 +219,68 @@ free_execattr(execattr_t *exec) } } +typedef struct call { + const char *type; + const char *id; + int sflag; +} call; + +typedef struct result { + execattr_t *head; + execattr_t *prev; +} result; + +/*ARGSUSED*/ +static int +findexecattr(const char *prof, kva_t *kva, void *ctxt, void *res) +{ + execattr_t *exec; + call *c = ctxt; + result *r = res; + + if ((exec = getexecprof(prof, c->type, c->id, c->sflag)) != NULL) { + if (IS_GET_ONE(c->sflag)) { + r->head = exec; + return (1); + } else if (IS_GET_ALL(c->sflag)) { + if (r->head == NULL) { + r->head = exec; + r->prev = get_tail(r->head); + } else { + r->prev->next = exec; + r->prev = get_tail(exec); + } + } + } + return (0); +} + static execattr_t * userprof(const char *username, const char *type, const char *id, int search_flag) { - int err = 0; - char *last; - char *sep = ","; - char *proflist = NULL; - char *profname = NULL; - char buf[NSS_BUFLEN_USERATTR]; char pwdb[NSS_BUFLEN_PASSWD]; - kva_t *user_attr; - userstr_t user; - userstr_t *utmp; - execattr_t *exec; - execattr_t *head = NULL; - execattr_t *prev = NULL; struct passwd pwd; - - char *profArray[MAXPROFS]; - int profcnt = 0; - int i; + call call; + result result; /* * Check if specified username is valid user */ if (getpwnam_r(username, &pwd, pwdb, sizeof (pwdb)) == NULL) { - return (head); + return (NULL); } - utmp = _getusernam(username, &user, buf, NSS_BUFLEN_USERATTR, &err); - if (utmp != NULL) { - user_attr = _str2kva(user.attr, KV_ASSIGN, KV_DELIMITER); - if ((proflist = kva_match(user_attr, "profiles")) != NULL) { - /* Get the list of profiles for this user */ - for (profname = _strtok_escape(proflist, sep, &last); - profname != NULL; - profname = _strtok_escape(NULL, sep, &last)) { - getproflist(profname, profArray, &profcnt); - } - } - } + result.head = result.prev = NULL; + call.type = type; + call.id = id; + call.sflag = search_flag; - /* Get the list of default profiles */ - proflist = NULL; - (void) _get_user_defs(username, NULL, &proflist); - if (proflist != NULL) { - for (profname = _strtok_escape(proflist, sep, &last); - profname != NULL; - profname = _strtok_escape(NULL, sep, &last)) { - getproflist(profname, profArray, &profcnt); - } - _free_user_defs(NULL, proflist); - } + (void) _enum_profs(username, findexecattr, &call, &result); - if (profcnt == 0) { - return (head); - } - - /* Get execs from the list of profiles */ - for (i = 0; i < profcnt; i++) { - profname = profArray[i]; - if ((exec = getexecprof(profname, type, id, search_flag)) != - NULL) { - if (IS_GET_ONE(search_flag)) { - head = exec; - break; - } else if (IS_GET_ALL(search_flag)) { - if (head == NULL) { - head = exec; - prev = get_tail(head); - } else { - prev->next = exec; - prev = get_tail(exec); - } - } - } - } - free_proflist(profArray, profcnt); - return (head); + return (result.head); } diff --git a/usr/src/lib/libsecdb/common/getprofattr.c b/usr/src/lib/libsecdb/common/getprofattr.c index bb3173672c..ac9b9b0c36 100644 --- a/usr/src/lib/libsecdb/common/getprofattr.c +++ b/usr/src/lib/libsecdb/common/getprofattr.c @@ -19,12 +19,9 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <stdio.h> #include <string.h> @@ -121,6 +118,9 @@ profstr2attr(profstr_t *prof) } +extern int _enum_common_p(const char *, int (*)(const char *, kva_t *, void *, + void *), void *, void *, boolean_t, int *, char *[MAXPROFS]); + /* * Given a profile name, gets the list of profiles found from * the whole hierarchy, using the given profile as root @@ -128,44 +128,12 @@ profstr2attr(profstr_t *prof) void getproflist(const char *profileName, char **profArray, int *profcnt) { - profattr_t *profattr; - char *subprofiles, *lasts, *profname; - int i; - - /* Check if this is a duplicate */ - for (i = 0; i < *profcnt; i++) { - if (strcmp(profileName, profArray[i]) == 0) { - /* It's a duplicate, don't need to do anything */ - return; - } - } - - profArray[*profcnt] = strdup(profileName); - *profcnt = *profcnt + 1; - - profattr = getprofnam(profileName); - if (profattr == NULL) { + /* There can't be a "," in a profile name. */ + if (strchr(profileName, KV_SEPCHAR) != NULL) return; - } - if (profattr->attr == NULL) { - free_profattr(profattr); - return; - } - - subprofiles = kva_match(profattr->attr, PROFATTR_PROFS_KW); - if (subprofiles == NULL) { - free_profattr(profattr); - return; - } - - /* get execattr from each subprofiles */ - for (profname = (char *)strtok_r(subprofiles, ",", &lasts); - profname != NULL; - profname = (char *)strtok_r(NULL, ",", &lasts)) { - getproflist(profname, profArray, profcnt); - } - free_profattr(profattr); + (void) _enum_common_p(profileName, NULL, NULL, NULL, B_FALSE, + profcnt, profArray); } void diff --git a/usr/src/lib/libsecdb/common/mapfile-vers b/usr/src/lib/libsecdb/common/mapfile-vers index 1b85f8324d..87d4e1ada5 100644 --- a/usr/src/lib/libsecdb/common/mapfile-vers +++ b/usr/src/lib/libsecdb/common/mapfile-vers @@ -19,8 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # # @@ -76,14 +75,15 @@ SUNWprivate_1.1 { _csl_to_argv; _do_unescape; _free_argv; - _free_user_defs; - _get_user_defs; _insert2kva; _kva2str; _kva_dup; _kva_free; _new_kva; _str2kva; + _enum_profs; + _enum_auths; + _enum_attrs; local: *; }; diff --git a/usr/src/lib/libsecdb/exec_attr.txt b/usr/src/lib/libsecdb/exec_attr.txt index f4f302987e..f9c90e41d0 100644 --- a/usr/src/lib/libsecdb/exec_attr.txt +++ b/usr/src/lib/libsecdb/exec_attr.txt @@ -20,7 +20,6 @@ # # Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - # # /etc/security/exec_attr # @@ -110,6 +109,25 @@ File System Management:suser:cmd:::/usr/sbin/umount:uid=0 File System Management:suser:cmd:::/usr/sbin/umountall:uid=0 File System Management:suser:cmd:::/usr/sbin/unshare:uid=0;gid=root File System Management:suser:cmd:::/usr/sbin/unshareall:uid=0;gid=root +Forced Privilege:solaris:cmd:::/usr/bin/newtask:\ + privs=proc_taskid,sys_resource,sys_res_config,proc_priocntl +Forced Privilege:solaris:cmd:::/usr/bin/rcp:privs=net_privaddr +Forced Privilege:solaris:cmd:::/usr/bin/rdist:privs=net_privaddr +Forced Privilege:solaris:cmd:::/usr/bin/rlogin:privs=net_privaddr +Forced Privilege:solaris:cmd:::/usr/bin/rmformat:\ + privs=file_dac_read,file_dac_write,proc_fork,proc_exec,sys_mount,sys_devices +Forced Privilege:solaris:cmd:::/usr/bin/rsh:privs=net_privaddr +Forced Privilege:solaris:cmd:::/usr/bin/w:privs=proc_owner +Forced Privilege:solaris:cmd:::/usr/lib/fs/ufs/quota:privs=file_dac_read +Forced Privilege:solaris:cmd:::/usr/lib/fs/ufs/ufsdump:privs=net_privaddr +Forced Privilege:solaris:cmd:::/usr/lib/fs/ufs/ufsrestore:privs=net_privaddr +Forced Privilege:solaris:cmd:::/usr/sbin/ping:\ + privs=net_icmpaccess,sys_ip_config +Forced Privilege:solaris:cmd:::/usr/sbin/traceroute:\ + privs=net_icmpaccess,net_rawaccess +Forced Privilege:solaris:cmd:::/usr/sbin/whodo:privs=proc_owner +Forced Privilege:solaris:cmd:::/usr/lib/fs/smbfs/mount:privs=sys_mount +Forced Privilege:solaris:cmd:::/usr/lib/fs/smbfs/umount:privs=sys_mount IP Filter Management:solaris:cmd:::/usr/sbin/ipf:privs=sys_ip_config IP Filter Management:solaris:cmd:::/usr/sbin/ipfs:privs=sys_ip_config IP Filter Management:solaris:cmd:::/usr/sbin/ipmon:privs=sys_ip_config diff --git a/usr/src/lib/libsecdb/help/profiles/Makefile b/usr/src/lib/libsecdb/help/profiles/Makefile index d3e01a790c..e34952fc27 100644 --- a/usr/src/lib/libsecdb/help/profiles/Makefile +++ b/usr/src/lib/libsecdb/help/profiles/Makefile @@ -73,6 +73,7 @@ HTMLENTS = \ RtPrntAdmin.html \ RtProcManagement.html \ RtReparseMngmnt.html \ + RtReservedProfile.html \ RtRightsDelegate.html \ RtSMBMngmnt.html \ RtSMBFSMngmnt.html \ diff --git a/usr/src/lib/libsecdb/help/profiles/RtReservedProfile.html b/usr/src/lib/libsecdb/help/profiles/RtReservedProfile.html new file mode 100644 index 0000000000..d32f69608c --- /dev/null +++ b/usr/src/lib/libsecdb/help/profiles/RtReservedProfile.html @@ -0,0 +1,35 @@ +<HTML> +<!-- + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (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 (c) 2010, Oracle and/or its affiliates. All rights reserved. +--> +<HEAD> + <TITLE> </TITLE> + + +</HEAD> +<BODY> + +<p> +This is a reserved profile. Do not assign to users or roles. + +</BODY> +</HTML> diff --git a/usr/src/lib/libsecdb/prof_attr.txt b/usr/src/lib/libsecdb/prof_attr.txt index 8657bd40ac..3069b9bafe 100644 --- a/usr/src/lib/libsecdb/prof_attr.txt +++ b/usr/src/lib/libsecdb/prof_attr.txt @@ -44,6 +44,7 @@ Extended Accounting Task Management:::Manage the Task Extended Accounting servic Extended Accounting Net Management:::Manage the Net Extended Accounting service:auths=solaris.smf.manage.extended-accounting.net,solaris.smf.value.extended-accounting.net;profiles=acctadm;help=RtExActtNet.html File System Management:::Manage, mount, share file systems:profiles=SMB Management,VSCAN Management,SMBFS Management;auths=solaris.smf.manage.autofs,solaris.smf.manage.shares.*,solaris.smf.value.shares.*;help=RtFileSysMngmnt.html File System Security:::Manage file system security attributes:help=RtFileSysSecurity.html +Forced Privilege:::Commands with forced privileges associated with them:help=RtReservedProfile.html HAL Management:::Manage HAL SMF service:auths=solaris.smf.manage.hal;help=RtHALMngmnt.html Hotplug Management:::Manage Hotplug Connections:auths=solaris.smf.manage.hotplug,solaris.hotplug.*;help=RtHotplugMgmt.html Idmap Name Mapping Management:::Manage Name-based Mapping Rules of Identity Mapping Service:auths=solaris.admin.idmap.rules;help=RtIdmapNameRulesMngmnt.html @@ -78,6 +79,7 @@ Rmvolmgr Management:::Manage Removable Volume Manager SMF service:auths=solaris. Service Management:::Manage services:auths=solaris.smf.manage,solaris.smf.modify Service Operator:::Administer services:auths=solaris.smf.manage,solaris.smf.modify.framework Software Installation:::Add application software to the system:help=RtSoftwareInstall.html +Stop:::Last Profile evaluated, default profiles are not considered:help=RtReservedProfile.html System Administrator:::Can perform most non-security administrative tasks:profiles=Audit Review,Printer Management,Cron Management,Device Management,File System Management,Mail Management,Maintenance and Repair,Media Backup,Media Restore,Name Service Management,Network Management,Object Access Management,Process Management,Software Installation,User Management,Project Management,All;help=RtSysAdmin.html System Event Management:::Manage system events and system event channels:help=RtSysEvMngmnt.html User Management:::Manage users, groups, home directory:auths=solaris.profmgr.read;help=RtUserMngmnt.html diff --git a/usr/src/lib/libshell/Makefile.com b/usr/src/lib/libshell/Makefile.com index 1e76e04af0..32bba5796e 100644 --- a/usr/src/lib/libshell/Makefile.com +++ b/usr/src/lib/libshell/Makefile.com @@ -20,8 +20,7 @@ # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. # SHELL=/usr/bin/ksh93 @@ -131,7 +130,6 @@ LDLIBS += \ -ldll \ -last \ -lsocket \ - -lsecdb \ -lm \ -lc diff --git a/usr/src/lib/libshell/amd64/src/cmd/ksh93/FEATURE/options b/usr/src/lib/libshell/amd64/src/cmd/ksh93/FEATURE/options index 9d0e8e990a..1db7ff29eb 100644 --- a/usr/src/lib/libshell/amd64/src/cmd/ksh93/FEATURE/options +++ b/usr/src/lib/libshell/amd64/src/cmd/ksh93/FEATURE/options @@ -12,9 +12,7 @@ #ifndef SHOPT_DEVFD # define SHOPT_DEVFD 1 #endif -#ifndef SHOPT_PFSH -# define SHOPT_PFSH 1 -#endif +#undef SHOPT_PFSH #undef SHOPT_TEST_L #ifndef SHOPT_SYSRC # define SHOPT_SYSRC 1 diff --git a/usr/src/lib/libshell/i386/src/cmd/ksh93/FEATURE/options b/usr/src/lib/libshell/i386/src/cmd/ksh93/FEATURE/options index 0ca0c8c236..a17b564638 100644 --- a/usr/src/lib/libshell/i386/src/cmd/ksh93/FEATURE/options +++ b/usr/src/lib/libshell/i386/src/cmd/ksh93/FEATURE/options @@ -12,9 +12,7 @@ #ifndef SHOPT_DEVFD # define SHOPT_DEVFD 1 #endif -#ifndef SHOPT_PFSH -# define SHOPT_PFSH 1 -#endif +#undef SHOPT_PFSH #undef SHOPT_TEST_L #ifndef SHOPT_SYSRC # define SHOPT_SYSRC 1 diff --git a/usr/src/lib/libshell/sparc/src/cmd/ksh93/FEATURE/options b/usr/src/lib/libshell/sparc/src/cmd/ksh93/FEATURE/options index 8bace0bf6b..ad28f7a1fe 100644 --- a/usr/src/lib/libshell/sparc/src/cmd/ksh93/FEATURE/options +++ b/usr/src/lib/libshell/sparc/src/cmd/ksh93/FEATURE/options @@ -12,9 +12,7 @@ #ifndef SHOPT_DEVFD # define SHOPT_DEVFD 1 #endif -#ifndef SHOPT_PFSH -# define SHOPT_PFSH 1 -#endif +#undef SHOPT_PFSH #undef SHOPT_TEST_L #ifndef SHOPT_SYSRC # define SHOPT_SYSRC 1 diff --git a/usr/src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/options b/usr/src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/options index f794aeade3..d5d031e0ec 100644 --- a/usr/src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/options +++ b/usr/src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/options @@ -12,9 +12,7 @@ #ifndef SHOPT_DEVFD # define SHOPT_DEVFD 1 #endif -#ifndef SHOPT_PFSH -# define SHOPT_PFSH 1 -#endif +#undef SHOPT_PFSH #undef SHOPT_TEST_L #ifndef SHOPT_SYSRC # define SHOPT_SYSRC 1 diff --git a/usr/src/lib/pam_modules/unix_cred/unix_cred.c b/usr/src/lib/pam_modules/unix_cred/unix_cred.c index c7c35c70a7..fcaeecb320 100644 --- a/usr/src/lib/pam_modules/unix_cred/unix_cred.c +++ b/usr/src/lib/pam_modules/unix_cred/unix_cred.c @@ -75,21 +75,17 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) } /* - * Obtain a privilege set "keyname" from userattr; if none is present, - * fall back to the default, "defname". + * Set the privilege set. The attributes are enumerated by _enum_attrs, + * including the attribues user_attr, prof_attr and policy.conf */ static int -getset(char *keyname, char *defname, userattr_t *ua, priv_set_t **res, - void *defp) +getset(char *str, priv_set_t **res) { - char *str; priv_set_t *tmp; char *badp; int len; - if ((ua == NULL || ua->attr == NULL || - (str = kva_match(ua->attr, keyname)) == NULL) && - (defp == NULL || (str = defread_r(defname, defp)) == NULL)) + if (str == NULL) return (0); len = strlen(str) + 1; @@ -129,6 +125,31 @@ getset(char *keyname, char *defname, userattr_t *ua, priv_set_t **res, return (0); } +typedef struct deflim { + char *def; + char *lim; +} deflim_t; + +/*ARGSUSED*/ +static int +finddeflim(const char *name, kva_t *kva, void *ctxt, void *pres) +{ + deflim_t *pdef = pres; + char *val; + + if (pdef->def == NULL) { + val = kva_match(kva, USERATTR_DFLTPRIV_KW); + if (val != NULL) + pdef->def = strdup(val); + } + if (pdef->lim == NULL) { + val = kva_match(kva, USERATTR_LIMPRIV_KW); + if (val != NULL) + pdef->lim = strdup(val); + } + return (pdef->lim != NULL && pdef->def != NULL); +} + /* * unix_cred - pam_sm_setcred * @@ -162,7 +183,6 @@ pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) au_id_t auid; adt_session_data_t *ah; adt_termid_t *termid = NULL; - userattr_t *ua; priv_set_t *lim, *def, *tset; char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE]; char buf[PROJECT_BUFSZ]; @@ -172,7 +192,7 @@ pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) char *kvs; struct passwd pwd; char pwbuf[NSS_BUFLEN_PASSWD]; - void *defp; + deflim_t deflim; for (i = 0; i < argc; i++) { if (strcmp(argv[i], "debug") == 0) @@ -555,20 +575,23 @@ adt_done: return (PAM_SYSTEM_ERR); } - ua = getusernam(user); - - defp = defopen_r(AUTH_POLICY); - tset = def = lim = NULL; + deflim.def = deflim.lim = NULL; - if (getset(USERATTR_LIMPRIV_KW, DEF_LIMITPRIV, ua, &lim, defp) != 0 || - getset(USERATTR_DFLTPRIV_KW, DEF_DFLTPRIV, ua, &def, defp) != 0) { + (void) _enum_attrs(user, finddeflim, NULL, &deflim); + + if (getset(deflim.lim, &lim) != 0 || getset(deflim.def, &def) != 0) { ret = PAM_SYSTEM_ERR; goto out; } if (def == NULL) { - def = priv_str_to_set("basic", ",", NULL); + def = priv_allocset(); + if (def == NULL) { + ret = PAM_SYSTEM_ERR; + goto out; + } + priv_basicset(def); errno = 0; if ((pathconf("/", _PC_CHOWN_RESTRICTED) == -1) && (errno == 0)) (void) priv_addset(def, PRIV_FILE_CHOWN_SELF); @@ -627,13 +650,16 @@ adt_done: * when the uids are set to their final values. */ (void) setpflags(PRIV_AWARE, 0); + /* + * Remove PRIV_PFEXEC; stop running as if we are under a profile + * shell. A user with a profile shell will set PRIV_PFEXEC. + */ + (void) setpflags(PRIV_PFEXEC, 0); out: - if (defp != NULL) - defclose_r(defp); + free(deflim.lim); + free(deflim.def); - if (ua != NULL) - free_userattr(ua); if (lim != NULL) priv_freeset(lim); if (def != NULL) diff --git a/usr/src/pkg/manifests/SUNWcs.mf b/usr/src/pkg/manifests/SUNWcs.mf index f20c6e940e..2261c44e44 100644 --- a/usr/src/pkg/manifests/SUNWcs.mf +++ b/usr/src/pkg/manifests/SUNWcs.mf @@ -735,7 +735,7 @@ file path=usr/bin/pagesize mode=0555 file path=usr/bin/passwd group=sys mode=6555 file path=usr/bin/pathchk mode=0555 file path=usr/bin/pax mode=0555 -file path=usr/bin/pfexec mode=4555 +file path=usr/bin/pfexec mode=0555 file path=usr/bin/pg mode=0555 file path=usr/bin/pgrep mode=0555 file path=usr/bin/pkg2du mode=0555 @@ -1090,6 +1090,7 @@ file path=usr/lib/help/profiles/locale/C/RtPriAdmin.html file path=usr/lib/help/profiles/locale/C/RtPrntAdmin.html file path=usr/lib/help/profiles/locale/C/RtProcManagement.html file path=usr/lib/help/profiles/locale/C/RtReparseMngmnt.html +file path=usr/lib/help/profiles/locale/C/RtReservedProfile.html file path=usr/lib/help/profiles/locale/C/RtRightsDelegate.html file path=usr/lib/help/profiles/locale/C/RtSMBFSMngmnt.html file path=usr/lib/help/profiles/locale/C/RtSMBMngmnt.html @@ -1144,6 +1145,7 @@ file path=usr/lib/more.help file path=usr/lib/newsyslog group=sys mode=0555 file path=usr/lib/pci/pcidr mode=0555 file path=usr/lib/pci/pcidr_plugin.so +file path=usr/lib/pfexecd mode=0555 file path=usr/lib/platexec mode=0555 file path=usr/lib/rcm/modules/SUNW_aggr_rcm.so mode=0555 file path=usr/lib/rcm/modules/SUNW_cluster_rcm.so mode=0555 @@ -1963,6 +1965,7 @@ file path=lib/svc/manifest/system/keymap.xml group=sys mode=0444 file path=lib/svc/manifest/system/early-manifest-import.xml group=sys mode=0444 file path=lib/svc/manifest/system/manifest-import.xml group=sys mode=0444 file path=lib/svc/manifest/system/name-service-cache.xml group=sys mode=0444 +file path=lib/svc/manifest/system/pfexecd.xml group=sys mode=0444 file path=lib/svc/manifest/system/rbac.xml group=sys mode=0444 file path=lib/svc/manifest/system/rmtmpfiles.xml group=sys mode=0444 file path=lib/svc/manifest/system/sac.xml group=sys mode=0444 @@ -2006,20 +2009,12 @@ hardlink path=sbin/rc6 target=../sbin/rc0 hardlink path=usr/bin/$(ARCH32)/encrypt target=decrypt hardlink path=usr/bin/$(ARCH32)/ksh target=ksh93 hardlink path=usr/bin/$(ARCH32)/mac target=digest -hardlink path=usr/bin/$(ARCH32)/pfksh target=ksh93 -hardlink path=usr/bin/$(ARCH32)/pfksh93 target=ksh93 -hardlink path=usr/bin/$(ARCH32)/pfrksh target=ksh93 -hardlink path=usr/bin/$(ARCH32)/pfrksh93 target=ksh93 hardlink path=usr/bin/$(ARCH32)/rksh target=ksh93 hardlink path=usr/bin/$(ARCH32)/rksh93 target=ksh93 $(i386_ONLY)hardlink path=usr/bin/$(ARCH32)/w target=uptime hardlink path=usr/bin/$(ARCH64)/encrypt target=decrypt hardlink path=usr/bin/$(ARCH64)/ksh target=ksh93 hardlink path=usr/bin/$(ARCH64)/mac target=digest -hardlink path=usr/bin/$(ARCH64)/pfksh target=ksh93 -hardlink path=usr/bin/$(ARCH64)/pfksh93 target=ksh93 -hardlink path=usr/bin/$(ARCH64)/pfrksh target=ksh93 -hardlink path=usr/bin/$(ARCH64)/pfrksh93 target=ksh93 hardlink path=usr/bin/$(ARCH64)/rksh target=ksh93 hardlink path=usr/bin/$(ARCH64)/rksh93 target=ksh93 hardlink path=usr/bin/$(ARCH64)/w target=uptime @@ -2065,11 +2060,15 @@ hardlink path=usr/bin/nohup target=../../usr/lib/isaexec hardlink path=usr/bin/page target=../../usr/bin/more hardlink path=usr/bin/paste target=../../usr/bin/alias hardlink path=usr/bin/pdp11 target=../../usr/bin/i286 -hardlink path=usr/bin/pfcsh target=../../usr/bin/csh -hardlink path=usr/bin/pfksh target=../../usr/lib/isaexec -hardlink path=usr/bin/pfksh93 target=../../usr/lib/isaexec -hardlink path=usr/bin/pfrksh target=../../usr/lib/isaexec -hardlink path=usr/bin/pfrksh93 target=../../usr/lib/isaexec +hardlink path=usr/bin/pfbash target=../../usr/bin/pfexec +hardlink path=usr/bin/pfcsh target=../../usr/bin/pfexec +hardlink path=usr/bin/pfksh target=../../usr/bin/pfexec +hardlink path=usr/bin/pfksh93 target=../../usr/bin/pfexec +hardlink path=usr/bin/pfrksh target=../../usr/bin/pfexec +hardlink path=usr/bin/pfrksh93 target=../../usr/bin/pfexec +hardlink path=usr/bin/pfsh target=../../usr/bin/pfexec +hardlink path=usr/bin/pftcsh target=../../usr/bin/pfexec +hardlink path=usr/bin/pfzsh target=../../usr/bin/pfexec hardlink path=usr/bin/pkill target=../../usr/bin/pgrep hardlink path=usr/bin/prctl target=../../usr/lib/isaexec hardlink path=usr/bin/print target=../../usr/bin/alias @@ -2114,6 +2113,7 @@ hardlink path=usr/bin/w target=../../usr/lib/isaexec hardlink path=usr/bin/wait target=../../usr/bin/alias hardlink path=usr/bin/wc target=../../usr/bin/alias hardlink path=usr/has/bin/ex target=edit +hardlink path=usr/has/bin/pfsh target=../../bin/pfexec hardlink path=usr/has/bin/vedit target=edit hardlink path=usr/has/bin/vi target=edit hardlink path=usr/has/bin/view target=edit @@ -2501,6 +2501,7 @@ hardlink path=usr/share/lib/zoneinfo/W-SU \ target=../../../../usr/share/lib/zoneinfo/Europe/Moscow hardlink path=usr/share/lib/zoneinfo/Zulu \ target=../../../../usr/share/lib/zoneinfo/Etc/UTC +hardlink path=usr/xpg4/bin/pfsh target=../../bin/pfexec $(sparc_ONLY)hardlink path=etc/svc/profile/platform_SUNW,Sun-Fire-V890.xml \ target=./platform_SUNW,Sun-Fire-880.xml $(sparc_ONLY)hardlink \ @@ -2616,7 +2617,7 @@ link path=etc/whodo target=../usr/sbin/whodo link path=etc/wtmpx target=../var/adm/wtmpx link path=sbin/in.mpathd target=../lib/inet/in.mpathd link path=sbin/jsh target=../usr/bin/ksh93 -link path=sbin/pfsh target=../usr/bin/ksh93 +link path=sbin/pfsh target=../usr/bin/pfexec link path=sbin/sh target=../usr/bin/$(ARCH32)/ksh93 link path=sbin/su target=../usr/bin/su link path=usr/adm target=../var/adm @@ -2625,7 +2626,6 @@ link path=usr/bin/cachefsstat target=../lib/fs/cachefs/cachefsstat link path=usr/bin/df target=../sbin/df link path=usr/bin/jsh target=ksh93 link path=usr/bin/passmgmt target=../sbin/passmgmt -link path=usr/bin/pfsh target=ksh93 link path=usr/bin/pwconv target=../sbin/pwconv link path=usr/bin/rmail target=./mail link path=usr/bin/sh target=$(ARCH32)/ksh93 @@ -2636,7 +2636,6 @@ link path=usr/bin/tar target=../sbin/tar link path=usr/bin/uname target=../../sbin/uname link path=usr/ccs/bin/m4 target=../../bin/m4 link path=usr/has/bin/jsh target=sh -link path=usr/has/bin/pfsh target=sh link path=usr/has/lib/rsh target=../bin/sh link path=usr/lib/$(ARCH64)/ld.so.1 target=../../../lib/$(ARCH64)/ld.so.1 link path=usr/lib/cron target=../../etc/cron.d diff --git a/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf b/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf index b74a9f2125..88db18dd8b 100644 --- a/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf +++ b/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf @@ -269,6 +269,7 @@ file path=usr/lib/help/profiles/locale/RtPriAdmin.html file path=usr/lib/help/profiles/locale/RtPrntAdmin.html file path=usr/lib/help/profiles/locale/RtProcManagement.html file path=usr/lib/help/profiles/locale/RtReparseMngmnt.html +file path=usr/lib/help/profiles/locale/RtReservedProfile.html file path=usr/lib/help/profiles/locale/RtRightsDelegate.html file path=usr/lib/help/profiles/locale/RtSMBFSMngmnt.html file path=usr/lib/help/profiles/locale/RtSMBMngmnt.html diff --git a/usr/src/pkg/manifests/shell-ksh88.mf b/usr/src/pkg/manifests/shell-ksh88.mf index ef7b21aa75..525dc19cf9 100644 --- a/usr/src/pkg/manifests/shell-ksh88.mf +++ b/usr/src/pkg/manifests/shell-ksh88.mf @@ -1,5 +1,4 @@ -# -# CDDL HEADER START +# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). @@ -20,8 +19,7 @@ # # -# Copyright 2010 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # set name=pkg.fmri value=pkg:/shell/ksh88@$(PKGVERS) @@ -35,5 +33,5 @@ dir path=usr group=sys dir path=usr/has dir path=usr/has/bin file path=usr/has/bin/ksh mode=0555 -hardlink path=usr/has/bin/pfksh target=ksh +hardlink path=usr/has/bin/pfksh target=../../bin/pfexec hardlink path=usr/has/bin/rksh target=ksh diff --git a/usr/src/uts/common/c2/audit.c b/usr/src/uts/common/c2/audit.c index 3641e2b212..0e99e777a7 100644 --- a/usr/src/uts/common/c2/audit.c +++ b/usr/src/uts/common/c2/audit.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -60,7 +59,7 @@ #include <sys/disp.h> /* for servicing_interrupt() */ #include <sys/devpolicy.h> #include <sys/crypto/ioctladmin.h> -#include <sys/cred.h> +#include <sys/cred_impl.h> #include <inet/kssl/kssl.h> #include <net/pfpolicy.h> @@ -1232,13 +1231,13 @@ audit_vncreate_finish(struct vnode *vp, int error) * QUESTION: */ -/*ARGSUSED*/ void audit_exec( const char *argstr, /* argument strings */ const char *envstr, /* environment strings */ ssize_t argc, /* total # arguments */ - ssize_t envc) /* total # environment variables */ + ssize_t envc, /* total # environment variables */ + cred_t *pfcred) /* the additional privileges in a profile */ { t_audit_data_t *tad; au_kcontext_t *kctx = GET_KCTX_PZ; @@ -1249,17 +1248,52 @@ audit_exec( if (!tad->tad_flag) return; - /* return if not interested in argv or environment variables */ - if (!(kctx->auk_policy & (AUDIT_ARGV|AUDIT_ARGE))) - return; + if (pfcred != NULL) { + p_audit_data_t *pad; + cred_t *cr = CRED(); + priv_set_t pset = CR_IPRIV(cr); - if (kctx->auk_policy & AUDIT_ARGV) { - au_uwrite(au_to_exec_args(argstr, argc)); + pad = P2A(curproc); + + /* It's a different event. */ + tad->tad_event = AUE_PFEXEC; + + /* Add the current working directory to the audit trail. */ + if (pad->pad_cwd != NULL) + au_uwrite(au_to_path(pad->pad_cwd)); + + /* + * The new credential is not yet in place when audit_exec + * is called. + * Compute the additional bits available in the new credential + * and the limit set. + */ + priv_inverse(&pset); + priv_intersect(&CR_IPRIV(pfcred), &pset); + if (!priv_isemptyset(&pset) || + !priv_isequalset(&CR_LPRIV(pfcred), &CR_LPRIV(cr))) { + au_uwrite(au_to_privset( + priv_getsetbynum(PRIV_INHERITABLE), &pset, AUT_PRIV, + 0)); + au_uwrite(au_to_privset(priv_getsetbynum(PRIV_LIMIT), + &CR_LPRIV(pfcred), AUT_PRIV, 0)); + } + /* + * Compare the uids & gids: create a process token if changed. + */ + if (crgetuid(cr) != crgetuid(pfcred) || + crgetruid(cr) != crgetruid(pfcred) || + crgetgid(cr) != crgetgid(pfcred) || + crgetrgid(cr) != crgetrgid(pfcred)) { + AUDIT_SETPROC(&(u_ad), cr, crgetauinfo(cr)); + } } - if (kctx->auk_policy & AUDIT_ARGE) { + if (pfcred != NULL || (kctx->auk_policy & AUDIT_ARGV) != 0) + au_uwrite(au_to_exec_args(argstr, argc)); + + if (kctx->auk_policy & AUDIT_ARGE) au_uwrite(au_to_exec_env(envstr, envc)); - } } /* diff --git a/usr/src/uts/common/c2/audit.h b/usr/src/uts/common/c2/audit.h index 6be3d04f94..3b5e43cc50 100644 --- a/usr/src/uts/common/c2/audit.h +++ b/usr/src/uts/common/c2/audit.h @@ -529,7 +529,7 @@ void audit_reboot(void); void audit_vncreate_start(void); void audit_setfsat_path(int argnum); void audit_vncreate_finish(struct vnode *, int); -void audit_exec(const char *, const char *, ssize_t, ssize_t); +void audit_exec(const char *, const char *, ssize_t, ssize_t, cred_t *); void audit_enterprom(int); void audit_exitprom(int); void audit_chdirec(struct vnode *, struct vnode **); diff --git a/usr/src/uts/common/c2/audit_kernel.h b/usr/src/uts/common/c2/audit_kernel.h index d2c61c3257..956c30992a 100644 --- a/usr/src/uts/common/c2/audit_kernel.h +++ b/usr/src/uts/common/c2/audit_kernel.h @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _BSM_AUDIT_KERNEL_H @@ -409,6 +408,15 @@ au_buff_t *au_get_buff(void), *au_free_buff(au_buff_t *); #define AUDIT_SETSUBJ(u, c, a, k) \ AUDIT_SETSUBJ_GENERIC(u, c, a, k, curproc->p_pid) +#define AUDIT_SETPROC_GENERIC(u, c, a, p) \ + (au_write((u), au_to_process(crgetuid(c), \ + crgetgid(c), crgetruid(c), crgetrgid(c), \ + p, (a)->ai_auid, (a)->ai_asid, \ + &((a)->ai_termid)))); + +#define AUDIT_SETPROC(u, c, a) \ + AUDIT_SETPROC_GENERIC(u, c, a, curproc->p_pid) + /* * Macros for type conversion */ diff --git a/usr/src/uts/common/c2/audit_kevents.h b/usr/src/uts/common/c2/audit_kevents.h index fdc3c4dc37..b106fdd3d6 100644 --- a/usr/src/uts/common/c2/audit_kevents.h +++ b/usr/src/uts/common/c2/audit_kevents.h @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _BSM_AUDIT_KEVENTS_H @@ -159,8 +158,9 @@ extern "C" { #define AUE_SYSTEMBOOT 113 /* =na system booted */ #define AUE_ASYNC_DAEMON_EXIT 114 /* =no async_daemon(2) exited */ #define AUE_NFSSVC_EXIT 115 /* =no nfssvc(2) exited */ +#define AUE_PFEXEC 116 /* =ps,ex,ua,as execve(2) w/ pfexec */ /* - * 116 - 129 are available for future growth (old SunOS_CMW events + * 117 - 129 are available for future growth (old SunOS_CMW events * that had no libbsm or praudit support or references) */ #define AUE_GETAUID 130 /* =aa getauid(2) */ diff --git a/usr/src/uts/common/c2/audit_start.c b/usr/src/uts/common/c2/audit_start.c index 87f898f52f..6911b21094 100644 --- a/usr/src/uts/common/c2/audit_start.c +++ b/usr/src/uts/common/c2/audit_start.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -465,6 +464,11 @@ auditme(au_kcontext_t *kctx, struct t_audit_data *tad, au_state_t estate) kctx->auk_ets[AUE_SOCKRECEIVE]; if (amask.as_success & estate || amask.as_failure & estate) flag = 1; + } else if (tad->tad_scid == SYS_execve && + getpflags(PRIV_PFEXEC, CRED()) != 0) { + estate = kctx->auk_ets[AUE_PFEXEC]; + if (amask.as_success & estate || amask.as_failure & estate) + flag = 1; } return (flag); diff --git a/usr/src/uts/common/fs/autofs/auto_vfsops.c b/usr/src/uts/common/fs/autofs/auto_vfsops.c index 388b7d9c29..3bd5fa7591 100644 --- a/usr/src/uts/common/fs/autofs/auto_vfsops.c +++ b/usr/src/uts/common/fs/autofs/auto_vfsops.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/param.h> @@ -193,6 +192,9 @@ autofs_zone_destructor(zoneid_t zoneid, void *arg) return; ASSERT(fngp->fng_fnnode_count == 1); ASSERT(fngp->fng_unmount_threads == 0); + + if (fngp->fng_autofs_daemon_dh != NULL) + door_ki_rele(fngp->fng_autofs_daemon_dh); /* * vn_alloc() initialized the rootnode with a count of 1; we need to * make this 0 to placate auto_freefnnode(). diff --git a/usr/src/uts/common/fs/autofs/auto_vnops.c b/usr/src/uts/common/fs/autofs/auto_vnops.c index 344aae643b..ebe3ce4055 100644 --- a/usr/src/uts/common/fs/autofs/auto_vnops.c +++ b/usr/src/uts/common/fs/autofs/auto_vnops.c @@ -337,10 +337,8 @@ auto_access( if (groupmember(fnp->fn_gid, cred) == 0) shift += 3; } - mode &= ~(fnp->fn_mode << shift); - if (mode != 0) - error = secpolicy_vnode_access(cred, vp, fnp->fn_uid, - mode); + error = secpolicy_vnode_access2(cred, vp, fnp->fn_uid, + fnp->fn_mode << shift, mode); } done: diff --git a/usr/src/uts/common/fs/cachefs/cachefs_vnops.c b/usr/src/uts/common/fs/cachefs/cachefs_vnops.c index 5f5005d565..625a5ec553 100644 --- a/usr/src/uts/common/fs/cachefs/cachefs_vnops.c +++ b/usr/src/uts/common/fs/cachefs/cachefs_vnops.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/param.h> @@ -402,8 +401,8 @@ cachefs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) * cnode disallow writing while disconnected. */ if (crcmp(cp->c_cred, CRED()) != 0 && - secpolicy_vnode_access(CRED(), *vpp, - cp->c_attr.va_uid, VWRITE) != 0) { + secpolicy_vnode_access2(CRED(), *vpp, + cp->c_attr.va_uid, 0, VWRITE) != 0) { mutex_exit(&cp->c_statelock); connected = 1; continue; @@ -9829,13 +9828,8 @@ cachefs_access_local(void *vcp, int mode, cred_t *cr) shift += 3; } - /* compute missing mode bits */ - mode &= ~(cp->c_attr.va_mode << shift); - - if (mode == 0) - return (0); - - return (secpolicy_vnode_access(cr, CTOV(cp), cp->c_attr.va_uid, mode)); + return (secpolicy_vnode_access2(cr, CTOV(cp), cp->c_attr.va_uid, + cp->c_attr.va_mode << shift, mode)); } /* @@ -9849,8 +9843,8 @@ cachefs_access_local(void *vcp, int mode, cred_t *cr) * Check Algorithm, of the POSIX 1003.6 Draft Standard. */ -#define ACL_MODE_CHECK(M, PERM, C, I) ((((M) & (PERM)) == (M)) ? 0 : \ - secpolicy_vnode_access(C, CTOV(I), owner, (M) & ~(PERM))) +#define ACL_MODE_CHECK(M, PERM, C, I) \ + secpolicy_vnode_access2(C, CTOV(I), owner, (PERM), (M)) static int cachefs_acl_access(struct cnode *cp, int mode, cred_t *cr) diff --git a/usr/src/uts/common/fs/dev/sdev_vnops.c b/usr/src/uts/common/fs/dev/sdev_vnops.c index 6519dd32ca..416c100125 100644 --- a/usr/src/uts/common/fs/dev/sdev_vnops.c +++ b/usr/src/uts/common/fs/dev/sdev_vnops.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -323,11 +322,8 @@ sdev_unlocked_access(void *vdv, int mode, struct cred *cr) shift += 3; } - mode &= ~(dv->sdev_attr->va_mode << shift); - if (mode == 0) - return (0); - - return (secpolicy_vnode_access(cr, SDEVTOV(dv), owner, mode)); + return (secpolicy_vnode_access2(cr, SDEVTOV(dv), owner, + dv->sdev_attr->va_mode << shift, mode)); } static int diff --git a/usr/src/uts/common/fs/devfs/devfs_vnops.c b/usr/src/uts/common/fs/devfs/devfs_vnops.c index 359e9e1d6a..0c5114066b 100644 --- a/usr/src/uts/common/fs/devfs/devfs_vnops.c +++ b/usr/src/uts/common/fs/devfs/devfs_vnops.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -719,13 +718,8 @@ devfs_unlocked_access(void *vdv, int mode, struct cred *cr) shift += 3; } - /* compute missing mode bits */ - mode &= ~(dv->dv_attr->va_mode << shift); - - if (mode == 0) - return (0); - - return (secpolicy_vnode_access(cr, DVTOV(dv), owner, mode)); + return (secpolicy_vnode_access2(cr, DVTOV(dv), owner, + dv->dv_attr->va_mode << shift, mode)); } static int diff --git a/usr/src/uts/common/fs/hsfs/hsfs_node.c b/usr/src/uts/common/fs/hsfs/hsfs_node.c index 58dbe56e1a..6e9456f65f 100644 --- a/usr/src/uts/common/fs/hsfs/hsfs_node.c +++ b/usr/src/uts/common/fs/hsfs/hsfs_node.c @@ -19,12 +19,9 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * Directory operations for High Sierra filesystem */ @@ -157,10 +154,8 @@ hs_access(struct vnode *vp, mode_t m, struct cred *cred) if (!groupmember((uid_t)hp->hs_dirent.gid, cred)) shift += 3; } - m &= ~(hp->hs_dirent.mode << shift); - if (m != 0) - return (secpolicy_vnode_access(cred, vp, hp->hs_dirent.uid, m)); - return (0); + return (secpolicy_vnode_access2(cred, vp, hp->hs_dirent.uid, + hp->hs_dirent.mode << shift, m)); } #if ((HS_HASHSIZE & (HS_HASHSIZE - 1)) == 0) diff --git a/usr/src/uts/common/fs/namefs/namevfs.c b/usr/src/uts/common/fs/namefs/namevfs.c index a6670d9cd6..b0470e45d9 100644 --- a/usr/src/uts/common/fs/namefs/namevfs.c +++ b/usr/src/uts/common/fs/namefs/namevfs.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -417,8 +416,8 @@ nm_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *crp) * Make sure the user has write permissions on the * mount point (or has sufficient privileges). */ - if (!(vattrp->va_mode & VWRITE) && - secpolicy_vnode_access(crp, mvp, vattrp->va_uid, VWRITE) != 0) { + if (secpolicy_vnode_access2(crp, mvp, vattrp->va_uid, vattrp->va_mode, + VWRITE) != 0) { error = EACCES; goto out; } diff --git a/usr/src/uts/common/fs/namefs/namevno.c b/usr/src/uts/common/fs/namefs/namevno.c index f487953db5..e1f8590718 100644 --- a/usr/src/uts/common/fs/namefs/namevno.c +++ b/usr/src/uts/common/fs/namefs/namevno.c @@ -23,12 +23,9 @@ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * This file defines the vnode operations for mounted file descriptors. * The routines in this file act as a layer between the NAMEFS file @@ -253,13 +250,10 @@ nm_access_unlocked(void *vnp, int mode, cred_t *crp) if (!groupmember(nodep->nm_vattr.va_gid, crp)) shift += 3; } - mode &= ~(nodep->nm_vattr.va_mode << shift); - - if (mode == 0) - return (0); - return (secpolicy_vnode_access(crp, NMTOV(nodep), - nodep->nm_vattr.va_uid, mode)); + return (secpolicy_vnode_access2(crp, NMTOV(nodep), + nodep->nm_vattr.va_uid, nodep->nm_vattr.va_mode << shift, + mode)); } /* * Set the attributes of the namenode from the attributes in vap. diff --git a/usr/src/uts/common/fs/nfs/nfs_vnops.c b/usr/src/uts/common/fs/nfs/nfs_vnops.c index fa7ba8b791..a3f43a4e95 100644 --- a/usr/src/uts/common/fs/nfs/nfs_vnops.c +++ b/usr/src/uts/common/fs/nfs/nfs_vnops.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved. * * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T. * All rights reserved. @@ -1445,12 +1444,9 @@ nfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct) if (!groupmember(va.va_gid, cr)) shift += 3; } -found: - mode &= ~(va.va_mode << shift); - if (mode == 0) - return (0); - return (secpolicy_vnode_access(cr, vp, va.va_uid, mode)); + return (secpolicy_vnode_access2(cr, vp, va.va_uid, + va.va_mode << shift, mode)); } static int nfs_do_symlink_cache = 1; diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c index 30926e61b0..048c159fdf 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c @@ -33,8 +33,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/systm.h> @@ -1211,9 +1210,6 @@ smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr) if (!groupmember(va.va_gid, cr)) shift += 3; } - mode &= ~(va.va_mode << shift); - if (mode == 0) - return (0); /* * We need a vnode for secpolicy_vnode_access, @@ -1223,7 +1219,9 @@ smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr) tvp = (va.va_type == VDIR) ? (vnode_t *)&tmpl_vdir : (vnode_t *)&tmpl_vreg; - return (secpolicy_vnode_access(cr, tvp, va.va_uid, mode)); + + return (secpolicy_vnode_access2(cr, tvp, va.va_uid, + va.va_mode << shift, mode)); } /* diff --git a/usr/src/uts/common/fs/tmpfs/tmp_subr.c b/usr/src/uts/common/fs/tmpfs/tmp_subr.c index 0012dfe35a..2e59d28d80 100644 --- a/usr/src/uts/common/fs/tmpfs/tmp_subr.c +++ b/usr/src/uts/common/fs/tmpfs/tmp_subr.c @@ -2,9 +2,8 @@ * 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. + * Common Development and Distribution License (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. @@ -20,12 +19,9 @@ * CDDL HEADER END */ /* - * Copyright 1989-1999,2001-2003 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <sys/errno.h> #include <sys/param.h> @@ -62,13 +58,8 @@ tmp_taccess(void *vtp, int mode, struct cred *cred) shift += MODESHIFT; } - /* compute missing mode bits */ - mode &= ~(tp->tn_mode << shift); - - if (mode == 0) - return (0); - - return (secpolicy_vnode_access(cred, TNTOV(tp), tp->tn_uid, mode)); + return (secpolicy_vnode_access2(cred, TNTOV(tp), tp->tn_uid, + tp->tn_mode << shift, mode)); } /* diff --git a/usr/src/uts/common/fs/udfs/udf_inode.c b/usr/src/uts/common/fs/udfs/udf_inode.c index 72440ffcc2..e30a5ffe6d 100644 --- a/usr/src/uts/common/fs/udfs/udf_inode.c +++ b/usr/src/uts/common/fs/udfs/udf_inode.c @@ -1963,13 +1963,9 @@ ud_iaccess(struct ud_inode *ip, int32_t mode, struct cred *cr, int dolock) if (!groupmember((uid_t)ip->i_gid, cr)) shift += 5; } - mode &= ~(ip->i_perm << shift); - if (mode == 0) - goto out; - - ret = secpolicy_vnode_access(cr, ITOV(ip), ip->i_uid, - UD2VA_PERM(mode)); + ret = secpolicy_vnode_access2(cr, ITOV(ip), ip->i_uid, + UD2VA_PERM(ip->i_perm << shift), UD2VA_PERM(mode)); out: if (dolock) diff --git a/usr/src/uts/common/fs/ufs/ufs_inode.c b/usr/src/uts/common/fs/ufs/ufs_inode.c index 40e051005a..ebb3fd6e9c 100644 --- a/usr/src/uts/common/fs/ufs/ufs_inode.c +++ b/usr/src/uts/common/fs/ufs/ufs_inode.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1983, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ @@ -1566,13 +1565,9 @@ ufs_iaccess(struct inode *ip, int mode, struct cred *cr, int dolock) shift += 3; } - mode &= ~(ip->i_mode << shift); - - if (mode == 0) - goto out; - /* test missing privilege bits */ - ret = secpolicy_vnode_access(cr, ITOV(ip), ip->i_uid, mode); + ret = secpolicy_vnode_access2(cr, ITOV(ip), ip->i_uid, + ip->i_mode << shift, mode); out: if (dolock) rw_exit(&ip->i_contents); diff --git a/usr/src/uts/common/fs/zfs/zfs_acl.c b/usr/src/uts/common/fs/zfs/zfs_acl.c index 34ace4a885..703f665964 100644 --- a/usr/src/uts/common/fs/zfs/zfs_acl.c +++ b/usr/src/uts/common/fs/zfs/zfs_acl.c @@ -2251,15 +2251,8 @@ zfs_has_access(znode_t *zp, cred_t *cr) uint32_t have = ACE_ALL_PERMS; if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr) != 0) { - return ( - secpolicy_vnode_access(cr, ZTOV(zp), - zp->z_uid, VREAD) == 0 || secpolicy_vnode_access(cr, - ZTOV(zp), zp->z_uid, VWRITE) == 0 || - secpolicy_vnode_access(cr, ZTOV(zp), - zp->z_uid, VEXEC) == 0 || - secpolicy_vnode_chown(cr, zp->z_uid) == 0 || - secpolicy_vnode_setdac(cr, zp->z_uid) == 0 || - secpolicy_vnode_remove(cr) == 0); + return (secpolicy_vnode_any_access(cr, ZTOV(zp), + zp->z_uid) == 0); } return (B_TRUE); } @@ -2379,8 +2372,9 @@ slow: } /* - * Determine whether Access should be granted/denied, invoking least - * priv subsytem when a deny is determined. + * Determine whether Access should be granted/denied. + * The least priv subsytem is always consulted as a basic privilege + * can define any form of access. */ int zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) @@ -2391,6 +2385,7 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) boolean_t check_privs; znode_t *xzp; znode_t *check_zp = zp; + mode_t needed_bits; is_attr = ((zp->z_pflags & ZFS_XATTR) && (ZTOV(zp)->v_type == VDIR)); @@ -2427,11 +2422,35 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) } } + /* + * Map the bits required to the standard vnode flags VREAD|VWRITE|VEXEC + * in needed_bits. Map the bits mapped by working_mode (currently + * missing) in missing_bits. + * Call secpolicy_vnode_access2() with (needed_bits & ~checkmode), + * needed_bits. + */ + needed_bits = 0; + + working_mode = mode; + if ((working_mode & (ACE_READ_ACL|ACE_READ_ATTRIBUTES)) && + zp->z_uid == crgetuid(cr)) + working_mode &= ~(ACE_READ_ACL|ACE_READ_ATTRIBUTES); + + if (working_mode & (ACE_READ_DATA|ACE_READ_NAMED_ATTRS| + ACE_READ_ACL|ACE_READ_ATTRIBUTES|ACE_SYNCHRONIZE)) + needed_bits |= VREAD; + if (working_mode & (ACE_WRITE_DATA|ACE_WRITE_NAMED_ATTRS| + ACE_APPEND_DATA|ACE_WRITE_ATTRIBUTES|ACE_SYNCHRONIZE)) + needed_bits |= VWRITE; + if (working_mode & ACE_EXECUTE) + needed_bits |= VEXEC; + if ((error = zfs_zaccess_common(check_zp, mode, &working_mode, &check_privs, skipaclchk, cr)) == 0) { if (is_attr) VN_RELE(ZTOV(xzp)); - return (0); + return (secpolicy_vnode_access2(cr, ZTOV(zp), zp->z_uid, + needed_bits, needed_bits)); } if (error && !check_privs) { @@ -2468,9 +2487,8 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) if (working_mode & ACE_EXECUTE) checkmode |= VEXEC; - if (checkmode) - error = secpolicy_vnode_access(cr, ZTOV(check_zp), - zp->z_uid, checkmode); + error = secpolicy_vnode_access2(cr, ZTOV(check_zp), zp->z_uid, + needed_bits & ~checkmode, needed_bits); if (error == 0 && (working_mode & ACE_WRITE_OWNER)) error = secpolicy_vnode_chown(cr, zp->z_uid); @@ -2493,8 +2511,12 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr) error = EACCES; } } + } else if (error == 0) { + error = secpolicy_vnode_access2(cr, ZTOV(zp), zp->z_uid, + needed_bits, needed_bits); } + if (is_attr) VN_RELE(ZTOV(xzp)); @@ -2524,12 +2546,12 @@ zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr) static int zfs_delete_final_check(znode_t *zp, znode_t *dzp, - mode_t missing_perms, cred_t *cr) + mode_t available_perms, cred_t *cr) { int error; - error = secpolicy_vnode_access(cr, ZTOV(dzp), - dzp->z_uid, missing_perms); + error = secpolicy_vnode_access2(cr, ZTOV(dzp), + dzp->z_uid, available_perms, VWRITE|VEXEC); if (error == 0) error = zfs_sticky_remove_access(dzp, zp, cr); @@ -2578,7 +2600,7 @@ zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr) uint32_t dzp_working_mode = 0; uint32_t zp_working_mode = 0; int dzp_error, zp_error; - mode_t missing_perms; + mode_t available_perms; boolean_t dzpcheck_privs = B_TRUE; boolean_t zpcheck_privs = B_TRUE; @@ -2639,23 +2661,20 @@ zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr) * only need to see if we have write/execute on directory. */ - if ((dzp_error = zfs_zaccess_common(dzp, ACE_EXECUTE|ACE_WRITE_DATA, - &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr)) == 0) - return (zfs_sticky_remove_access(dzp, zp, cr)); + dzp_error = zfs_zaccess_common(dzp, ACE_EXECUTE|ACE_WRITE_DATA, + &dzp_working_mode, &dzpcheck_privs, B_FALSE, cr); - if (!dzpcheck_privs) + if (dzp_error != 0 && !dzpcheck_privs) return (dzp_error); /* * Fourth row */ - missing_perms = (dzp_working_mode & ACE_WRITE_DATA) ? VWRITE : 0; - missing_perms |= (dzp_working_mode & ACE_EXECUTE) ? VEXEC : 0; - - ASSERT(missing_perms); + available_perms = (dzp_working_mode & ACE_WRITE_DATA) ? 0 : VWRITE; + available_perms |= (dzp_working_mode & ACE_EXECUTE) ? 0 : VEXEC; - return (zfs_delete_final_check(zp, dzp, missing_perms, cr)); + return (zfs_delete_final_check(zp, dzp, available_perms, cr)); } diff --git a/usr/src/uts/common/inet/ip/icmp.c b/usr/src/uts/common/inet/ip/icmp.c index fa4c7a8b57..b024baaf0c 100644 --- a/usr/src/uts/common/inet/ip/icmp.c +++ b/usr/src/uts/common/inet/ip/icmp.c @@ -38,7 +38,7 @@ #include <sys/xti_inet.h> #include <sys/cmn_err.h> #include <sys/kmem.h> -#include <sys/cred_impl.h> +#include <sys/cred.h> #include <sys/policy.h> #include <sys/priv.h> #include <sys/ucred.h> diff --git a/usr/src/uts/common/inet/ip/spdsock.c b/usr/src/uts/common/inet/ip/spdsock.c index 4a9053cddf..37dc31875e 100644 --- a/usr/src/uts/common/inet/ip/spdsock.c +++ b/usr/src/uts/common/inet/ip/spdsock.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/param.h> @@ -156,6 +155,7 @@ static void spdsock_wput(queue_t *, mblk_t *); static void spdsock_wsrv(queue_t *); static void spdsock_rsrv(queue_t *); static void *spdsock_stack_init(netstackid_t stackid, netstack_t *ns); +static void spdsock_stack_shutdown(netstackid_t stackid, void *arg); static void spdsock_stack_fini(netstackid_t stackid, void *arg); static void spdsock_loadcheck(void *); static void spdsock_merge_algs(spd_stack_t *); @@ -276,8 +276,8 @@ spdsock_ddi_init(void) * destroyed in the kernel, so we can maintain the * set of spd_stack_t's. */ - netstack_register(NS_SPDSOCK, spdsock_stack_init, NULL, - spdsock_stack_fini); + netstack_register(NS_SPDSOCK, spdsock_stack_init, + spdsock_stack_shutdown, spdsock_stack_fini); return (B_TRUE); } @@ -340,13 +340,28 @@ spdsock_ddi_destroy(void) netstack_unregister(NS_SPDSOCK); } +/* + * Do pre-removal cleanup. + */ +/* ARGSUSED */ +static void +spdsock_stack_shutdown(netstackid_t stackid, void *arg) +{ + spd_stack_t *spds = (spd_stack_t *)arg; + + if (spds->spds_mp_algs != NULL) { + freemsg(spds->spds_mp_algs); + spds->spds_mp_algs = NULL; + } +} + /* ARGSUSED */ static void spdsock_stack_fini(netstackid_t stackid, void *arg) { spd_stack_t *spds = (spd_stack_t *)arg; - freemsg(spds->spds_mp_algs); + ASSERT(spds->spds_mp_algs == NULL); mutex_destroy(&spds->spds_param_lock); mutex_destroy(&spds->spds_alg_lock); nd_free(&spds->spds_g_nd); @@ -2794,7 +2809,6 @@ spdsock_updatealg(queue_t *q, mblk_t *mp, spd_ext_t *extv[]) if (spds->spds_mp_algs != NULL) freemsg(spds->spds_mp_algs); spds->spds_mp_algs = mp; - spds->spds_algs_pending = B_TRUE; mutex_exit(&spds->spds_alg_lock); if (auditing) { cred_t *cr; @@ -3152,9 +3166,10 @@ spdsock_update_pending_algs(netstack_t *ns) spd_stack_t *spds = ns->netstack_spdsock; mutex_enter(&spds->spds_alg_lock); - if (spds->spds_algs_pending) { + if (spds->spds_mp_algs != NULL) { (void) spdsock_do_updatealg(spds->spds_extv_algs, spds); - spds->spds_algs_pending = B_FALSE; + freemsg(spds->spds_mp_algs); + spds->spds_mp_algs = NULL; } mutex_exit(&spds->spds_alg_lock); } diff --git a/usr/src/uts/common/inet/spdsock.h b/usr/src/uts/common/inet/spdsock.h index 64c63cdd71..7cc065d740 100644 --- a/usr/src/uts/common/inet/spdsock.h +++ b/usr/src/uts/common/inet/spdsock.h @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _INET_SPDSOCK_H @@ -49,7 +48,6 @@ struct spd_stack { */ struct spd_ext *spds_extv_algs[SPD_EXT_MAX + 1]; mblk_t *spds_mp_algs; - boolean_t spds_algs_pending; struct ipsec_alginfo *spds_algs[IPSEC_NALGTYPES][IPSEC_MAX_ALGS]; int spds_algs_exec_mode[IPSEC_NALGTYPES]; diff --git a/usr/src/uts/common/os/cred.c b/usr/src/uts/common/os/cred.c index 01dc69774d..93a274f2d1 100644 --- a/usr/src/uts/common/os/cred.c +++ b/usr/src/uts/common/os/cred.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -348,6 +347,7 @@ crset(proc_t *p, cred_t *cr) void crhold(cred_t *cr) { + ASSERT(cr->cr_ref != 0xdeadbeef && cr->cr_ref != 0); atomic_add_32(&cr->cr_ref, 1); } @@ -358,6 +358,7 @@ crhold(cred_t *cr) void crfree(cred_t *cr) { + ASSERT(cr->cr_ref != 0xdeadbeef && cr->cr_ref != 0); if (atomic_add_32_nv(&cr->cr_ref, -1) == 0) { ASSERT(cr != kcred); if (cr->cr_label) @@ -901,7 +902,7 @@ cred2ucaud(const cred_t *cr, auditinfo64_addr_t *ainfo, const cred_t *rcr) auditinfo_addr_t *ai; au_tid_addr_t tid; - if (secpolicy_audit_getattr(rcr) != 0) + if (secpolicy_audit_getattr(rcr, B_TRUE) != 0) return (-1); ai = CR_AUINFO(cr); /* caller makes sure this is non-NULL */ diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c index f9cf4e1eea..c01c81062c 100644 --- a/usr/src/uts/common/os/exec.c +++ b/usr/src/uts/common/os/exec.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1988 AT&T */ @@ -66,6 +65,7 @@ #include <sys/pool.h> #include <sys/sdt.h> #include <sys/brand.h> +#include <sys/klpd.h> #include <c2/audit.h> @@ -80,8 +80,10 @@ #define PRIV_SETUGID 0x04 /* is setuid/setgid/forced privs */ #define PRIV_INCREASE 0x08 /* child runs with more privs */ #define MAC_FLAGS 0x10 /* need to adjust MAC flags */ +#define PRIV_FORCED 0x20 /* has forced privileges */ -static int execsetid(struct vnode *, struct vattr *, uid_t *, uid_t *); +static int execsetid(struct vnode *, struct vattr *, uid_t *, uid_t *, + priv_set_t *, cred_t *, const char *); static int hold_execsw(struct execsw *); uint_t auxv_hwcap = 0; /* auxv AT_SUN_HWCAP value; determined on the fly */ @@ -252,6 +254,31 @@ exec_common(const char *fname, const char **argp, const char **envp, pn_free(&pn); /* + * If we're running in a profile shell, then call pfexecd. + */ + if ((CR_FLAGS(p->p_cred) & PRIV_PFEXEC) != 0) { + error = pfexec_call(p->p_cred, &resolvepn, &args.pfcred, + &args.scrubenv); + + /* Returning errno in case we're not allowed to execute. */ + if (error > 0) { + if (dir != NULL) + VN_RELE(dir); + pn_free(&resolvepn); + VN_RELE(vp); + goto out; + } + + /* Don't change the credentials when using old ptrace. */ + if (args.pfcred != NULL && + (p->p_proc_flag & P_PR_PTRACE) != 0) { + crfree(args.pfcred); + args.pfcred = NULL; + args.scrubenv = B_FALSE; + } + } + + /* * Specific exec handlers, or policies determined via * /etc/system may override the historical default. */ @@ -527,6 +554,7 @@ gexec( cred_t *oldcred, *newcred = NULL; int privflags = 0; int setidfl; + priv_set_t fset; /* * If the SNOCD or SUGID flag is set, turn it off and remember the @@ -562,9 +590,17 @@ gexec( goto bad; if (level == 0 && - (privflags = execsetid(vp, &vattr, &uid, &gid)) != 0) { + (privflags = execsetid(vp, &vattr, &uid, &gid, &fset, + args->pfcred == NULL ? cred : args->pfcred, args->pathname)) != 0) { + + /* Pfcred is a credential with a ref count of 1 */ - newcred = cred = crdup(cred); + if (args->pfcred != NULL) { + privflags |= PRIV_INCREASE|PRIV_RESET; + newcred = cred = args->pfcred; + } else { + newcred = cred = crdup(cred); + } /* If we can, drop the PA bit */ if ((privflags & PRIV_RESET) != 0) @@ -592,17 +628,31 @@ gexec( * * E' = P' = (I' + F) & A * - * But if running under ptrace, we cap I with P. + * But if running under ptrace, we cap I and F with P. */ - if ((privflags & PRIV_RESET) != 0) { + if ((privflags & (PRIV_RESET|PRIV_FORCED)) != 0) { if ((privflags & PRIV_INCREASE) != 0 && - (pp->p_proc_flag & P_PR_PTRACE) != 0) + (pp->p_proc_flag & P_PR_PTRACE) != 0) { priv_intersect(&CR_OPPRIV(cred), &CR_IPRIV(cred)); + priv_intersect(&CR_OPPRIV(cred), &fset); + } priv_intersect(&CR_LPRIV(cred), &CR_IPRIV(cred)); CR_EPRIV(cred) = CR_PPRIV(cred) = CR_IPRIV(cred); + if (privflags & PRIV_FORCED) { + priv_set_PA(cred); + priv_union(&fset, &CR_EPRIV(cred)); + priv_union(&fset, &CR_PPRIV(cred)); + } priv_adjust_PA(cred); } + } else if (level == 0 && args->pfcred != NULL) { + newcred = cred = args->pfcred; + privflags |= PRIV_INCREASE; + /* pfcred is not forced to adhere to these settings */ + priv_intersect(&CR_LPRIV(cred), &CR_IPRIV(cred)); + CR_EPRIV(cred) = CR_PPRIV(cred) = CR_IPRIV(cred); + priv_adjust_PA(cred); } /* SunOS 4.x buy-back */ @@ -659,7 +709,7 @@ gexec( * credentials of the process. In privflags, it told us * whether we gained any privileges or executed a set-uid executable. */ - setid = (privflags & (PRIV_SETUGID|PRIV_INCREASE)); + setid = (privflags & (PRIV_SETUGID|PRIV_INCREASE|PRIV_FORCED)); /* * Use /etc/system variable to determine if the stack @@ -692,7 +742,7 @@ gexec( } if (setid & PRIV_SETUGID) setidfl |= EXECSETID_SETID; - if (setid & PRIV_INCREASE) + if (setid & PRIV_FORCED) setidfl |= EXECSETID_PRIVS; execvp = pp->p_exec; @@ -718,6 +768,8 @@ gexec( } if (level == 0) { + uid_t oruid; + if (execvp != NULL) { /* * Close the previous executable only if we are @@ -728,6 +780,9 @@ gexec( } mutex_enter(&pp->p_crlock); + + oruid = pp->p_cred->cr_ruid; + if (newcred != NULL) { /* * Free the old credentials, and set the new ones. @@ -778,6 +833,13 @@ gexec( suidflags = 0; mutex_exit(&pp->p_crlock); + if (newcred != NULL && oruid != newcred->cr_ruid) { + /* Note that the process remains in the same zone. */ + mutex_enter(&pidlock); + upcount_dec(oruid, crgetzoneid(newcred)); + upcount_inc(newcred->cr_ruid, crgetzoneid(newcred)); + mutex_exit(&pidlock); + } if (suidflags) { mutex_enter(&pp->p_lock); pp->p_flag |= suidflags; @@ -929,11 +991,11 @@ hold_execsw(struct execsw *eswp) } static int -execsetid(struct vnode *vp, struct vattr *vattrp, uid_t *uidp, uid_t *gidp) +execsetid(struct vnode *vp, struct vattr *vattrp, uid_t *uidp, uid_t *gidp, + priv_set_t *fset, cred_t *cr, const char *pathname) { proc_t *pp = ttoproc(curthread); uid_t uid, gid; - cred_t *cr = pp->p_cred; int privflags = 0; /* @@ -948,13 +1010,38 @@ execsetid(struct vnode *vp, struct vattr *vattrp, uid_t *uidp, uid_t *gidp) if ((vp->v_vfsp->vfs_flag & VFS_NOSETUID) == 0) { /* - * Set-uid root execution only allowed if the limit set - * holds all unsafe privileges. + * If it's a set-uid root program we perform the + * forced privilege look-aside. This has three possible + * outcomes: + * no look aside information -> treat as before + * look aside in Limit set -> apply forced privs + * look aside not in Limit set -> ignore set-uid root + * + * Ordinary set-uid root execution only allowed if the limit + * set holds all unsafe privileges. */ - if ((vattrp->va_mode & VSUID) && (vattrp->va_uid != 0 || - priv_issubset(&priv_unsafe, &CR_LPRIV(cr)))) { - uid = vattrp->va_uid; - privflags |= PRIV_SETUGID; + if (vattrp->va_mode & VSUID) { + if (vattrp->va_uid == 0) { + int res = get_forced_privs(cr, pathname, fset); + + switch (res) { + case -1: + if (priv_issubset(&priv_unsafe, + &CR_LPRIV(cr))) { + uid = vattrp->va_uid; + privflags |= PRIV_SETUGID; + } + break; + case 0: + privflags |= PRIV_FORCED|PRIV_INCREASE; + break; + default: + break; + } + } else { + uid = vattrp->va_uid; + privflags |= PRIV_SETUGID; + } } if (vattrp->va_mode & VSGID) { gid = vattrp->va_gid; @@ -980,20 +1067,14 @@ execsetid(struct vnode *vp, struct vattr *vattrp, uid_t *uidp, uid_t *gidp) !priv_isequalset(&CR_PPRIV(cr), &CR_IPRIV(cr))) privflags |= PRIV_RESET; + /* Child has more privileges than parent */ + if (!priv_issubset(&CR_IPRIV(cr), &CR_PPRIV(cr))) + privflags |= PRIV_INCREASE; + /* If MAC-aware flag(s) are on, need to update cred to remove. */ if ((CR_FLAGS(cr) & NET_MAC_AWARE) || (CR_FLAGS(cr) & NET_MAC_AWARE_INHERIT)) privflags |= MAC_FLAGS; - - /* - * When we introduce the "forced" set then we will need - * to set PRIV_INCREASE here if I not a subset of P. - * If the "allowed" set is introduced we will need to do - * a similar thing; however, it seems more reasonable to - * have the allowed set reduce "L": script language interpreters - * would typically have an allowed set of "all". - */ - /* * Set setuid/setgid protections if no ptrace() compatibility. * For privileged processes, honor setuid/setgid even in @@ -1498,12 +1579,18 @@ stk_copyin(execa_t *uap, uarg_t *args, intpdata_t *intp, void **auxvpp) */ if (envp != NULL) { for (;;) { + char *tmp = args->stk_strp; if (stk_getptr(args, envp, &sp)) return (EFAULT); if (sp == NULL) break; if ((error = stk_add(args, sp, UIO_USERSPACE)) != 0) return (error); + if (args->scrubenv && strncmp(tmp, "LD_", 3) == 0) { + /* Undo the copied string */ + args->stk_strp = tmp; + *(args->stk_offp++) = NULL; + } envp += ptrsize; } } @@ -1840,7 +1927,7 @@ exec_args(execa_t *uap, uarg_t *args, intpdata_t *intp, void **auxvpp) if (AU_AUDITING()) audit_exec(args->stk_base, args->stk_base + args->arglen, - args->na - args->ne, args->ne); + args->na - args->ne, args->ne, args->pfcred); /* * Ensure that we don't change resource associations while we diff --git a/usr/src/uts/common/os/klpd.c b/usr/src/uts/common/os/klpd.c index 5441b20cef..2d7cd7e1c5 100644 --- a/usr/src/uts/common/os/klpd.c +++ b/usr/src/uts/common/os/klpd.c @@ -20,12 +20,9 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/atomic.h> #include <sys/door.h> #include <sys/proc.h> @@ -139,21 +136,21 @@ klpd_unlink(klpd_reg_t *p) } /* - * Remove the head of the klpd list and decrement its refcnt. + * Remove all elements of the klpd list and decrement their refcnts. * The lock guarding the list should be held; this function is - * called when we are sure we want to remove the entry from the - * list but not so sure that the reference count has dropped back to - * 1 and is specifically intended to remove the non-list variants. + * called when we are sure we want to destroy the list completely + * list but not so sure that the reference counts of all elements have + * dropped back to 1. */ void -klpd_remove(klpd_reg_t **pp) +klpd_freelist(klpd_reg_t **pp) { - klpd_reg_t *p = *pp; - if (p == NULL) - return; - ASSERT(p->klpd_next == NULL); - klpd_unlink(p); - klpd_rele(p); + klpd_reg_t *p; + + while ((p = *pp) != NULL) { + klpd_unlink(p); + klpd_rele(p); + } } /* @@ -192,7 +189,7 @@ klpd_link(klpd_reg_t *p, klpd_reg_t **listp, boolean_t single) static klpd_head_t * klpd_marshall(klpd_reg_t *p, const priv_set_t *rq, va_list ap) { - char *comp; + char *tmp; uint_t type; vnode_t *vp; size_t len = sizeof (priv_set_t) + sizeof (klpd_head_t); @@ -214,10 +211,10 @@ klpd_marshall(klpd_reg_t *p, const priv_set_t *rq, va_list ap) if (vp == NULL) return (NULL); - comp = va_arg(ap, char *); + tmp = va_arg(ap, char *); - if (comp != NULL && *comp != '\0') - clen = strlen(comp) + 1; + if (tmp != NULL && *tmp != '\0') + clen = strlen(tmp) + 1; else clen = 0; @@ -242,7 +239,7 @@ klpd_marshall(klpd_reg_t *p, const priv_set_t *rq, va_list ap) if (plen <= 2) plen = 0; kap->kla_str[plen] = '/'; - bcopy(comp, &kap->kla_str[plen + 1], clen); + bcopy(tmp, &kap->kla_str[plen + 1], clen); } break; case KLPDARG_PORT: @@ -636,7 +633,7 @@ klpd_unreg(int did, idtype_t type, id_t id) if (kpp->kpj_klpd == NULL) res = ESRCH; else - klpd_remove(&kpp->kpj_klpd); + klpd_freelist(&kpp->kpj_klpd); mutex_exit(&klpd_mutex); project_rele(kpp); goto out; @@ -721,3 +718,429 @@ crklpd_setreg(credklpd_t *crk, klpd_reg_t *new) if (old != NULL) klpd_rele(old); } + +/* Allocate and register the pfexec specific callback */ +int +pfexec_reg(int did) +{ + door_handle_t dh; + int err = secpolicy_pfexec_register(CRED()); + klpd_reg_t *pfx; + door_info_t di; + zone_t *myzone = crgetzone(CRED()); + + if (err != 0) + return (set_errno(err)); + + dh = door_ki_lookup(did); + if (dh == NULL || door_ki_info(dh, &di) != 0) + return (set_errno(EBADF)); + + pfx = kmem_zalloc(sizeof (*pfx), KM_SLEEP); + + pfx->klpd_door = dh; + pfx->klpd_door_pid = di.di_target; + pfx->klpd_ref = 1; + pfx->klpd_cred = NULL; + mutex_enter(&myzone->zone_lock); + pfx = klpd_link(pfx, &myzone->zone_pfexecd, B_TRUE); + mutex_exit(&myzone->zone_lock); + if (pfx != NULL) + klpd_rele(pfx); + + return (0); +} + +int +pfexec_unreg(int did) +{ + door_handle_t dh; + int err = 0; + zone_t *myzone = crgetzone(CRED()); + klpd_reg_t *pfd; + + dh = door_ki_lookup(did); + if (dh == NULL) + return (set_errno(EBADF)); + + mutex_enter(&myzone->zone_lock); + pfd = myzone->zone_pfexecd; + if (pfd != NULL && pfd->klpd_door == dh) { + klpd_unlink(pfd); + } else { + pfd = NULL; + err = EINVAL; + } + mutex_exit(&myzone->zone_lock); + door_ki_rele(dh); + /* + * crfree() cannot be called with zone_lock held; it is called + * indirectly through closing the door handle + */ + if (pfd != NULL) + klpd_rele(pfd); + if (err != 0) + return (set_errno(err)); + return (0); +} + +static int +get_path(char *buf, const char *path, int len) +{ + size_t lc; + char *s; + + if (len < 0) + len = strlen(path); + + if (*path == '/' && len < MAXPATHLEN) { + (void) strcpy(buf, path); + return (0); + } + /* + * Build the pathname using the current directory + resolve pathname. + * The resolve pathname either starts with a normal component and + * we can just concatenate them or it starts with one + * or more ".." component and we can remove those; the + * last one cannot be a ".." and the current directory has + * more components than the number of ".." in the resolved pathname. + */ + if (dogetcwd(buf, MAXPATHLEN) != 0) + return (-1); + + lc = strlen(buf); + + while (len > 3 && strncmp("../", path, 3) == 0) { + len -= 3; + path += 3; + + s = strrchr(buf, '/'); + if (s == NULL || s == buf) + return (-1); + + *s = '\0'; + lc = s - buf; + } + /* Add a "/" and a NUL */ + if (lc < 2 || lc + len + 2 >= MAXPATHLEN) + return (-1); + + buf[lc] = '/'; + (void) strcpy(buf + lc + 1, path); + + return (0); +} + +/* + * Perform the pfexec upcall. + * + * The pfexec upcall is different from the klpd_upcall in that a failure + * will lead to a denial of execution. + */ +int +pfexec_call(const cred_t *cr, struct pathname *rpnp, cred_t **pfcr, + boolean_t *scrub) +{ + klpd_reg_t *pfd; + pfexec_arg_t *pap; + pfexec_reply_t pr, *prp; + door_arg_t da; + int dres; + cred_t *ncr = NULL; + int err = -1; + priv_set_t *iset; + priv_set_t *lset; + zone_t *myzone = crgetzone(CRED()); + size_t pasize = PFEXEC_ARG_SIZE(MAXPATHLEN); + + /* Find registration */ + mutex_enter(&myzone->zone_lock); + if ((pfd = myzone->zone_pfexecd) != NULL) + klpd_hold(pfd); + mutex_exit(&myzone->zone_lock); + + if (pfd == NULL) + return (0); + + if (pfd->klpd_door_pid == curproc->p_pid) { + klpd_rele(pfd); + return (0); + } + + pap = kmem_zalloc(pasize, KM_SLEEP); + + if (get_path(pap->pfa_path, rpnp->pn_path, rpnp->pn_pathlen) == -1) + goto out1; + + pap->pfa_vers = PFEXEC_ARG_VERS; + pap->pfa_call = PFEXEC_EXEC_ATTRS; + pap->pfa_len = pasize; + pap->pfa_uid = crgetruid(cr); + + da.data_ptr = (char *)pap; + da.data_size = pap->pfa_len; + da.desc_ptr = NULL; + da.desc_num = 0; + da.rbuf = (char *)≺ + da.rsize = sizeof (pr); + + while ((dres = door_ki_upcall(pfd->klpd_door, &da)) != 0) { + switch (dres) { + case EAGAIN: + delay(1); + continue; + case EINVAL: + case EBADF: + /* FALLTHROUGH */ + case EINTR: + /* FALLTHROUGH */ + default: + goto out; + } + } + + prp = (pfexec_reply_t *)da.rbuf; + /* + * Check the size of the result and the alignment of the + * privilege sets. + */ + if (da.rsize < sizeof (pr) || + prp->pfr_ioff > da.rsize - sizeof (priv_set_t) || + prp->pfr_loff > da.rsize - sizeof (priv_set_t) || + (prp->pfr_loff & (sizeof (priv_chunk_t) - 1)) != 0 || + (prp->pfr_loff & (sizeof (priv_chunk_t) - 1)) != 0) + goto out; + + /* + * Get results: + * allow/allow with additional credentials/disallow[*] + * + * euid, uid, egid, gid, privs, and limitprivs + * We now have somewhat more flexibility we could even set E and P + * judiciously but that would break some currently valid assumptions + * [*] Disallow is not readily supported by always including + * the Basic Solaris User profile in all user's profiles. + */ + + if (!prp->pfr_allowed) { + err = EACCES; + goto out; + } + if (!prp->pfr_setcred) { + err = 0; + goto out; + } + ncr = crdup((cred_t *)cr); + + /* + * Generate the new credential set scrubenv if ruid != euid (or set) + * the "I'm set-uid flag" but that is not inherited so scrubbing + * the environment is a requirement. + */ + /* Set uids or gids, note that -1 will do the right thing */ + if (crsetresuid(ncr, prp->pfr_ruid, prp->pfr_euid, prp->pfr_euid) != 0) + goto out; + if (crsetresgid(ncr, prp->pfr_rgid, prp->pfr_egid, prp->pfr_egid) != 0) + goto out; + + *scrub = prp->pfr_scrubenv; + + if (prp->pfr_clearflag) + CR_FLAGS(ncr) &= ~PRIV_PFEXEC; + + /* We cannot exceed our Limit set, no matter what */ + iset = PFEXEC_REPLY_IPRIV(prp); + + if (iset != NULL) { + if (!priv_issubset(iset, &CR_LPRIV(ncr))) + goto out; + priv_union(iset, &CR_IPRIV(ncr)); + } + + /* Nor can we increate our Limit set itself */ + lset = PFEXEC_REPLY_LPRIV(prp); + + if (lset != NULL) { + if (!priv_issubset(lset, &CR_LPRIV(ncr))) + goto out; + CR_LPRIV(ncr) = *lset; + } + + /* Exec will do the standard set operations */ + + err = 0; +out: + if (da.rbuf != (char *)&pr) + kmem_free(da.rbuf, da.rsize); +out1: + kmem_free(pap, pasize); + klpd_rele(pfd); + if (ncr != NULL) { + if (err == 0) + *pfcr = ncr; + else + crfree(ncr); + } + return (err); +} + +int +get_forced_privs(const cred_t *cr, const char *respn, priv_set_t *set) +{ + klpd_reg_t *pfd; + pfexec_arg_t *pap; + door_arg_t da; + int dres; + int err = -1; + priv_set_t *fset, pmem; + cred_t *zkcr; + zone_t *myzone = crgetzone(cr); + size_t pasize = PFEXEC_ARG_SIZE(MAXPATHLEN); + + mutex_enter(&myzone->zone_lock); + if ((pfd = myzone->zone_pfexecd) != NULL) + klpd_hold(pfd); + mutex_exit(&myzone->zone_lock); + + if (pfd == NULL) + return (-1); + + if (pfd->klpd_door_pid == curproc->p_pid) { + klpd_rele(pfd); + return (0); + } + + pap = kmem_zalloc(pasize, KM_SLEEP); + + if (get_path(pap->pfa_path, respn, -1) == -1) + goto out1; + + pap->pfa_vers = PFEXEC_ARG_VERS; + pap->pfa_call = PFEXEC_FORCED_PRIVS; + pap->pfa_len = pasize; + pap->pfa_uid = (uid_t)-1; /* Not relevant */ + + da.data_ptr = (char *)pap; + da.data_size = pap->pfa_len; + da.desc_ptr = NULL; + da.desc_num = 0; + da.rbuf = (char *)&pmem; + da.rsize = sizeof (pmem); + + while ((dres = door_ki_upcall(pfd->klpd_door, &da)) != 0) { + switch (dres) { + case EAGAIN: + delay(1); + continue; + case EINVAL: + case EBADF: + case EINTR: + default: + goto out; + } + } + + /* + * Check the size of the result, it's a privilege set. + */ + if (da.rsize != sizeof (priv_set_t)) + goto out; + + fset = (priv_set_t *)da.rbuf; + + /* + * We restrict the forced privileges with whatever is available in + * the current zone. + */ + zkcr = zone_kcred(); + priv_intersect(&CR_LPRIV(zkcr), fset); + + /* + * But we fail if the forced privileges are not found in the current + * Limit set. + */ + if (!priv_issubset(fset, &CR_LPRIV(cr))) { + err = EACCES; + } else if (!priv_isemptyset(fset)) { + err = 0; + *set = *fset; + } +out: + if (da.rbuf != (char *)&pmem) + kmem_free(da.rbuf, da.rsize); +out1: + kmem_free(pap, pasize); + klpd_rele(pfd); + return (err); +} + +int +check_user_privs(const cred_t *cr, const priv_set_t *set) +{ + klpd_reg_t *pfd; + pfexec_arg_t *pap; + door_arg_t da; + int dres; + int err = -1; + zone_t *myzone = crgetzone(cr); + size_t pasize = PFEXEC_ARG_SIZE(sizeof (priv_set_t)); + uint32_t res; + + mutex_enter(&myzone->zone_lock); + if ((pfd = myzone->zone_pfexecd) != NULL) + klpd_hold(pfd); + mutex_exit(&myzone->zone_lock); + + if (pfd == NULL) + return (-1); + + if (pfd->klpd_door_pid == curproc->p_pid) { + klpd_rele(pfd); + return (0); + } + + pap = kmem_zalloc(pasize, KM_SLEEP); + + *(priv_set_t *)&pap->pfa_buf = *set; + + pap->pfa_vers = PFEXEC_ARG_VERS; + pap->pfa_call = PFEXEC_USER_PRIVS; + pap->pfa_len = pasize; + pap->pfa_uid = crgetruid(cr); + + da.data_ptr = (char *)pap; + da.data_size = pap->pfa_len; + da.desc_ptr = NULL; + da.desc_num = 0; + da.rbuf = (char *)&res; + da.rsize = sizeof (res); + + while ((dres = door_ki_upcall(pfd->klpd_door, &da)) != 0) { + switch (dres) { + case EAGAIN: + delay(1); + continue; + case EINVAL: + case EBADF: + case EINTR: + default: + goto out; + } + } + + /* + * Check the size of the result. + */ + if (da.rsize != sizeof (res)) + goto out; + + if (*(uint32_t *)da.rbuf == 1) + err = 0; +out: + if (da.rbuf != (char *)&res) + kmem_free(da.rbuf, da.rsize); +out1: + kmem_free(pap, pasize); + klpd_rele(pfd); + return (err); +} diff --git a/usr/src/uts/common/os/policy.c b/usr/src/uts/common/os/policy.c index d6444e7fc3..c56ec6db92 100644 --- a/usr/src/uts/common/os/policy.c +++ b/usr/src/uts/common/os/policy.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/types.h> @@ -147,6 +146,12 @@ int priv_basic_test = -1; HAS_ALLPRIVS(cr) : \ PRIV_ISASSERT(&CR_OEPRIV(cr), pr)) +#define FAST_BASIC_CHECK(cr, priv) \ + if (PRIV_ISASSERT(&CR_OEPRIV(cr), priv)) { \ + DTRACE_PROBE2(priv__ok, int, priv, boolean_t, B_FALSE); \ + return (0); \ + } + /* * Policy checking functions. * @@ -338,17 +343,28 @@ priv_policy_override(const cred_t *cr, int priv, boolean_t allzone, va_list ap) } static int -priv_policy_override_set(const cred_t *cr, const priv_set_t *req, ...) +priv_policy_override_set(const cred_t *cr, const priv_set_t *req, va_list ap) { - va_list ap; - + if (CR_FLAGS(cr) & PRIV_PFEXEC) + return (check_user_privs(cr, req)); if (CR_FLAGS(cr) & PRIV_XPOLICY) { - va_start(ap, req); return (klpd_call(cr, req, ap)); } return (-1); } +static int +priv_policy_override_set_va(const cred_t *cr, const priv_set_t *req, ...) +{ + va_list ap; + int ret; + + va_start(ap, req); + ret = priv_policy_override_set(cr, req, ap); + va_end(ap); + return (ret); +} + /* * Audit failure, log error message. */ @@ -418,7 +434,7 @@ int priv_policy(const cred_t *cr, int priv, boolean_t allzone, int err, const char *msg) { - return (priv_policy_va(cr, priv, allzone, err, msg, KLPDARG_NOMORE)); + return (priv_policy_va(cr, priv, allzone, err, msg, KLPDARG_NONE)); } /* @@ -465,18 +481,24 @@ priv_policy_only(const cred_t *cr, int priv, boolean_t allzone) * Check whether all privileges in the required set are present. */ static int -secpolicy_require_set(const cred_t *cr, const priv_set_t *req, const char *msg) +secpolicy_require_set(const cred_t *cr, const priv_set_t *req, + const char *msg, ...) { int priv; int pfound = -1; priv_set_t pset; + va_list ap; + int ret; if (req == PRIV_FULLSET ? HAS_ALLPRIVS(cr) : priv_issubset(req, &CR_OEPRIV(cr))) { return (0); } - if (priv_policy_override_set(cr, req, KLPDARG_NOMORE) == 0) + va_start(ap, msg); + ret = priv_policy_override_set(cr, req, ap); + va_end(ap); + if (ret == 0) return (0); if (req == PRIV_FULLSET || priv_isfullset(req)) { @@ -542,6 +564,9 @@ secpolicy_setpriority(const cred_t *cr) /* * Binding to a privileged port, port must be specified in host byte * order. + * When adding a new privilege which allows binding to currently privileged + * ports, then you MUST also allow processes with PRIV_NET_PRIVADDR bind + * to these ports because of backward compatibility. */ int secpolicy_net_privaddr(const cred_t *cr, in_port_t port, int proto) @@ -555,10 +580,16 @@ secpolicy_net_privaddr(const cred_t *cr, in_port_t port, int proto) case 139: case 445: /* - * NBT and SMB ports, these are extra privileged ports, - * allow bind only if the SYS_SMB privilege is present. + * NBT and SMB ports, these are normal privileged ports, + * allow bind only if the SYS_SMB or NET_PRIVADDR privilege + * is present. + * Try both, if neither is present return an error for + * priv SYS_SMB. */ - priv = PRIV_SYS_SMB; + if (PRIV_POLICY_ONLY(cr, PRIV_NET_PRIVADDR, B_FALSE)) + priv = PRIV_NET_PRIVADDR; + else + priv = PRIV_SYS_SMB; reason = "NBT or SMB port"; break; @@ -684,8 +715,8 @@ secpolicy_fs_common(cred_t *cr, vnode_t *mvp, const vfs_t *vfsp, if ((err = secpolicy_vnode_owner(cr, va.va_uid)) != 0) return (err); - if ((va.va_mode & VWRITE) == 0 && - secpolicy_vnode_access(cr, mvp, va.va_uid, VWRITE) != 0) { + if (secpolicy_vnode_access2(cr, mvp, va.va_uid, va.va_mode, + VWRITE) != 0) { return (EACCES); } } @@ -839,7 +870,6 @@ secpolicy_fs_linkdir(const cred_t *cr, const vfs_t *vfsp) * Output: EACCES - if privilege check fails. */ -/* ARGSUSED */ int secpolicy_vnode_access(const cred_t *cr, vnode_t *vp, uid_t owner, mode_t mode) { @@ -877,6 +907,116 @@ secpolicy_vnode_access(const cred_t *cr, vnode_t *vp, uid_t owner, mode_t mode) } /* + * Like secpolicy_vnode_access() but we get the actual wanted mode and the + * current mode of the file, not the missing bits. + */ +int +secpolicy_vnode_access2(const cred_t *cr, vnode_t *vp, uid_t owner, + mode_t curmode, mode_t wantmode) +{ + mode_t mode; + + /* Inline the basic privileges tests. */ + if ((wantmode & VREAD) && + !PRIV_ISASSERT(&CR_OEPRIV(cr), PRIV_FILE_READ) && + priv_policy_va(cr, PRIV_FILE_READ, B_FALSE, EACCES, NULL, + KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE) != 0) { + return (EACCES); + } + + if ((wantmode & VWRITE) && + !PRIV_ISASSERT(&CR_OEPRIV(cr), PRIV_FILE_WRITE) && + priv_policy_va(cr, PRIV_FILE_WRITE, B_FALSE, EACCES, NULL, + KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE) != 0) { + return (EACCES); + } + + mode = ~curmode & wantmode; + + if (mode == 0) + return (0); + + if ((mode & VREAD) && priv_policy_va(cr, PRIV_FILE_DAC_READ, B_FALSE, + EACCES, NULL, KLPDARG_VNODE, vp, (char *)NULL, + KLPDARG_NOMORE) != 0) { + return (EACCES); + } + + if (mode & VWRITE) { + boolean_t allzone; + + if (owner == 0 && cr->cr_uid != 0) + allzone = B_TRUE; + else + allzone = B_FALSE; + if (priv_policy_va(cr, PRIV_FILE_DAC_WRITE, allzone, EACCES, + NULL, KLPDARG_VNODE, vp, (char *)NULL, + KLPDARG_NOMORE) != 0) { + return (EACCES); + } + } + + if (mode & VEXEC) { + /* + * Directories use file_dac_search to override the execute bit. + */ + int p = vp->v_type == VDIR ? PRIV_FILE_DAC_SEARCH : + PRIV_FILE_DAC_EXECUTE; + + return (priv_policy_va(cr, p, B_FALSE, EACCES, NULL, + KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE)); + } + return (0); +} + +/* + * This is a special routine for ZFS; it is used to determine whether + * any of the privileges in effect allow any form of access to the + * file. There's no reason to audit this or any reason to record + * this. More work is needed to do the "KPLD" stuff. + */ +int +secpolicy_vnode_any_access(const cred_t *cr, vnode_t *vp, uid_t owner) +{ + static int privs[] = { + PRIV_FILE_OWNER, + PRIV_FILE_DAC_READ, + PRIV_FILE_DAC_WRITE, + PRIV_FILE_DAC_EXECUTE, + PRIV_FILE_DAC_SEARCH, + }; + int i; + + /* Same as secpolicy_vnode_setdac */ + if (owner == cr->cr_uid) + return (0); + + for (i = 0; i < sizeof (privs)/sizeof (int); i++) { + boolean_t allzone = B_FALSE; + int priv; + + switch (priv = privs[i]) { + case PRIV_FILE_DAC_EXECUTE: + if (vp->v_type == VDIR) + continue; + break; + case PRIV_FILE_DAC_SEARCH: + if (vp->v_type != VDIR) + continue; + break; + case PRIV_FILE_DAC_WRITE: + case PRIV_FILE_OWNER: + /* We know here that if owner == 0, that cr_uid != 0 */ + allzone = owner == 0; + break; + } + if (PRIV_POLICY_CHOICE(cr, priv, allzone)) + return (0); + } + return (EPERM); +} + +/* * Name: secpolicy_vnode_setid_modify() * * Normal: verify that subject can set the file setid flags. @@ -1407,14 +1547,19 @@ secpolicy_audit_modify(const cred_t *cr) * "Least" of the two privileges on error. */ int -secpolicy_audit_getattr(const cred_t *cr) +secpolicy_audit_getattr(const cred_t *cr, boolean_t checkonly) { - if (!PRIV_POLICY_ONLY(cr, PRIV_SYS_AUDIT, B_FALSE)) { - return (PRIV_POLICY(cr, PRIV_PROC_AUDIT, B_FALSE, EPERM, - NULL)); - } else { - return (PRIV_POLICY(cr, PRIV_SYS_AUDIT, B_FALSE, EPERM, NULL)); - } + int priv; + + if (PRIV_POLICY_ONLY(cr, PRIV_SYS_AUDIT, B_FALSE)) + priv = PRIV_SYS_AUDIT; + else + priv = PRIV_PROC_AUDIT; + + if (checkonly) + return (!PRIV_POLICY_ONLY(cr, priv, B_FALSE)); + else + return (PRIV_POLICY(cr, priv, B_FALSE, EPERM, NULL)); } @@ -1582,7 +1727,7 @@ secpolicy_zone_config(const cred_t *cr) * Require all privileges to avoid possibility of privilege * escalation. */ - return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); + return (secpolicy_require_set(cr, PRIV_FULLSET, NULL, KLPDARG_NONE)); } /* @@ -1857,12 +2002,20 @@ secpolicy_tasksys(const cred_t *cr) return (PRIV_POLICY(cr, PRIV_PROC_TASKID, B_FALSE, EPERM, NULL)); } +int +secpolicy_pfexec_register(const cred_t *cr) +{ + return (PRIV_POLICY(cr, PRIV_SYS_ADMIN, B_TRUE, EPERM, NULL)); +} + /* * Basic privilege checks. */ int secpolicy_basic_exec(const cred_t *cr, vnode_t *vp) { + FAST_BASIC_CHECK(cr, PRIV_PROC_EXEC); + return (priv_policy_va(cr, PRIV_PROC_EXEC, B_FALSE, EPERM, NULL, KLPDARG_VNODE, vp, (char *)NULL, KLPDARG_NOMORE)); } @@ -1870,12 +2023,16 @@ secpolicy_basic_exec(const cred_t *cr, vnode_t *vp) int secpolicy_basic_fork(const cred_t *cr) { + FAST_BASIC_CHECK(cr, PRIV_PROC_FORK); + return (PRIV_POLICY(cr, PRIV_PROC_FORK, B_FALSE, EPERM, NULL)); } int secpolicy_basic_proc(const cred_t *cr) { + FAST_BASIC_CHECK(cr, PRIV_PROC_SESSION); + return (PRIV_POLICY(cr, PRIV_PROC_SESSION, B_FALSE, EPERM, NULL)); } @@ -1900,15 +2057,39 @@ secpolicy_basic_procinfo(const cred_t *cr, proc_t *tp, proc_t *sp) int secpolicy_basic_link(const cred_t *cr) { + FAST_BASIC_CHECK(cr, PRIV_FILE_LINK_ANY); + return (PRIV_POLICY(cr, PRIV_FILE_LINK_ANY, B_FALSE, EPERM, NULL)); } int secpolicy_basic_net_access(const cred_t *cr) { + FAST_BASIC_CHECK(cr, PRIV_NET_ACCESS); + return (PRIV_POLICY(cr, PRIV_NET_ACCESS, B_FALSE, EACCES, NULL)); } +/* ARGSUSED */ +int +secpolicy_basic_file_read(const cred_t *cr, vnode_t *vp, const char *pn) +{ + FAST_BASIC_CHECK(cr, PRIV_FILE_READ); + + return (priv_policy_va(cr, PRIV_FILE_READ, B_FALSE, EACCES, NULL, + KLPDARG_VNODE, vp, (char *)pn, KLPDARG_NOMORE)); +} + +/* ARGSUSED */ +int +secpolicy_basic_file_write(const cred_t *cr, vnode_t *vp, const char *pn) +{ + FAST_BASIC_CHECK(cr, PRIV_FILE_WRITE); + + return (priv_policy_va(cr, PRIV_FILE_WRITE, B_FALSE, EACCES, NULL, + KLPDARG_VNODE, vp, (char *)pn, KLPDARG_NOMORE)); +} + /* * Additional device protection. * @@ -1969,7 +2150,7 @@ secpolicy_spec_open(const cred_t *cr, struct vnode *vp, int oflag) priv_addset(&pset, PRIV_SYS_NET_CONFIG); } - err = secpolicy_require_set(cr, &pset, "devpolicy"); + err = secpolicy_require_set(cr, &pset, "devpolicy", KLPDARG_NONE); dpfree(plcy); return (err); @@ -2000,7 +2181,8 @@ secpolicy_modctl(const cred_t *cr, int cmd) return (0); case MODLOAD: case MODSETDEVPOLICY: - return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); + return (secpolicy_require_set(cr, PRIV_FULLSET, NULL, + KLPDARG_NONE)); default: return (secpolicy_sys_config(cr, B_FALSE)); } @@ -2025,7 +2207,7 @@ secpolicy_power_mgmt(const cred_t *cr) int secpolicy_sti(const cred_t *cr) { - return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); + return (secpolicy_require_set(cr, PRIV_FULLSET, NULL, KLPDARG_NONE)); } boolean_t @@ -2146,7 +2328,7 @@ secpolicy_gart_map(const cred_t *cr) int secpolicy_zinject(const cred_t *cr) { - return (secpolicy_require_set(cr, PRIV_FULLSET, NULL)); + return (secpolicy_require_set(cr, PRIV_FULLSET, NULL, KLPDARG_NONE)); } /* @@ -2205,7 +2387,7 @@ secpolicy_sadopen(const cred_t *credp) else priv_addset(&pset, PRIV_SYS_IP_CONFIG); - return (secpolicy_require_set(credp, &pset, "devpolicy")); + return (secpolicy_require_set(credp, &pset, "devpolicy", KLPDARG_NONE)); } @@ -2226,7 +2408,7 @@ secpolicy_require_privs(const cred_t *cr, const priv_set_t *nset) priv_inverse(&rqd); priv_intersect(nset, &rqd); - return (secpolicy_require_set(cr, &rqd, NULL)); + return (secpolicy_require_set(cr, &rqd, NULL, KLPDARG_NONE)); } /* diff --git a/usr/src/uts/common/os/priv_defs b/usr/src/uts/common/os/priv_defs index ef77206388..9ec62db828 100644 --- a/usr/src/uts/common/os/priv_defs +++ b/usr/src/uts/common/os/priv_defs @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. * INSERT COMMENT */ @@ -136,6 +135,10 @@ privilege PRIV_FILE_OWNER permission bits or ACL except for the set-uid and set-gid bits. +basic privilege PRIV_FILE_READ + + Allows a process to read objects in the filesystem. + privilege PRIV_FILE_SETID Allows a process to change the ownership of a file or write to @@ -157,6 +160,10 @@ privilege PRIV_FILE_UPGRADE_SL This privilege is interpreted only if the system is configured with Trusted Extensions. +basic privilege PRIV_FILE_WRITE + + Allows a process to modify objects in the filesystem. + privilege PRIV_GRAPHICS_ACCESS Allows a process to make privileged ioctls to graphics devices. diff --git a/usr/src/uts/common/os/project.c b/usr/src/uts/common/os/project.c index 7d10ec9370..98b5b93683 100644 --- a/usr/src/uts/common/os/project.c +++ b/usr/src/uts/common/os/project.c @@ -19,12 +19,9 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/project.h> #include <sys/modhash.h> #include <sys/modctl.h> @@ -361,7 +358,7 @@ project_rele(kproject_t *p) project_kstat_delete(p); if (p->kpj_klpd != NULL) - klpd_remove(&p->kpj_klpd); + klpd_freelist(&p->kpj_klpd); if (mod_hash_destroy(projects_hash, (mod_hash_key_t)p)) panic("unable to delete project %d zone %d", p->kpj_id, diff --git a/usr/src/uts/common/os/zone.c b/usr/src/uts/common/os/zone.c index 4f08e77f59..1d3cfc8f51 100644 --- a/usr/src/uts/common/os/zone.c +++ b/usr/src/uts/common/os/zone.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -227,6 +226,7 @@ #include <sys/vmparam.h> #include <sys/corectl.h> #include <sys/ipc_impl.h> +#include <sys/klpd.h> #include <sys/door.h> #include <sys/cpuvar.h> @@ -2043,6 +2043,8 @@ zone_free(zone_t *zone) kmem_free(zone->zone_bootargs, strlen(zone->zone_bootargs) + 1); if (zone->zone_initname != NULL) kmem_free(zone->zone_initname, strlen(zone->zone_initname) + 1); + if (zone->zone_pfexecd != NULL) + klpd_freelist(&zone->zone_pfexecd); id_free(zoneid_space, zone->zone_id); mutex_destroy(&zone->zone_lock); cv_destroy(&zone->zone_cv); @@ -4479,6 +4481,12 @@ zone_destroy(zoneid_t zoneid) /* Get rid of the zone's kstats */ zone_kstat_delete(zone); + /* remove the pfexecd doors */ + if (zone->zone_pfexecd != NULL) { + klpd_freelist(&zone->zone_pfexecd); + zone->zone_pfexecd = NULL; + } + /* free brand specific data */ if (ZONE_IS_BRANDED(zone)) ZBROP(zone)->b_free_brand_data(zone); diff --git a/usr/src/uts/common/sys/exec.h b/usr/src/uts/common/sys/exec.h index d246d5e885..d36bc20481 100644 --- a/usr/src/uts/common/sys/exec.h +++ b/usr/src/uts/common/sys/exec.h @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -105,6 +104,8 @@ typedef struct uarg { char *brandname; char *auxp_auxflags; /* addr of auxflags auxv on the user stack */ char *auxp_brand; /* address of first brand auxv on user stack */ + cred_t *pfcred; + boolean_t scrubenv; } uarg_t; /* diff --git a/usr/src/uts/common/sys/fs/ufs_acl.h b/usr/src/uts/common/sys/fs/ufs_acl.h index d1849a4d8e..a373384090 100644 --- a/usr/src/uts/common/sys/fs/ufs_acl.h +++ b/usr/src/uts/common/sys/fs/ufs_acl.h @@ -19,15 +19,12 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SYS_FS_UFS_ACL_H #define _SYS_FS_UFS_ACL_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <sys/cred.h> #include <sys/vfs.h> @@ -162,8 +159,8 @@ typedef struct ufs_fsd { #define ACL_CHECK 0x01 #define DEF_ACL_CHECK 0x02 -#define MODE_CHECK(O, M, PERM, C, I) ((((M) & (PERM)) == (M)) ? 0 : \ - secpolicy_vnode_access(C, ITOV(I), O, (M) & ~(PERM))) +#define MODE_CHECK(O, M, PERM, C, I) \ + secpolicy_vnode_access2(C, ITOV(I), O, (PERM), M) /* * Check that the file type is one that accepts ACLs diff --git a/usr/src/uts/common/sys/klpd.h b/usr/src/uts/common/sys/klpd.h index 535af85f89..32769f438f 100644 --- a/usr/src/uts/common/sys/klpd.h +++ b/usr/src/uts/common/sys/klpd.h @@ -19,15 +19,12 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SYS_KLPD_H #define _SYS_KLPD_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <sys/priv.h> #include <sys/procset.h> @@ -61,11 +58,16 @@ struct credklpd; int klpd_reg(int, idtype_t, id_t, priv_set_t *); int klpd_unreg(int, idtype_t, id_t); -void klpd_remove(struct klpd_reg **); +void klpd_freelist(struct klpd_reg **); void klpd_rele(struct klpd_reg *); int klpd_call(const cred_t *, const priv_set_t *, va_list); void crklpd_hold(struct credklpd *); void crklpd_rele(struct credklpd *); +int pfexec_reg(int); +int pfexec_unreg(int); +int pfexec_call(const cred_t *, struct pathname *, cred_t **, boolean_t *); +int get_forced_privs(const cred_t *, const char *, priv_set_t *); +int check_user_privs(const cred_t *, const priv_set_t *); #endif /* _KERNEL */ @@ -95,6 +97,50 @@ typedef struct klpd_arg { #define kla_int kla_data.__idata #define kla_uint kla_data.__uidata +#define PFEXEC_ARG_VERS 0x1 +#define PFEXEC_EXEC_ATTRS 0x1 /* pfexec_reply_t */ +#define PFEXEC_FORCED_PRIVS 0x2 /* priv_set_t */ +#define PFEXEC_USER_PRIVS 0x3 /* uint32_t */ + +#define PFEXEC_ARG_SIZE(bufsize) \ + (offsetof(pfexec_arg_t, pfa_data) + (bufsize)) + +typedef struct pfexec_arg { + uint_t pfa_vers; /* Caller version */ + uint_t pfa_call; /* Call type */ + uint_t pfa_len; /* Length of data */ + uid_t pfa_uid; /* Real uid of subject */ + union { + char __pfa_path[1]; + uint32_t __pfa_buf[1]; + } pfa_data; +} pfexec_arg_t; + +#define pfa_path pfa_data.__pfa_path +#define pfa_buf pfa_data.__pfa_buf + +#define PFEXEC_NOTSET ((uid_t)-1) + +typedef struct pfexec_reply { + uint_t pfr_vers; + uint_t pfr_len; + uid_t pfr_ruid, pfr_euid; + gid_t pfr_rgid, pfr_egid; + boolean_t pfr_setcred; + boolean_t pfr_scrubenv; + boolean_t pfr_clearflag; + boolean_t pfr_allowed; + uint_t pfr_ioff; + uint_t pfr_loff; +} pfexec_reply_t; + +#define PFEXEC_REPLY_IPRIV(pfr) \ + ((pfr)->pfr_ioff ? (priv_set_t *)((char *)(pfr) + (pfr)->pfr_ioff) \ + : (priv_set_t *)0) +#define PFEXEC_REPLY_LPRIV(pfr) \ + ((pfr)->pfr_loff ? (priv_set_t *)((char *)(pfr) + (pfr)->pfr_loff) \ + : (priv_set_t *)0) + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/common/sys/policy.h b/usr/src/uts/common/sys/policy.h index 3bbb416060..1703b7bec9 100644 --- a/usr/src/uts/common/sys/policy.h +++ b/usr/src/uts/common/sys/policy.h @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SYS_POLICY_H @@ -74,7 +73,7 @@ int secpolicy_acct(const cred_t *); int secpolicy_require_privs(const cred_t *, const struct priv_set *); int secpolicy_allow_setid(const cred_t *, uid_t, boolean_t); int secpolicy_audit_config(const cred_t *); -int secpolicy_audit_getattr(const cred_t *); +int secpolicy_audit_getattr(const cred_t *, boolean_t); int secpolicy_audit_modify(const cred_t *); int secpolicy_blacklist(const cred_t *); int secpolicy_chroot(const cred_t *); @@ -120,6 +119,7 @@ boolean_t secpolicy_net_reply_equal(const cred_t *); int secpolicy_newproc(const cred_t *); int secpolicy_nfs(const cred_t *); int secpolicy_pcfs_modify_bootpartition(const cred_t *); +int secpolicy_pfexec_register(const cred_t *); int secpolicy_ponline(const cred_t *); int secpolicy_pool(const cred_t *); int secpolicy_power_mgmt(const cred_t *); @@ -148,6 +148,8 @@ int secpolicy_sys_devices(const cred_t *); int secpolicy_systeminfo(const cred_t *); int secpolicy_tasksys(const cred_t *); int secpolicy_vnode_access(const cred_t *, vnode_t *, uid_t, mode_t); +int secpolicy_vnode_access2(const cred_t *, vnode_t *, uid_t, mode_t, mode_t); +int secpolicy_vnode_any_access(const cred_t *, vnode_t *, uid_t); int secpolicy_vnode_chown(const cred_t *, uid_t); int secpolicy_vnode_create_gid(const cred_t *); int secpolicy_vnode_owner(const cred_t *, uid_t); @@ -171,6 +173,8 @@ int secpolicy_xvm_control(const cred_t *); int secpolicy_basic_exec(const cred_t *, vnode_t *); int secpolicy_basic_fork(const cred_t *); int secpolicy_basic_link(const cred_t *); +int secpolicy_basic_file_read(const cred_t *, vnode_t *, const char *); +int secpolicy_basic_file_write(const cred_t *, vnode_t *, const char *); int secpolicy_basic_net_access(const cred_t *); int secpolicy_basic_proc(const cred_t *); int secpolicy_basic_procinfo(const cred_t *, struct proc *, struct proc *); diff --git a/usr/src/uts/common/sys/priv.h b/usr/src/uts/common/sys/priv.h index 2683446bd2..49beaf156d 100644 --- a/usr/src/uts/common/sys/priv.h +++ b/usr/src/uts/common/sys/priv.h @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SYS_PRIV_H @@ -82,6 +81,9 @@ typedef enum priv_op { #define PRIVSYS_ISSETUGID 5 #define PRIVSYS_KLPD_REG 6 #define PRIVSYS_KLPD_UNREG 7 +#define PRIVSYS_PFEXEC_REG 8 +#define PRIVSYS_PFEXEC_UNREG 9 + /* * Maximum length of a user defined privilege name. @@ -137,10 +139,11 @@ typedef struct priv_impl_info { #define NET_MAC_AWARE_INHERIT 0x0020 /* Inherit MAC aware */ #define PRIV_AWARE_RESET 0x0040 /* Reset on setuid() */ #define PRIV_XPOLICY 0x0080 /* Extended policy */ +#define PRIV_PFEXEC 0x0100 /* As if pfexec'ed */ /* user-settable flags: */ #define PRIV_USER (PRIV_DEBUG | NET_MAC_AWARE | NET_MAC_AWARE_INHERIT |\ - PRIV_XPOLICY | PRIV_AWARE_RESET) + PRIV_XPOLICY | PRIV_AWARE_RESET | PRIV_PFEXEC) /* * Header of the privilege info data structure; multiple structures can diff --git a/usr/src/uts/common/sys/zone.h b/usr/src/uts/common/sys/zone.h index eb6317cf15..ead3f94774 100644 --- a/usr/src/uts/common/sys/zone.h +++ b/usr/src/uts/common/sys/zone.h @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SYS_ZONE_H @@ -336,6 +335,7 @@ typedef struct zone { * zone_ntasks * zone_flags * zone_zsd + * zone_pfexecd */ kmutex_t zone_lock; /* @@ -441,6 +441,8 @@ typedef struct zone { */ struct mntelem *zone_mntfs_db; krwlock_t zone_mntfs_db_lock; + + struct klpd_reg *zone_pfexecd; } zone_t; /* diff --git a/usr/src/uts/common/syscall/auditsys.c b/usr/src/uts/common/syscall/auditsys.c index 43b7df42b9..2b0f535d57 100644 --- a/usr/src/uts/common/syscall/auditsys.c +++ b/usr/src/uts/common/syscall/auditsys.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/systm.h> @@ -106,7 +105,7 @@ getauid(caddr_t auid_p) { const auditinfo_addr_t *ainfo; - if (secpolicy_audit_getattr(CRED()) != 0) + if (secpolicy_audit_getattr(CRED(), B_FALSE) != 0) return (EPERM); ainfo = crgetauinfo(CRED()); @@ -171,7 +170,7 @@ getaudit(caddr_t info_p) const auditinfo_addr_t *ainfo; model_t model; - if (secpolicy_audit_getattr(CRED()) != 0) + if (secpolicy_audit_getattr(CRED(), B_FALSE) != 0) return (EPERM); model = get_udatamodel(); @@ -220,7 +219,7 @@ getaudit_addr(caddr_t info_p, int len) const auditinfo_addr_t *ainfo; model_t model; - if (secpolicy_audit_getattr(CRED()) != 0) + if (secpolicy_audit_getattr(CRED(), B_FALSE) != 0) return (EPERM); model = get_udatamodel(); @@ -1344,7 +1343,7 @@ auditctl( case A_GETPOLICY: case A_GETQCTRL: case A_GETSTAT: - if (secpolicy_audit_getattr(CRED()) != 0) + if (secpolicy_audit_getattr(CRED(), B_FALSE) != 0) return (EPERM); break; default: diff --git a/usr/src/uts/common/syscall/ppriv.c b/usr/src/uts/common/syscall/ppriv.c index 14858710d9..bf42dc9810 100644 --- a/usr/src/uts/common/syscall/ppriv.c +++ b/usr/src/uts/common/syscall/ppriv.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/param.h> @@ -253,7 +252,7 @@ setpflags(uint_t flag, uint_t val, cred_t *tcr) if (val > 1 || (flag != PRIV_DEBUG && flag != PRIV_AWARE && flag != NET_MAC_AWARE && flag != NET_MAC_AWARE_INHERIT && flag != __PROC_PROTECT && flag != PRIV_XPOLICY && - flag != PRIV_AWARE_RESET)) { + flag != PRIV_AWARE_RESET && flag != PRIV_PFEXEC)) { return (EINVAL); } @@ -360,7 +359,8 @@ getpflags(uint_t flag, const cred_t *cr) { if (flag != PRIV_DEBUG && flag != PRIV_AWARE && flag != NET_MAC_AWARE && flag != NET_MAC_AWARE_INHERIT && - flag != PRIV_XPOLICY && flag != PRIV_AWARE_RESET) + flag != PRIV_XPOLICY && flag != PRIV_PFEXEC && + flag != PRIV_AWARE_RESET) return ((uint_t)-1); return ((CR_FLAGS(cr) & flag) != 0); @@ -402,6 +402,10 @@ privsys(int code, priv_op_t op, priv_ptype_t type, void *buf, size_t bufsize, buf)); case PRIVSYS_KLPD_UNREG: return ((int)klpd_unreg((int)op, (idtype_t)itype, (id_t)type)); + case PRIVSYS_PFEXEC_REG: + return ((int)pfexec_reg((int)op)); + case PRIVSYS_PFEXEC_UNREG: + return ((int)pfexec_unreg((int)op)); } return (set_errno(EINVAL)); } diff --git a/usr/src/uts/common/syscall/uid.c b/usr/src/uts/common/syscall/uid.c index e3aa0a2dd2..2841892ff4 100644 --- a/usr/src/uts/common/syscall/uid.c +++ b/usr/src/uts/common/syscall/uid.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -133,6 +132,11 @@ retry_locked: newcr->cr_ruid = uid; newcr->cr_suid = uid; newcr->cr_uid = uid; + + /* Remove the PRIV_PFEXEC, we changed the real uid. */ + if (uidchge) + CR_FLAGS(newcr) &= ~PRIV_PFEXEC; + crsetsid(newcr, ksp, KSID_USER); priv_reset_PA(newcr, B_TRUE); @@ -345,6 +349,10 @@ retry_locked: crsetsid(newcr, ksp, KSID_USER); } if (ruid != -1) { + /* Remove the PRIV_PFEXEC, we changed the real uid. */ + if (uidchge) + CR_FLAGS(newcr) &= ~PRIV_PFEXEC; + oldruid = newcr->cr_ruid; newcr->cr_ruid = ruid; ASSERT(ruid != oldruid ? uidchge : 1); |