PSARC 2009/377 In-kernel pfexec implementation.
authorCasper H.S. Dik <Casper.Dik@Sun.COM>
Wed, 28 Apr 2010 10:01:37 +0200
changeset 12273 63678502e95e
parent 12272 400aca678a81
child 12274 8a6217ddb91a
PSARC 2009/377 In-kernel pfexec implementation. PSARC 2009/378 Basic File Privileges PSARC 2010/072 RBAC update: user attrs from profiles 4912090 pfzsh(1) should exist 4912093 pfbash(1) should exist 4912096 pftcsh(1) should exist 6440298 Expand the basic privilege set in order to restrict file access 6859862 Move pfexec into the kernel 6919171 cred_t sidesteps kmem_debug; we need to be able to detect bad hold/free when they occur 6923721 The new SYS_SMB privilege is not backward compatible 6937562 autofs doesn't remove its door when the zone shuts down 6937727 Zones stuck on deathrow; netstack_zone keeps a credential reference to the zone 6940159 Implement PSARC 2010/072
usr/src/cmd/Makefile
usr/src/cmd/auditrecord/audit_record_attr.txt
usr/src/cmd/auths/auths.c
usr/src/cmd/csh/i386/Makefile
usr/src/cmd/csh/sh.c
usr/src/cmd/csh/sh.exec.c
usr/src/cmd/csh/sparc/Makefile
usr/src/cmd/fs.d/ufs/newfs/newfs.c
usr/src/cmd/ksh/Makefile
usr/src/cmd/ksh/Makefile.com
usr/src/cmd/perl/contrib/Sun/Solaris/Privilege/Privilege.pm
usr/src/cmd/pfexec/Makefile
usr/src/cmd/pfexec/pfexec.c
usr/src/cmd/pfexecd/Makefile
usr/src/cmd/pfexecd/pfexecd.c
usr/src/cmd/pfexecd/pfexecd.xml
usr/src/cmd/profiles/profiles.c
usr/src/cmd/ptools/ppriv/ppriv.c
usr/src/cmd/sh/Makefile
usr/src/cmd/sh/main.c
usr/src/cmd/sh/service.c
usr/src/cmd/sh/sh_policy.c
usr/src/cmd/sh/sh_policy.h
usr/src/cmd/svc/configd/rc_node.c
usr/src/cmd/truss/actions.c
usr/src/cmd/truss/main.c
usr/src/cmd/truss/print.c
usr/src/cmd/truss/proto.h
usr/src/cmd/truss/ramdata.c
usr/src/cmd/truss/ramdata.h
usr/src/head/prof_attr.h
usr/src/head/secdb.h
usr/src/lib/libbsm/audit_event.txt
usr/src/lib/libc/port/gen/getusershell.c
usr/src/lib/libc/port/gen/privlib.c
usr/src/lib/libsecdb/common/chkauthattr.c
usr/src/lib/libsecdb/common/getexecattr.c
usr/src/lib/libsecdb/common/getprofattr.c
usr/src/lib/libsecdb/common/mapfile-vers
usr/src/lib/libsecdb/exec_attr.txt
usr/src/lib/libsecdb/help/profiles/Makefile
usr/src/lib/libsecdb/help/profiles/RtReservedProfile.html
usr/src/lib/libsecdb/prof_attr.txt
usr/src/lib/libshell/Makefile.com
usr/src/lib/libshell/amd64/src/cmd/ksh93/FEATURE/options
usr/src/lib/libshell/i386/src/cmd/ksh93/FEATURE/options
usr/src/lib/libshell/sparc/src/cmd/ksh93/FEATURE/options
usr/src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/options
usr/src/lib/pam_modules/unix_cred/unix_cred.c
usr/src/pkg/manifests/SUNWcs.mf
usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf
usr/src/pkg/manifests/shell-ksh88.mf
usr/src/uts/common/c2/audit.c
usr/src/uts/common/c2/audit.h
usr/src/uts/common/c2/audit_kernel.h
usr/src/uts/common/c2/audit_kevents.h
usr/src/uts/common/c2/audit_start.c
usr/src/uts/common/fs/autofs/auto_vfsops.c
usr/src/uts/common/fs/autofs/auto_vnops.c
usr/src/uts/common/fs/cachefs/cachefs_vnops.c
usr/src/uts/common/fs/dev/sdev_vnops.c
usr/src/uts/common/fs/devfs/devfs_vnops.c
usr/src/uts/common/fs/hsfs/hsfs_node.c
usr/src/uts/common/fs/namefs/namevfs.c
usr/src/uts/common/fs/namefs/namevno.c
usr/src/uts/common/fs/nfs/nfs_vnops.c
usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c
usr/src/uts/common/fs/tmpfs/tmp_subr.c
usr/src/uts/common/fs/udfs/udf_inode.c
usr/src/uts/common/fs/ufs/ufs_inode.c
usr/src/uts/common/fs/zfs/zfs_acl.c
usr/src/uts/common/inet/ip/icmp.c
usr/src/uts/common/inet/ip/spdsock.c
usr/src/uts/common/inet/spdsock.h
usr/src/uts/common/os/cred.c
usr/src/uts/common/os/exec.c
usr/src/uts/common/os/klpd.c
usr/src/uts/common/os/policy.c
usr/src/uts/common/os/priv_defs
usr/src/uts/common/os/project.c
usr/src/uts/common/os/zone.c
usr/src/uts/common/sys/exec.h
usr/src/uts/common/sys/fs/ufs_acl.h
usr/src/uts/common/sys/klpd.h
usr/src/uts/common/sys/policy.h
usr/src/uts/common/sys/priv.h
usr/src/uts/common/sys/zone.h
usr/src/uts/common/syscall/auditsys.c
usr/src/uts/common/syscall/ppriv.c
usr/src/uts/common/syscall/uid.c
--- a/usr/src/cmd/Makefile	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/Makefile	Wed Apr 28 10:01:37 2010 +0200
@@ -292,6 +292,7 @@
 	pcidr		\
 	pcitool		\
 	pfexec		\
+	pfexecd		\
 	pgrep		\
 	picl		\
 	plimit		\
--- a/usr/src/cmd/auditrecord/audit_record_attr.txt	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/auditrecord/audit_record_attr.txt	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 #	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":
--- a/usr/src/cmd/auths/auths.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/auths/auths.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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
 
-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 *);
+typedef struct cbs {
+	int	auth_cnt;
+	int	auth_max;
+	char	**auths;
+} cbs_t;
+
+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 @@
 		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);
-		}
+		simplify(&cbs);
 
-		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]);
-			}
+		if (print_name)
+			(void) printf("%s: ", username);
 
-			/* print out the last entry, without the comma */
-			(void) printf("%s\n", userauths[userauth_cnt - 1]);
-		}
-	}
-
-	/* free memory allocated for authorizations */
-	free_auths(userauths, &userauth_cnt);
-
-	return (status);
-}
-
+		/* print out the auths */
+		for (i = 0; i < cbs.auth_cnt - 1; i++)
+			(void) printf("%s,", cbs.auths[i]);
 
-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;
+		/* print out the last entry, without the comma */
+		(void) printf("%s\n", cbs.auths[cbs.auth_cnt - 1]);
 
-	authlist = kva_match(user->attr, USERATTR_AUTHS_KW);
-	if (authlist != NULL) {
-		add_auths(authlist, authArray, authcnt);
+		/* free memory allocated for authorizations */
+		free_auths(&cbs);
 	}
-	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);
-	}
-	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);
-		}
-
-		/* get authorizations from default profiles */
-		if (profs != NULL) {
-			getProfiles(profs, profArray, &profcnt,
-			    authArray, authcnt);
-			free_proflist(profArray, profcnt);
-		}
-		_free_user_defs(auths, profs);
-	}
-}
-
-void
-add_auths(char *auths, char **authArray, int *authcnt)
-{
-	char	*authname, *lasts, *real_authname;
-	int	i;
+	cbs->auths[cbs->auth_cnt] = strdup(authname);
+	cbs->auth_cnt++;
 
-	for (authname = (char *)strtok_r(auths, AUTH_SEP, &lasts);
-	    authname != NULL;
-	    authname = (char *)strtok_r(NULL, AUTH_SEP, &lasts)) {
-
-		if ((strcmp(authname, KV_WILDCARD) == 0) ||
-		    (strcmp(authname, ALL_SUN_AUTHS) == 0)) {
-			real_authname = ALL_AUTHS;
-		} else {
-			real_authname = authname;
-		}
-
-		/* 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 */
-			}
-		}
-
-		/* not in list, add it in */
-		if (i == *authcnt) {
-			authArray[i] = strdup(real_authname);
-			*authcnt = i + 1;
-		}
-	}
-
+	return (0);
 }
 
 static void
-free_auths(char *auths[], int *auth_cnt)
+free_auths(cbs_t *cbs)
 {
 	int i;
 
-	for (i = 0; i < *auth_cnt; i++) {
-		free(auths[i]);
-	}
-	*auth_cnt = 0;
+	for (i = 0; i < cbs->auth_cnt; i++)
+		free(cbs->auths[i]);
+
+	free(cbs->auths);
+}
+
+/* We have always ignored .grant in auths(1) */
+static boolean_t
+auth_match(const char *pattern, const char *auth)
+{
+	size_t len = strlen(pattern);
+
+	if (pattern[len - 1] != KV_WILDCHAR)
+		return (B_FALSE);
+
+	return (strncmp(pattern, auth, len - 1) == 0);
+}
+
+static int
+mstrptr(const void *a, const void *b)
+{
+	char *const *ap = a;
+	char *const *bp = b;
+
+	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)
 {
+	int rem, i;
+
+	/* First we sort */
+	qsort(cbs->auths, cbs->auth_cnt, sizeof (cbs->auths[0]), mstrptr);
 
-	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);
+	/*
+	 * 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];
+		}
 	}
 
-	/* 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);
-		}
-
-		free_profattr(pa);
-	}
+	cbs->auth_cnt -= rem;
 }
--- a/usr/src/cmd/csh/i386/Makefile	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/csh/i386/Makefile	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 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 @@
 	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 @@
 	$(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)
--- a/usr/src/cmd/csh/sh.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/csh/sh.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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_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 @@
 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 @@
 	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 @@
 #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 @@
 		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 @@
 	 */
 	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 @@
 			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 @@
 		}
 
 		/* 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 @@
 		 */
 		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 @@
 	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 @@
 		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 @@
 		(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 @@
 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 @@
 	 * 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 @@
 		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;
-	}
-}
--- a/usr/src/cmd/csh/sh.exec.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/csh/sh.exec.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 		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 @@
 				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 @@
 void
 texec(struct command *cmd, tchar *f, tchar **t)
 {
-	int	pfstatus = 0;
 	struct	varent *v;
 	tchar	**vp;
 	tchar		*lastsh[2];
@@ -204,16 +201,7 @@
 	/* 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 @@
 #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 @@
 
 	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 @@
 	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 @@
 			    (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 @@
 
 	if (hits+misses)
 		printf("%d hits, %d misses, %d%%\n",
-			hits, misses, 100 * hits / (hits + misses));
+		    hits, misses, 100 * hits / (hits + misses));
 }
 #endif
 
--- a/usr/src/cmd/csh/sparc/Makefile	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/csh/sparc/Makefile	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 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 @@
 	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 @@
 	$(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)
--- a/usr/src/cmd/fs.d/ufs/newfs/newfs.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/fs.d/ufs/newfs/newfs.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 	 * 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,
--- a/usr/src/cmd/ksh/Makefile	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/ksh/Makefile	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 	$(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
--- a/usr/src/cmd/ksh/Makefile.com	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/ksh/Makefile.com	Wed Apr 28 10:01:37 2010 +0200
@@ -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
--- a/usr/src/cmd/perl/contrib/Sun/Solaris/Privilege/Privilege.pm	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/perl/contrib/Sun/Solaris/Privilege/Privilege.pm	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 
 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
--- a/usr/src/cmd/pfexec/Makefile	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/pfexec/Makefile	Wed Apr 28 10:01:37 2010 +0200
@@ -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:
 
--- a/usr/src/cmd/pfexec/pfexec.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/pfexec/pfexec.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 <string.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>
-
-#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);
-}
+#define	RES_PFEXEC	1
+#define	RES_OK		0
+#define	RES_FAILURE	-1
 
 /*
- * gets execution attributed for cmd, sets uids/gids, checks environ.
- * returns 1 on success, 0 on failure.
+ * Return the shellname
  */
-static int
-checkattrs(char *cmd_realpath, int argc, char *argv[])
+int
+shellname(const char *name, char buf[MAXPATHLEN])
 {
-	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;
+	const char *cmd = strrchr(name, '/');
 
-	adt_session_data_t	*ah;		/* audit session handle */
-	adt_event_data_t	*event;		/* event to be generated */
-	char			cwd[MAXPATHLEN];
+	if (cmd == NULL)
+		cmd = name;
+	else
+		cmd++;
 
-	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();
-	}
+	if (strncmp(cmd, "pf", 2) != 0)
+		return (RES_FAILURE);
+
+	if (strcmp(cmd, PFEXEC) == 0)
+		return (RES_PFEXEC);
 
-	/* 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);
+	if (strlen(name) >= MAXPATHLEN)
+		return (RES_FAILURE);
 
-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 (cmd == name) {
+		(void) strlcpy(buf, cmd + 2, MAXPATHLEN);
+	} else {
+		(void) strncpy(buf, name, cmd - name);
+		(void) strcpy(buf + (cmd - name), cmd + 2);
 	}
-	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);
-}
-
-
-/*
- * cleans up environ. code from su.c
- */
-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));
+	return (RES_OK);
 
-	(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)
-{
-	struct group *group_ent;
-
-	if ((group_ent = getgrnam(value)) != NULL)
-		return (group_ent->gr_gid);
-
-	if (isnumber(value))
-		return (atoi(value));
-
-	(void) fprintf(stderr, "pfexec: %s: ", value);
-	(void) fprintf(stderr, gettext("can't get group entry\n"));
-	exit(EXIT_FAILURE);
-	/*NOTREACHED*/
-}
-
-
-static int
-isnumber(char *s)
-{
-	int c;
-
-	if (*s == '\0')
-		return (0);
-
-	while ((c = *s++) != '\0') {
-		if (!isdigit(c)) {
-			return (0);
-		}
-	}
-
-	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 @@
 	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)
+int
+main(int argc, char **argv)
 {
-	struct passwd *pwent;
-	userattr_t *ua;
-	char *profs;
-	priv_set_t *res;
-	char *profArray[MAXPROFS];
-	int profcnt = 0;
+	char *cmd;
+	char *pset = NULL;
+	char pathbuf[MAXPATHLEN];
+	int c;
+	priv_set_t *wanted;
+	int oflag;
 
-	res = priv_allocset();
-	if (res == NULL) {
-		perror("priv_allocset");
-		exit(EXIT_FAILURE);
+	oflag = getpflags(PRIV_PFEXEC);
+	if (setpflags(PRIV_PFEXEC, 1) != 0) {
+		perror("setpflags(PRIV_PFEXEC)");
+		exit(1);
 	}
 
-	priv_emptyset(res);
+	if (*argv[0] == '-')
+		cmd = argv[0] + 1;
+	else
+		cmd = argv[0];
 
-	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);
+	/* 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] = '-';
 	}
 
-	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)
-{
+	/* If this fails, we just continue with plan B */
+	if (shellname(getexecname(), pathbuf) == RES_OK)
+		(void) execv(pathbuf, 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++) {
+	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();
 
-		if ((pa = getprofnam(profArray[i])) == NULL) {
-			/*
-			 *  this should never happen.
-			 *  unless the database has an undefined profile
-			 */
-			continue;
-		}
-
-		/* 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);
+		(void) execvp(argv[0], argv);
+		perror(argv[0]);
+		return (1);
 	}
+	return (1);
 }
-
-/*
- * 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);
-	}
-
-	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);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/pfexecd/Makefile	Wed Apr 28 10:01:37 2010 +0200
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/pfexecd/pfexecd.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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(&regc, regexpr, REG_EXTENDED) != 0)
+		return;
+
+	cansplice = B_TRUE;
+}
+
+#define	NMATCH	2
+
+static boolean_t
+removeisapath(char *path)
+{
+	regmatch_t match[NMATCH];
+
+	if (!cansplice || regexec(&regc, 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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/pfexecd/pfexecd.xml	Wed Apr 28 10:01:37 2010 +0200
@@ -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>
--- a/usr/src/cmd/profiles/profiles.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/profiles/profiles.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 	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,25 +143,23 @@
 		(void) fprintf(stderr, gettext("No such user\n"));
 		return (status);
 	}
-	if (username != NULL) {
-		if ((user = getusernam(username)) != NULL) {
-			status = list_profs(user, print_flag);
+
+	if (print_flag & PRINT_LONG) {
+		exec = getexecuser(username, KV_COMMAND, NULL,
+		    GET_ALL|__SEARCH_ALL_POLS);
+		if (exec != NULL) {
+			print_profs_long(exec);
+			free_execattr(exec);
 		} 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);
-				}
-			}
+			status = EXIT_NON_FATAL;
 		}
+	} else {
+		int cnt = 0;
+		(void) _enum_profs(username, show_profs_callback, &print_flag,
+		    &cnt);
+
+		if (cnt == 0)
+			status = EXIT_NON_FATAL;
 	}
 
 	if (status == EXIT_NON_FATAL) {
@@ -164,47 +170,6 @@
 	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,
-		    GET_ALL|__SEARCH_ALL_POLS);
-		if (exec == NULL) {
-			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) {
-			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);
-		}
-	}
-	free_userattr(user);
-
-	return (status);
-}
-
-
 /*
  * print extended profile information.
  *
@@ -242,9 +207,16 @@
 	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 @@
 }
 
 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);
-		}
-	}
-}
--- a/usr/src/cmd/ptools/ppriv/ppriv.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/ptools/ppriv/ppriv.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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	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 @@
 	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 @@
 			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 @@
 		}
 	}
 
-	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 @@
 			fl |= PRIV_DEBUG;
 		if (Doff)
 			fl &= ~PRIV_DEBUG;
+		if (pfexec)
+			fl |= PRIV_PFEXEC;
 		if (xpol)
 			fl |= PRIV_XPOLICY;
 
@@ -552,6 +558,10 @@
 		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 @@
 		(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 @@
 	{ 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" },
 };
--- a/usr/src/cmd/sh/Makefile	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/sh/Makefile	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 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 @@
 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 @@
 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
 
--- a/usr/src/cmd/sh/main.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/sh/main.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 	(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 @@
 		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;
-	}
-}
--- a/usr/src/cmd/sh/service.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/sh/service.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 		if (argp >= brkend)
 			growstak(argp);
 	}
-	while (*argp++ = *scanp++);
+	while (*argp++ = *scanp++)
+		;
 	return (path);
 }
 
@@ -253,7 +250,6 @@
 static unsigned char *
 execs(unsigned char *ap, unsigned char *t[])
 {
-	int		pfstatus = NOATTRS;
 	unsigned char	*p, *prefix;
 	unsigned char	*savptr;
 
@@ -261,28 +257,8 @@
 	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 @@
 		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 @@
 			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 @@
 		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);
 		}
--- a/usr/src/cmd/sh/sh_policy.c	Wed Apr 28 09:25:44 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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);
-}
--- a/usr/src/cmd/sh/sh_policy.h	Wed Apr 28 09:25:44 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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 */
--- a/usr/src/cmd/svc/configd/rc_node.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/svc/configd/rc_node.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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_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);
-
-		if (ret != PERM_DENIED)
-			return (ret);
-	}
-
+
+static int
+auth_cb(const char *auth, void *ctxt, void *vres)
+{
+	permcheck_t *pcp = ctxt;
+	int *pret = vres;
+
+	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 @@
 	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 @@
 	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,50 +1559,11 @@
 	}
 
 	/*
-	 * Get user's default authorizations from policy.conf
-	 */
-	rv = _get_user_defs(pw.pw_name, &authlist, &def_prof);
-
-	if (rv != 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.
+	 * Enumerate all the auths defined for the user and return the
+	 * result in ret.
 	 */
-
-	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);
+	if (_enum_auths(pw.pw_name, auth_cb, pcp, &ret) < 0)
+		return (PERM_FAIL);
 
 	return (ret);
 }
--- a/usr/src/cmd/truss/actions.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/truss/actions.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 	if (raw)
 		showpaths(pri, &systable[SYS_execve]);
 
-	show_cred(pri, FALSE);
+	show_cred(pri, FALSE, FALSE);
 
 	if (aflag || eflag) {		/* dump args or environment */
 
--- a/usr/src/cmd/truss/main.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/truss/main.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 	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 @@
 					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 @@
 	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 @@
 			    (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 @@
 	else
 		(void) Punsetflags(Proc, PR_FORK);
 	procadd(set->pid, set->lwps);
-	show_cred(pri, TRUE);
+	show_cred(pri, TRUE, FALSE);
 	return (TRUE);
 }
 
--- a/usr/src/cmd/truss/print.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/truss/print.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 		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";
--- a/usr/src/cmd/truss/proto.h	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/truss/proto.h	Wed Apr 28 10:01:37 2010 +0200
@@ -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	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 *);
 
--- a/usr/src/cmd/truss/ramdata.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/truss/ramdata.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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	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 */
 
--- a/usr/src/cmd/truss/ramdata.h	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/cmd/truss/ramdata.h	Wed Apr 28 10:01:37 2010 +0200
@@ -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	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 */
 
--- a/usr/src/head/prof_attr.h	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/head/prof_attr.h	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 #define	PROFATTR_COL3_KW		"desc"
 #define	PROFATTR_COL4_KW		"attr"
 
+#define	PROFILE_STOP			"Stop"
+
 #define	DEF_PROF			"PROFS_GRANTED="
 #define	DEF_CONSUSER			"CONSOLE_USER="
 
--- a/usr/src/head/secdb.h	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/head/secdb.h	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 #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 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
 }
--- a/usr/src/lib/libbsm/audit_event.txt	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/lib/libbsm/audit_event.txt	Wed Apr 28 10:01:37 2010 +0200
@@ -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
--- a/usr/src/lib/libc/port/gen/getusershell.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/lib/libc/port/gen/getusershell.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 	"/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
--- a/usr/src/lib/libc/port/gen/privlib.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/lib/libc/port/gen/privlib.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 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
--- a/usr/src/lib/libsecdb/common/chkauthattr.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/lib/libsecdb/common/chkauthattr.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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>
 
-
-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 *);
-int
-chkauthattr(const char *authname, const char *username)
-{
-	int		auth_granted = 0;
-	char		*auths;
-	char		*profiles;
-	userattr_t	*user = NULL;
-	char		*chkedprof[MAXPROFS];
-	int		chkedprof_cnt = 0;
-	int		i;
-
-	if (authname == NULL || username == 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 ((user = getusernam(username)) == NULL)
-		goto exit;
-
-	/* 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;
-	}
-
-	/* 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);
-
-exit:
-	/* free memory allocated for checked array */
-	for (i = 0; i < chkedprof_cnt; i++) {
-		free(chkedprof[i]);
+#define	COPYTOSTACK(dst, csrc)		{	\
+		size_t len = strlen(csrc) + 1;	\
+		dst = alloca(len);		\
+		(void) memcpy(dst, csrc, len);	\
 	}
 
-	if (user != NULL)
-		free_userattr(user);
+static kva_t *get_default_attrs(const char *);
+static void free_default_attrs(kva_t *);
 
-	return (auth_granted);
-}
+/*
+ * 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
-_chkprof_for_auth(const char *profs, const char *authname,
-    char **chkedprof, int *chkedprof_cnt)
-{
+#define	CONSUSER_PROFILE_KW		"consprofile"
+#define	DEF_LOCK_AFTER_RETRIES		"LOCK_AFTER_RETRIES="
 
-	char *prof, *lasts, *auths, *profiles;
-	profattr_t	*pa;
-	int		i;
-	int		checked = 0;
+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}
+};
 
-	for (prof = strtok_r((char *)profs, ",", &lasts); prof != NULL;
-	    prof = strtok_r(NULL, ",", &lasts)) {
+#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))
 
-		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;
-			}
-		}
+/*
+ * Enumerate profiles from listed profiles.
+ */
+int
+_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])
+{
+	char *prof, *last;
+	char *profiles;
+	profattr_t *pa;
+	int i;
+	int res = 0;
 
-		if (!checked) {
+	if (cprofiles == NULL)
+		return (0);
 
-			chkedprof[*chkedprof_cnt] = strdup(prof);
-			*chkedprof_cnt = *chkedprof_cnt + 1;
+	if (*pcnt > 0 && strcmp(profs[*pcnt - 1], PROFILE_STOP) == NULL)
+		return (0);
+
+	COPYTOSTACK(profiles, cprofiles)
+
+	while (prof = strtok_r(profiles, KV_SEPSTR, &last)) {
 
-			if ((pa = getprofnam(prof)) == NULL)
-				continue;
+		profiles = NULL;	/* For next iterations of strtok_r */
+
+		for (i = 0; i < *pcnt; i++)
+			if (strcmp(profs[i], prof) == 0)
+				goto cont;
+
+		if (*pcnt >= MAXPROFS)		/* oops: too many profs */
+			return (-1);
+
+		/* Add it */
+		profs[(*pcnt)++] = strdup(prof);
 
-			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);
-				}
+		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;
 	}
-	/* authorization not found in any profile */
-	return (0);
+	return (res);
+}
+
+/*
+ * Enumerate all attributes associated with a username and the profiles
+ * associated with the user.
+ */
+static int
+_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;
+
+	if (cb == NULL)
+		return (-1);
+
+	ua = getusernam(username);
+
+	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 ((cnt == 0 || strcmp(profs[cnt-1], PROFILE_STOP) != 0) &&
+	    (kattrs = get_default_attrs(username)) != NULL) {
+
+		res = _enum_common_p(GETCONSPROF(kattrs), cb, ctxt, pres,
+		    wantattr, &cnt, profs);
+
+		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);
+	}
+
+	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 @@
 	 * 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 @@
 }
 
 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;
+	int *resp = res;
 
-	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;
-			}
-		}
+	if (strcmp(authname, auth) == 0 ||
+	    (strchr(auth, KV_WILDCHAR) != NULL &&
+	    _auth_match(auth, authname))) {
+		*resp = 1;
+		return (1);
 	}
 
-	free(buf);
-
-	return (found);
+	return (0);
 }
 
+int
+chkauthattr(const char *authname, const char *username)
+{
+	int		auth_granted = 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)
-{
-	char	*auths = NULL;
-	char	*profs = NULL;
-	int	ret = 1;
-
-	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;
-	}
+	(void) _enum_auths(username, _is_authorized, (char *)authname,
+	    &auth_granted);
 
-	if (profs != NULL) {
-		if (_chkprof_for_auth(profs, authname, chkedprof,
-		    chkedprof_cnt))
-			goto exit;
-	}
-	ret = 0;
-
-exit:
-	_free_user_defs(auths, profs);
-	return (ret);
+	return (auth_granted);
 }
 
 #define	CONSOLE_USER_LINK "/dev/vt/console_user"
@@ -257,77 +366,58 @@
 	return (pw.pw_uid == cons.st_uid);
 }
 
-
-int
-_get_user_defs(const char *user, char **def_auth, char **def_prof)
+static void
+free_default_attrs(kva_t *kva)
 {
-	char *cp;
-	char *profs;
-	void	*defp;
+	int i;
+
+	for (i = 0; i < kva->length; i++)
+		free(kva->data[i].value);
+
+	free(kva);
+}
+
+/*
+ * Return the default attributes; this are ignored when a STOP profile
+ * was found.
+ */
+static kva_t *
+get_default_attrs(const char *user)
+{
+	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 (kva == NULL)
+		return (NULL);
+
+	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;
 	}
 
-	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;
+	(void) defclose_r(defp);
+	return (kva);
 
-			if (*def_prof == NULL) {
-				if ((*def_prof = strdup(cp)) == NULL) {
-					defclose_r(defp);
-					return (-1);
-				}
-				defclose_r(defp);
-				return (0);
-			}
+return_null:
+	if (defp != NULL)
+		(void) defclose_r(defp);
 
-			/* 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;
-		}
-	}
-
-	defclose_r(defp);
-	return (0);
+	free_default_attrs(kva);
+	return (NULL);
 }
-
-
-void
-_free_user_defs(char *def_auth, char *def_prof)
-{
-	free(def_auth);
-	free(def_prof);
-}
--- a/usr/src/lib/libsecdb/common/getexecattr.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/lib/libsecdb/common/getexecattr.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 	}
 }
 
+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);
-	}
-
-	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);
-			}
-		}
+		return (NULL);
 	}
 
-	/* 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);
-	}
-
-	if (profcnt == 0) {
-		return (head);
-	}
+	result.head = result.prev = NULL;
+	call.type = type;
+	call.id = id;
+	call.sflag = search_flag;
 
-	/* 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);
+	(void) _enum_profs(username, findexecattr, &call, &result);
+
+	return (result.head);
 }
 
 
--- a/usr/src/lib/libsecdb/common/getprofattr.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/lib/libsecdb/common/getprofattr.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 }
 
 
+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 @@
 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
--- a/usr/src/lib/libsecdb/common/mapfile-vers	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/lib/libsecdb/common/mapfile-vers	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 	_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:
 	*;
 };
--- a/usr/src/lib/libsecdb/exec_attr.txt	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/lib/libsecdb/exec_attr.txt	Wed Apr 28 10:01:37 2010 +0200
@@ -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/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
--- a/usr/src/lib/libsecdb/help/profiles/Makefile	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/lib/libsecdb/help/profiles/Makefile	Wed Apr 28 10:01:37 2010 +0200
@@ -73,6 +73,7 @@
 	RtPrntAdmin.html \
 	RtProcManagement.html \
 	RtReparseMngmnt.html \
+	RtReservedProfile.html \
 	RtRightsDelegate.html \
 	RtSMBMngmnt.html \
 	RtSMBFSMngmnt.html \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsecdb/help/profiles/RtReservedProfile.html	Wed Apr 28 10:01:37 2010 +0200
@@ -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>
--- a/usr/src/lib/libsecdb/prof_attr.txt	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/lib/libsecdb/prof_attr.txt	Wed Apr 28 10:01:37 2010 +0200
@@ -44,6 +44,7 @@
 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 @@
 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
--- a/usr/src/lib/libshell/Makefile.com	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/lib/libshell/Makefile.com	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 	-ldll \
 	-last \
 	-lsocket \
-	-lsecdb \
 	-lm \
 	-lc
 
--- a/usr/src/lib/libshell/amd64/src/cmd/ksh93/FEATURE/options	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/lib/libshell/amd64/src/cmd/ksh93/FEATURE/options	Wed Apr 28 10:01:37 2010 +0200
@@ -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
--- a/usr/src/lib/libshell/i386/src/cmd/ksh93/FEATURE/options	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/lib/libshell/i386/src/cmd/ksh93/FEATURE/options	Wed Apr 28 10:01:37 2010 +0200
@@ -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
--- a/usr/src/lib/libshell/sparc/src/cmd/ksh93/FEATURE/options	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/lib/libshell/sparc/src/cmd/ksh93/FEATURE/options	Wed Apr 28 10:01:37 2010 +0200
@@ -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
--- a/usr/src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/options	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/lib/libshell/sparcv9/src/cmd/ksh93/FEATURE/options	Wed Apr 28 10:01:37 2010 +0200
@@ -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
--- a/usr/src/lib/pam_modules/unix_cred/unix_cred.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/lib/pam_modules/unix_cred/unix_cred.c	Wed Apr 28 10:01:37 2010 +0200
@@ -75,21 +75,17 @@
 }
 
 /*
- * 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 @@
 	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 @@
 	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 @@
 	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 @@
 		return (PAM_SYSTEM_ERR);
 	}
 
-	ua = getusernam(user);
-
-	defp = defopen_r(AUTH_POLICY);
+	tset = def = lim = NULL;
+	deflim.def = deflim.lim = NULL;
 
-	tset = def = lim = NULL;
+	(void) _enum_attrs(user, finddeflim, NULL, &deflim);
 
-	if (getset(USERATTR_LIMPRIV_KW, DEF_LIMITPRIV, ua, &lim, defp) != 0 ||
-	    getset(USERATTR_DFLTPRIV_KW, DEF_DFLTPRIV, ua, &def, defp) != 0) {
+	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 @@
 	 * 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)
--- a/usr/src/pkg/manifests/SUNWcs.mf	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/pkg/manifests/SUNWcs.mf	Wed Apr 28 10:01:37 2010 +0200
@@ -735,7 +735,7 @@
 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/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/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/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=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/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/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 @@
     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/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/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/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
--- a/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf	Wed Apr 28 10:01:37 2010 +0200
@@ -269,6 +269,7 @@
 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
--- a/usr/src/pkg/manifests/shell-ksh88.mf	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/pkg/manifests/shell-ksh88.mf	Wed Apr 28 10:01:37 2010 +0200
@@ -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/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
--- a/usr/src/uts/common/c2/audit.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/c2/audit.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
  * 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 @@
 	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);
+
+		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));
 
-	if (kctx->auk_policy & AUDIT_ARGV) {
-		au_uwrite(au_to_exec_args(argstr, argc));
+		/*
+		 * 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));
-	}
 }
 
 /*
--- a/usr/src/uts/common/c2/audit.h	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/c2/audit.h	Wed Apr 28 10:01:37 2010 +0200
@@ -529,7 +529,7 @@
 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 **);
--- a/usr/src/uts/common/c2/audit_kernel.h	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/c2/audit_kernel.h	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 #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
  */
--- a/usr/src/uts/common/c2/audit_kevents.h	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/c2/audit_kevents.h	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 #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) */
--- a/usr/src/uts/common/c2/audit_start.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/c2/audit_start.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 		    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);
--- a/usr/src/uts/common/fs/autofs/auto_vfsops.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/fs/autofs/auto_vfsops.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 		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().
--- a/usr/src/uts/common/fs/autofs/auto_vnops.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/fs/autofs/auto_vnops.c	Wed Apr 28 10:01:37 2010 +0200
@@ -337,10 +337,8 @@
 			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:
--- a/usr/src/uts/common/fs/cachefs/cachefs_vnops.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/fs/cachefs/cachefs_vnops.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 			 * 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 @@
 			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 @@
  * 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)
--- a/usr/src/uts/common/fs/dev/sdev_vnops.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/fs/dev/sdev_vnops.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 			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
--- a/usr/src/uts/common/fs/devfs/devfs_vnops.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/fs/devfs/devfs_vnops.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 			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
--- a/usr/src/uts/common/fs/hsfs/hsfs_node.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/fs/hsfs/hsfs_node.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 		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)
--- a/usr/src/uts/common/fs/namefs/namevfs.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/fs/namefs/namevfs.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 	 * 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;
 	}
--- a/usr/src/uts/common/fs/namefs/namevno.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/fs/namefs/namevno.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 		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.
--- a/usr/src/uts/common/fs/nfs/nfs_vnops.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/fs/nfs/nfs_vnops.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 		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;
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 		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 @@
 	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));
 }
 
 /*
--- a/usr/src/uts/common/fs/tmpfs/tmp_subr.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/fs/tmpfs/tmp_subr.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 			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));
 }
 
 /*
--- a/usr/src/uts/common/fs/udfs/udf_inode.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/fs/udfs/udf_inode.c	Wed Apr 28 10:01:37 2010 +0200
@@ -1963,13 +1963,9 @@
 		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)
--- a/usr/src/uts/common/fs/ufs/ufs_inode.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/fs/ufs/ufs_inode.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 			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);
--- a/usr/src/uts/common/fs/zfs/zfs_acl.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/fs/zfs/zfs_acl.c	Wed Apr 28 10:01:37 2010 +0200
@@ -2251,15 +2251,8 @@
 	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 @@
 }
 
 /*
- * 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 @@
 	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 @@
 		}
 	}
 
+	/*
+	 * 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 @@
 		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 @@
 				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 @@
 
 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 @@
 	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 @@
 	 * 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;
+	available_perms = (dzp_working_mode & ACE_WRITE_DATA) ? 0 : VWRITE;
+	available_perms |= (dzp_working_mode & ACE_EXECUTE) ? 0 : VEXEC;
 
-	ASSERT(missing_perms);
-
-	return (zfs_delete_final_check(zp, dzp, missing_perms, cr));
+	return (zfs_delete_final_check(zp, dzp, available_perms, cr));
 
 }
 
--- a/usr/src/uts/common/inet/ip/icmp.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/inet/ip/icmp.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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>
--- a/usr/src/uts/common/inet/ip/spdsock.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/inet/ip/spdsock.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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_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 @@
 	 * 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 @@
 	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 @@
 		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 @@
 	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);
 }
--- a/usr/src/uts/common/inet/spdsock.h	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/inet/spdsock.h	Wed Apr 28 10:01:37 2010 +0200
@@ -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_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];
--- a/usr/src/uts/common/os/cred.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/os/cred.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 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 @@
 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 @@
 	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 */
--- a/usr/src/uts/common/os/exec.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/os/exec.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 	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 @@
 	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 @@
 		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 @@
 		 *
 		 *	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 @@
 	 * 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 @@
 	}
 	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 @@
 	}
 
 	if (level == 0) {
+		uid_t oruid;
+
 		if (execvp != NULL) {
 			/*
 			 * Close the previous executable only if we are
@@ -728,6 +780,9 @@
 		}
 
 		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 @@
 			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 @@
 }
 
 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 @@
 
 	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 @@
 	    !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 @@
 	 */
 	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 @@
 
 	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
--- a/usr/src/uts/common/os/klpd.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/os/klpd.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 }
 
 /*
- * 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 @@
 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 @@
 		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 @@
 			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 @@
 		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 @@
 	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 *)&pr;
+	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);
+}
--- a/usr/src/uts/common/os/policy.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/os/policy.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 					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 @@
 }
 
 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 @@
 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 @@
  * 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 @@
 /*
  * 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 @@
 	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 @@
 		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 @@
  * 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 @@
 }
 
 /*
+ * 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 @@
  * "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 @@
 	 * 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 @@
 	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 @@
 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 @@
 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 @@
 		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 @@
 		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 @@
 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 @@
 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 @@
 	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 @@
 	priv_inverse(&rqd);
 	priv_intersect(nset, &rqd);
 
-	return (secpolicy_require_set(cr, &rqd, NULL));
+	return (secpolicy_require_set(cr, &rqd, NULL, KLPDARG_NONE));
 }
 
 /*
--- a/usr/src/uts/common/os/priv_defs	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/os/priv_defs	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 	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 @@
 	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.
--- a/usr/src/uts/common/os/project.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/os/project.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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_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,
--- a/usr/src/uts/common/os/zone.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/os/zone.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 		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 @@
 	/* 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);
--- a/usr/src/uts/common/sys/exec.h	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/sys/exec.h	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 	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;
 
 /*
--- a/usr/src/uts/common/sys/fs/ufs_acl.h	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/sys/fs/ufs_acl.h	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 #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
--- a/usr/src/uts/common/sys/klpd.h	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/sys/klpd.h	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 
 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 @@
 #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
--- a/usr/src/uts/common/sys/policy.h	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/sys/policy.h	Wed Apr 28 10:01:37 2010 +0200
@@ -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_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 @@
 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_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_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 *);
--- a/usr/src/uts/common/sys/priv.h	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/sys/priv.h	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 #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 @@
 #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
--- a/usr/src/uts/common/sys/zone.h	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/sys/zone.h	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 	 * 	zone_ntasks
 	 * 	zone_flags
 	 * 	zone_zsd
+	 *	zone_pfexecd
 	 */
 	kmutex_t	zone_lock;
 	/*
@@ -441,6 +441,8 @@
 	 */
 	struct mntelem	*zone_mntfs_db;
 	krwlock_t	zone_mntfs_db_lock;
+
+	struct klpd_reg		*zone_pfexecd;
 } zone_t;
 
 /*
--- a/usr/src/uts/common/syscall/auditsys.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/syscall/auditsys.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 {
 	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 @@
 	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 @@
 	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 @@
 	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:
--- a/usr/src/uts/common/syscall/ppriv.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/syscall/ppriv.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 	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 @@
 {
 	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 @@
 		    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));
 }
--- a/usr/src/uts/common/syscall/uid.c	Wed Apr 28 09:25:44 2010 +0200
+++ b/usr/src/uts/common/syscall/uid.c	Wed Apr 28 10:01:37 2010 +0200
@@ -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 @@
 		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 @@
 			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);