4963290 RFE: implement flexible zone administration that doesn't require uid=0
authorGlenn Faden <Glenn.Faden@Sun.COM>
Mon, 07 Jun 2010 14:07:27 -0700
changeset 12578 f9062c43c8bc
parent 12577 98b7657d1987
child 12579 611412d35eb8
4963290 RFE: implement flexible zone administration that doesn't require uid=0 PSARC/2010/132 Delegated Administration for Zones
usr/src/cmd/oamuser/user/funcs.c
usr/src/cmd/zlogin/Makefile
usr/src/cmd/zlogin/zlogin.c
usr/src/cmd/zoneadm/Makefile
usr/src/cmd/zoneadm/zoneadm.c
usr/src/cmd/zonecfg/zonecfg.c
usr/src/cmd/zonecfg/zonecfg.h
usr/src/cmd/zonecfg/zonecfg_grammar.y
usr/src/cmd/zonecfg/zonecfg_lex.l
usr/src/head/auth_list.h
usr/src/head/libzonecfg.h
usr/src/head/secdb.h
usr/src/lib/brand/ipkg/zone/config.xml
usr/src/lib/brand/labeled/zone/config.xml
usr/src/lib/brand/lx/zone/config.xml
usr/src/lib/brand/sn1/zone/config.xml
usr/src/lib/brand/solaris10/zone/config.xml
usr/src/lib/libbrand/common/libbrand.c
usr/src/lib/libbrand/common/libbrand.h
usr/src/lib/libbrand/common/mapfile-vers
usr/src/lib/libbrand/dtd/brand.dtd.1
usr/src/lib/libsecdb/auth_attr.txt
usr/src/lib/libsecdb/common/chkauthattr.c
usr/src/lib/libsecdb/exec_attr.txt
usr/src/lib/libsecdb/help/auths/Makefile
usr/src/lib/libsecdb/help/auths/ZoneCloneFrom.html
usr/src/lib/libsecdb/help/auths/ZoneHeader.html
usr/src/lib/libsecdb/help/auths/ZoneLogin.html
usr/src/lib/libsecdb/help/auths/ZoneManage.html
usr/src/lib/libsecdb/help/profiles/Makefile
usr/src/lib/libsecdb/help/profiles/RtZoneMngmnt.html
usr/src/lib/libsecdb/help/profiles/RtZoneSecurity.html
usr/src/lib/libsecdb/prof_attr.txt
usr/src/lib/libzonecfg/Makefile.com
usr/src/lib/libzonecfg/common/libzonecfg.c
usr/src/lib/libzonecfg/common/mapfile-vers
usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1
usr/src/pkg/manifests/SUNWcs.mf
usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf
--- a/usr/src/cmd/oamuser/user/funcs.c	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/cmd/oamuser/user/funcs.c	Mon Jun 07 14:07:27 2010 -0700
@@ -19,12 +19,9 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <strings.h>
@@ -231,6 +228,10 @@
 	int have_grant = 0;
 
 	tmp = strdup(auths);
+	if (tmp == NULL) {
+		errmsg(M_NOSPACE);
+		exit(EX_FAILURE);
+	}
 
 	authname = strtok(tmp, AUTH_SEP);
 	pw = getpwuid(getuid());
@@ -242,6 +243,14 @@
 		char *suffix;
 		char *authtoks;
 
+		/* Check if user has been granted this authorization */
+		if (!chkauthattr(authname, pw->pw_name))
+			return (authname);
+
+		/* Remove named object after slash */
+		if ((suffix = index(authname, KV_OBJECTCHAR)) != NULL)
+			*suffix = '\0';
+
 		/* Find the suffix */
 		if ((suffix = rindex(authname, '.')) == NULL)
 			return (authname);
@@ -258,11 +267,6 @@
 			free_authattr(result);
 		}
 
-		/* Check if user has been granted this authorization */
-		if (!chkauthattr(authname, pw->pw_name)) {
-			return (authname);
-		}
-
 		/* Check if user can delegate this authorization */
 		if (strcmp(suffix, "grant")) { /* Not a grant option */
 			authtoks = malloc(strlen(authname) + sizeof ("grant"));
@@ -281,6 +285,7 @@
 		}
 		authname = strtok(NULL, AUTH_SEP);
 	}
+	free(tmp);
 	return (NULL);
 }
 
@@ -299,6 +304,10 @@
 	char *tmp;
 
 	tmp = strdup(profs);
+	if (tmp == NULL) {
+		errmsg(M_NOSPACE);
+		exit(EX_FAILURE);
+	}
 
 	profname = strtok(tmp, PROF_SEP);
 	while (profname != NULL) {
@@ -310,6 +319,7 @@
 		free_profattr(result);
 		profname = strtok(NULL, PROF_SEP);
 	}
+	free(tmp);
 	return (NULL);
 }
 
@@ -330,6 +340,10 @@
 	char *tmp;
 
 	tmp = strdup(roles);
+	if (tmp == NULL) {
+		errmsg(M_NOSPACE);
+		exit(EX_FAILURE);
+	}
 
 	rolename = strtok(tmp, ROLE_SEP);
 	while (rolename != NULL) {
@@ -352,6 +366,7 @@
 		free_userattr(result);
 		rolename = strtok(NULL, ROLE_SEP);
 	}
+	free(tmp);
 	return (NULL);
 }
 
--- a/usr/src/cmd/zlogin/Makefile	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/cmd/zlogin/Makefile	Mon Jun 07 14:07:27 2010 -0700
@@ -19,8 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 PROG = zlogin
@@ -28,7 +27,7 @@
 include ../Makefile.cmd
 
 LINTFLAGS += -u
-LDLIBS += -lsocket -lzonecfg -lcontract -lbrand
+LDLIBS += -lsocket -lzonecfg -lcontract -lbrand -lsecdb
 CFLAGS += $(CCVERBOSE)
 FILEMODE = 0555
 
--- a/usr/src/cmd/zlogin/zlogin.c	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/cmd/zlogin/zlogin.c	Mon Jun 07 14:07:27 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * 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.
  */
 
 /*
@@ -85,6 +84,9 @@
 #include <libzonecfg.h>
 #include <libcontract.h>
 #include <libbrand.h>
+#include <auth_list.h>
+#include <auth_attr.h>
+#include <secdb.h>
 
 static int masterfd;
 static struct termios save_termios;
@@ -103,6 +105,13 @@
 static int pollerr = 0;
 
 static const char *pname;
+static char *username;
+
+/*
+ * When forced_login is true, the user is not prompted
+ * for an authentication password in the target zone.
+ */
+static boolean_t forced_login = B_FALSE;
 
 #if !defined(TEXT_DOMAIN)		/* should be defined by cc -D */
 #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it wasn't */
@@ -1022,9 +1031,16 @@
 
 	/* Get the login command for the target zone. */
 	bzero(result_buf, sizeof (result_buf));
-	if (brand_get_login_cmd(bh, login,
-	    result_buf, sizeof (result_buf)) != 0)
-		return (NULL);
+
+	if (forced_login) {
+		if (brand_get_forcedlogin_cmd(bh, login,
+		    result_buf, sizeof (result_buf)) != 0)
+			return (NULL);
+	} else {
+		if (brand_get_login_cmd(bh, login,
+		    result_buf, sizeof (result_buf)) != 0)
+			return (NULL);
+	}
 
 	/*
 	 * We got back a string that we'd like to execute.  But since
@@ -1114,6 +1130,10 @@
 				return (NULL);
 
 			new_argv[a++] = SUPATH;
+			if (strcmp(login, "root") != 0) {
+				new_argv[a++] = "-";
+				n++;
+			}
 			new_argv[a++] = (char *)login;
 		}
 		new_argv[a++] = "-c";
@@ -1637,6 +1657,15 @@
 		 */
 		(void) setpgid(getpid(), getpid());
 
+		/*
+		 * The child needs to run as root to
+		 * execute the su program.
+		 */
+		if (setuid(0) == -1) {
+			zperror(gettext("insufficient privilege"));
+			return (1);
+		}
+
 		(void) execve(new_args[0], new_args, new_env);
 		zperror(gettext("exec failure"));
 		_exit(1);
@@ -1667,6 +1696,29 @@
 	return (WEXITSTATUS(child_status));
 }
 
+static char *
+get_username()
+{
+	uid_t	uid;
+	struct passwd *nptr;
+
+	/*
+	 * Authorizations are checked to restrict access based on the
+	 * requested operation and zone name, It is assumed that the
+	 * program is running with all privileges, but that the real
+	 * user ID is that of the user or role on whose behalf we are
+	 * operating. So we start by getting the username that will be
+	 * used for subsequent authorization checks.
+	 */
+
+	uid = getuid();
+	if ((nptr = getpwuid(uid)) == NULL) {
+		zerror(gettext("could not get user name."));
+		_exit(1);
+	}
+	return (nptr->pw_name);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -1689,11 +1741,13 @@
 	char kernzone[ZONENAME_MAX];
 	brand_handle_t bh;
 	char user_cmd[MAXPATHLEN];
+	char authname[MAXAUTHS];
 
 	(void) setlocale(LC_ALL, "");
 	(void) textdomain(TEXT_DOMAIN);
 
 	(void) getpname(argv[0]);
+	username = get_username();
 
 	while ((arg = getopt(argc, argv, "ECR:Se:l:")) != EOF) {
 		switch (arg) {
@@ -1800,13 +1854,8 @@
 	 * In the console case, because we may need to startup zoneadmd.
 	 * In the non-console case in order to do zone_enter(2), zonept()
 	 * and other tasks.
-	 *
-	 * Future work: this solution is temporary.  Ultimately, we need to
-	 * move to a flexible system which allows the global admin to
-	 * designate that a particular user can zlogin (and probably zlogin
-	 * -C) to a particular zone.  This all-root business we have now is
-	 * quite sketchy.
 	 */
+
 	if ((privset = priv_allocset()) == NULL) {
 		zperror(gettext("priv_allocset failed"));
 		return (1);
@@ -1827,6 +1876,37 @@
 	priv_freeset(privset);
 
 	/*
+	 * Check if user is authorized for requested usage of the zone
+	 */
+
+	(void) snprintf(authname, MAXAUTHS, "%s%s%s",
+	    ZONE_MANAGE_AUTH, KV_OBJECT, zonename);
+	if (chkauthattr(authname, username) == 0) {
+		if (console) {
+			zerror(gettext("%s is not authorized for console "
+			    "access to  %s zone."),
+			    username, zonename);
+			return (1);
+		} else {
+			(void) snprintf(authname, MAXAUTHS, "%s%s%s",
+			    ZONE_LOGIN_AUTH, KV_OBJECT, zonename);
+			if (failsafe || !interactive) {
+				zerror(gettext("%s is not authorized for  "
+				    "failsafe or non-interactive login "
+				    "to  %s zone."), username, zonename);
+				return (1);
+			} else if (chkauthattr(authname, username) == 0) {
+				zerror(gettext("%s is not authorized "
+				    " to login to %s zone."),
+				    username, zonename);
+				return (1);
+			}
+		}
+	} else {
+		forced_login = B_TRUE;
+	}
+
+	/*
 	 * The console is a separate case from the rest of the code; handle
 	 * it first.
 	 */
@@ -2116,10 +2196,20 @@
 			if (setup_utmpx(slaveshortname) == -1)
 				return (1);
 
+		/*
+		 * The child needs to run as root to
+		 * execute the brand's login program.
+		 */
+		if (setuid(0) == -1) {
+			zperror(gettext("insufficient privilege"));
+			return (1);
+		}
+
 		(void) execve(new_args[0], new_args, new_env);
 		zperror(gettext("exec failure"));
 		return (1);
 	}
+
 	(void) ct_tmpl_clear(tmpl_fd);
 	(void) close(tmpl_fd);
 
--- a/usr/src/cmd/zoneadm/Makefile	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/cmd/zoneadm/Makefile	Mon Jun 07 14:07:27 2010 -0700
@@ -20,8 +20,7 @@
 #
 
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 PROG=		zoneadm
@@ -37,7 +36,7 @@
 POFILE=zoneadm_all.po
 POFILES= $(OBJS:%.o=%.po)
 
-LDLIBS += -lzonecfg -lsocket -lgen -lpool -lzfs -luuid -lnvpair -lbrand -ldladm
+LDLIBS += -lzonecfg -lsocket -lgen -lpool -lzfs -luuid -lnvpair -lbrand -ldladm -lsecdb
 
 .KEEP_STATE:
 
--- a/usr/src/cmd/zoneadm/zoneadm.c	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/cmd/zoneadm/zoneadm.c	Mon Jun 07 14:07:27 2010 -0700
@@ -79,10 +79,15 @@
 #include <sys/fsspriocntl.h>
 #include <libdladm.h>
 #include <libdllink.h>
+#include <pwd.h>
+#include <auth_list.h>
+#include <auth_attr.h>
+#include <secdb.h>
 
 #include "zoneadm.h"
 
 #define	MAXARGS	8
+#define	SOURCE_ZONE (CMD_MAX + 1)
 
 /* Reflects kernel zone entries */
 typedef struct zone_entry {
@@ -201,6 +206,7 @@
 static char *locale;
 char *target_zone;
 static char *target_uuid;
+char *username;
 
 char *
 cmd_to_str(int cmd_num)
@@ -1505,6 +1511,56 @@
 	return (ZONE_SUBPROC_FATAL);
 }
 
+static int
+auth_check(char *user, char *zone, int cmd_num)
+{
+	char authname[MAXAUTHS];
+
+	switch (cmd_num) {
+	case CMD_LIST:
+	case CMD_HELP:
+		return (Z_OK);
+	case SOURCE_ZONE:
+		(void) strlcpy(authname, ZONE_CLONEFROM_AUTH, MAXAUTHS);
+		break;
+	case CMD_BOOT:
+	case CMD_HALT:
+	case CMD_READY:
+	case CMD_REBOOT:
+	case CMD_SYSBOOT:
+	case CMD_VERIFY:
+	case CMD_INSTALL:
+	case CMD_UNINSTALL:
+	case CMD_MOUNT:
+	case CMD_UNMOUNT:
+	case CMD_CLONE:
+	case CMD_MOVE:
+	case CMD_DETACH:
+	case CMD_ATTACH:
+	case CMD_MARK:
+	case CMD_APPLY:
+	default:
+		(void) strlcpy(authname, ZONE_MANAGE_AUTH, MAXAUTHS);
+		break;
+	}
+	(void) strlcat(authname, KV_OBJECT, MAXAUTHS);
+	(void) strlcat(authname, zone, MAXAUTHS);
+	if (chkauthattr(authname, user) == 0) {
+		return (Z_ERR);
+	} else {
+		/*
+		 * Some subcommands, e.g. install, run subcommands,
+		 * e.g. sysidcfg, that require a real uid of root,
+		 *  so switch to root, here.
+		 */
+		if (setuid(0) == -1) {
+			zperror(gettext("insufficient privilege"), B_TRUE);
+			return (Z_ERR);
+		}
+		return (Z_OK);
+	}
+}
+
 /*
  * Various sanity checks; make sure:
  * 1. We're in the global zone.
@@ -1568,6 +1624,12 @@
 		return (Z_ERR);
 	}
 
+	if (auth_check(username, zone, cmd_num) == Z_ERR) {
+		zerror(gettext("User %s is not authorized to %s this zone."),
+		    username, cmd_to_str(cmd_num));
+		return (Z_ERR);
+	}
+
 	if (strcmp(zone, GLOBAL_ZONENAME) == 0) {
 		zerror(gettext("%s operation is invalid for the global zone."),
 		    cmd_to_str(cmd_num));
@@ -3594,6 +3656,13 @@
 			return (Z_ERR);
 		}
 
+		if (auth_check(username, source_zone, SOURCE_ZONE) == Z_ERR) {
+			zerror(gettext("%s operation is invalid because "
+			    "user is not authorized to read source zone."),
+			    cmd_to_str(CMD_CLONE));
+			return (Z_ERR);
+		}
+
 		zent = lookup_running_zone(source_zone);
 		if (zent != NULL) {
 			/* check whether the zone is ready or running */
@@ -5611,6 +5680,30 @@
 	return (execbasename);
 }
 
+static char *
+get_username()
+{
+	uid_t uid;
+	struct passwd *nptr;
+
+
+	/*
+	 * Authorizations are checked to restrict access based on the
+	 * requested operation and zone name, It is assumed that the
+	 * program is running with all privileges, but that the real
+	 * user ID is that of the user or role on whose behalf we are
+	 * operating. So we start by getting the username that will be
+	 * used for subsequent authorization checks.
+	 */
+
+	uid = getuid();
+	if ((nptr = getpwuid(uid)) == NULL) {
+		zerror(gettext("could not get user name."));
+		exit(Z_ERR);
+	}
+	return (nptr->pw_name);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -5626,11 +5719,13 @@
 	setbuf(stdout, NULL);
 	(void) sigset(SIGHUP, SIG_IGN);
 	execname = get_execbasename(argv[0]);
+	username = get_username();
 	target_zone = NULL;
 	if (chdir("/") != 0) {
 		zerror(gettext("could not change directory to /."));
 		exit(Z_ERR);
 	}
+
 	/*
 	 * Use the default system mask rather than anything that may have been
 	 * set by the caller.
--- a/usr/src/cmd/zonecfg/zonecfg.c	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/cmd/zonecfg/zonecfg.c	Mon Jun 07 14:07:27 2010 -0700
@@ -75,6 +75,7 @@
 #include <sys/systeminfo.h>
 #include <libdladm.h>
 #include <libinetutil.h>
+#include <pwd.h>
 
 #include <libzonecfg.h>
 #include "zonecfg.h"
@@ -181,6 +182,7 @@
 	"ip-type",
 	"capped-cpu",
 	"hostid",
+	"admin",
 	NULL
 };
 
@@ -223,6 +225,8 @@
 	"ip-type",
 	"defrouter",
 	"hostid",
+	"user",
+	"auths",
 	NULL
 };
 
@@ -271,6 +275,7 @@
 	"add dedicated-cpu",
 	"add capped-cpu",
 	"add capped-memory",
+	"add admin",
 	NULL
 };
 
@@ -301,6 +306,7 @@
 	"remove dedicated-cpu ",
 	"remove capped-cpu ",
 	"remove capped-memory ",
+	"remove admin ",
 	NULL
 };
 
@@ -315,6 +321,7 @@
 	"select dedicated-cpu",
 	"select capped-cpu",
 	"select capped-memory",
+	"select admin",
 	NULL
 };
 
@@ -365,6 +372,7 @@
 	"info max-sem-ids",
 	"info cpu-shares",
 	"info hostid",
+	"info admin",
 	NULL
 };
 
@@ -486,6 +494,17 @@
 	NULL
 };
 
+static const char *admin_res_scope_cmds[] = {
+	"cancel",
+	"end",
+	"exit",
+	"help",
+	"info",
+	"set user=",
+	"set auths=",
+	NULL
+};
+
 /* Global variables */
 
 /* set early in main(), never modified thereafter, used all over the place */
@@ -553,6 +572,7 @@
 static struct zone_dstab	old_dstab, in_progress_dstab;
 static struct zone_psettab	old_psettab, in_progress_psettab;
 static struct zone_mcaptab	old_mcaptab, in_progress_mcaptab;
+static struct zone_admintab	old_admintab, in_progress_admintab;
 
 static GetLine *gl;	/* The gl_get_line() resource object */
 
@@ -630,6 +650,8 @@
 		return (add_stuff(cpl, line, pcap_res_scope_cmds, word_end));
 	case RT_MCAP:
 		return (add_stuff(cpl, line, mcap_res_scope_cmds, word_end));
+	case RT_ADMIN:
+		return (add_stuff(cpl, line, admin_res_scope_cmds, word_end));
 	}
 	return (0);
 }
@@ -1092,6 +1114,20 @@
 			    pt_to_str(PT_LOCKED),
 			    gettext("<qualified unsigned decimal>"));
 			break;
+		case RT_ADMIN:
+			(void) fprintf(fp, gettext("The '%s' resource scope is "
+			    "used to delegate specific zone management\n"
+			    "rights to users and roles. These rights are "
+			    "only applicable to this zone.\n"),
+			    rt_to_str(resource_scope));
+			(void) fprintf(fp, gettext("Valid commands:\n"));
+			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
+			    pt_to_str(PT_USER),
+			    gettext("<single user or role name>"));
+			(void) fprintf(fp, "\t%s %s=%s\n", cmd_to_str(CMD_SET),
+			    pt_to_str(PT_AUTHS),
+			    gettext("<comma separated list>"));
+			break;
 		}
 		(void) fprintf(fp, gettext("And from any resource scope, you "
 		    "can:\n"));
@@ -1150,12 +1186,13 @@
 	}
 	if (flags & HELP_RESOURCES) {
 		(void) fprintf(fp, "<%s> := %s | %s | %s | %s | %s | %s |\n\t"
-		    "%s | %s | %s | %s\n\n",
+		    "%s | %s | %s | %s | %s\n\n",
 		    gettext("resource type"), rt_to_str(RT_FS),
 		    rt_to_str(RT_IPD), rt_to_str(RT_NET), rt_to_str(RT_DEVICE),
 		    rt_to_str(RT_RCTL), rt_to_str(RT_ATTR),
 		    rt_to_str(RT_DATASET), rt_to_str(RT_DCPU),
-		    rt_to_str(RT_PCAP), rt_to_str(RT_MCAP));
+		    rt_to_str(RT_PCAP), rt_to_str(RT_MCAP),
+		    rt_to_str(RT_ADMIN));
 	}
 	if (flags & HELP_PROPS) {
 		(void) fprintf(fp, gettext("For resource type ... there are "
@@ -1217,6 +1254,8 @@
 		(void) fprintf(fp, "\t%s\t%s, %s, %s\n", rt_to_str(RT_MCAP),
 		    pt_to_str(PT_PHYSICAL), pt_to_str(PT_SWAP),
 		    pt_to_str(PT_LOCKED));
+		(void) fprintf(fp, "\t%s\t\t%s, %s\n", rt_to_str(RT_ADMIN),
+		    pt_to_str(PT_USER), pt_to_str(PT_AUTHS));
 	}
 	if (need_to_close)
 		(void) pclose(fp);
@@ -1266,6 +1305,30 @@
 				    "  Unable to continue", zone, brandname);
 				exit(Z_ERR);
 			}
+			/*
+			 * If the user_attr file is newer than
+			 * the zone config file, the admins
+			 * may need to be updated since the
+			 * RBAC files are authoritative for
+			 * authorization checks.
+			 */
+			err = zonecfg_update_userauths(handle, zone);
+			if (err == Z_OK) {
+				zerr(gettext("The administrative rights "
+				    "were updated to match "
+				    "the current RBAC configuration.\n"
+				    "Use \"info admin\" and \"revert\" to "
+				    "compare with the previous settings."));
+				need_to_commit = B_TRUE;
+			} else if (err != Z_NO_ENTRY) {
+				zerr(gettext("failed to update "
+				    "admin  rights."));
+				exit(Z_ERR);
+			} else if (need_to_commit) {
+				zerr(gettext("admin rights were updated "
+				    "to match RBAC configuration."));
+			}
+
 		} else if (global_zone && err == Z_NO_ZONE && !got_handle &&
 		    !read_only_mode) {
 			/*
@@ -1635,6 +1698,7 @@
 	struct zone_psettab psettab;
 	struct zone_mcaptab mcaptab;
 	struct zone_rctlvaltab *valptr;
+	struct zone_admintab admintab;
 	int err, arg;
 	char zonepath[MAXPATHLEN], outfile[MAXPATHLEN], pool[MAXNAMELEN];
 	char bootargs[BOOTARGS_MAX];
@@ -1896,6 +1960,19 @@
 		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
 	}
 
+	if ((err = zonecfg_setadminent(handle)) != Z_OK) {
+		zone_perror(zone, err, B_FALSE);
+		goto done;
+	}
+	while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
+		(void) fprintf(of, "%s %s\n", cmd_to_str(CMD_ADD),
+		    rt_to_str(RT_ADMIN));
+		export_prop(of, PT_USER, admintab.zone_admin_user);
+		export_prop(of, PT_AUTHS, admintab.zone_admin_auths);
+		(void) fprintf(of, "%s\n", cmd_to_str(CMD_END));
+	}
+	(void) zonecfg_endadminent(handle);
+
 	/*
 	 * There is nothing to export for pcap since this resource is just
 	 * a container for an rctl alias.
@@ -2091,6 +2168,9 @@
 			    "to administer.  Please use caution."));
 		bzero(&in_progress_mcaptab, sizeof (in_progress_mcaptab));
 		return;
+	case RT_ADMIN:
+		bzero(&in_progress_admintab, sizeof (in_progress_admintab));
+		return;
 	default:
 		zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
 		long_usage(CMD_ADD, B_TRUE);
@@ -2413,7 +2493,7 @@
 		 * user if the zone is not configured.  In force mode, we don't
 		 * trust that evaluation, and hence skip it.  (We don't need the
 		 * handle to be loaded anyway, since zonecfg_destroy is done by
-		 * zonename).  However, we also have to take care to emulate the
+		 * zonename). However, we also have to take care to emulate the
 		 * messages spit out by initialize; see below.
 		 */
 		if (initialize(B_TRUE) != Z_OK)
@@ -2431,6 +2511,13 @@
 			return;
 	}
 
+	/*
+	 * This function removes the authorizations from user_attr
+	 * that correspond to those specified in the configuration
+	 */
+	if (initialize(B_TRUE) == Z_OK) {
+		(void) zonecfg_deauthorize_users(handle, zone);
+	}
 	if ((err = zonecfg_destroy(zone, force)) != Z_OK) {
 		if ((err == Z_BAD_ZONE_STATE) && !force) {
 			zerr(gettext("Zone %s not in %s state; %s not "
@@ -2742,6 +2829,45 @@
 	return (zonecfg_lookup_ds(handle, dstab));
 }
 
+static int
+fill_in_admintab(cmd_t *cmd, struct zone_admintab *admintab,
+    boolean_t fill_in_only)
+{
+	int err, i;
+	property_value_ptr_t pp;
+
+	if ((err = initialize(B_TRUE)) != Z_OK)
+		return (err);
+
+	bzero(admintab, sizeof (*admintab));
+	for (i = 0; i < cmd->cmd_prop_nv_pairs; i++) {
+		pp = cmd->cmd_property_ptr[i];
+		if (pp->pv_type != PROP_VAL_SIMPLE || pp->pv_simple == NULL) {
+			zerr(gettext("A simple value was expected here."));
+			saw_error = B_TRUE;
+			return (Z_INSUFFICIENT_SPEC);
+		}
+		switch (cmd->cmd_prop_name[i]) {
+		case PT_USER:
+			(void) strlcpy(admintab->zone_admin_user, pp->pv_simple,
+			    sizeof (admintab->zone_admin_user));
+			break;
+		case PT_AUTHS:
+			(void) strlcpy(admintab->zone_admin_auths,
+			    pp->pv_simple, sizeof (admintab->zone_admin_auths));
+			break;
+		default:
+			zone_perror(pt_to_str(cmd->cmd_prop_name[i]),
+			    Z_NO_PROPERTY_TYPE, B_TRUE);
+			return (Z_INSUFFICIENT_SPEC);
+		}
+	}
+	if (fill_in_only)
+		return (Z_OK);
+	err = zonecfg_lookup_admin(handle, admintab);
+	return (err);
+}
+
 static void
 remove_aliased_rctl(int type, char *name)
 {
@@ -3144,6 +3270,46 @@
 }
 
 static void
+remove_admin(cmd_t *cmd)
+{
+	int err;
+
+	/* traditional, qualified attr removal */
+	if (cmd->cmd_prop_nv_pairs > 0) {
+		struct zone_admintab admintab;
+
+		if ((err = fill_in_admintab(cmd, &admintab, B_FALSE)) != Z_OK) {
+			z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
+			    err, B_TRUE);
+			return;
+		}
+		if ((err = zonecfg_delete_admin(handle, &admintab,
+		    zone))
+		    != Z_OK)
+			z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
+			    err, B_TRUE);
+		else
+			need_to_commit = B_TRUE;
+		return;
+	} else {
+		/*
+		 * unqualified admin removal.
+		 * remove all admins but prompt if more
+		 * than one.
+		 */
+		if (!prompt_remove_resource(cmd, "admin"))
+			return;
+
+		if ((err = zonecfg_delete_admins(handle, zone))
+		    != Z_OK)
+			z_cmd_rt_perror(CMD_REMOVE, RT_ADMIN,
+			    err, B_TRUE);
+		else
+			need_to_commit = B_TRUE;
+	}
+}
+
+static void
 remove_resource(cmd_t *cmd)
 {
 	int type;
@@ -3207,6 +3373,9 @@
 	case RT_MCAP:
 		remove_mcap();
 		return;
+	case RT_ADMIN:
+		remove_admin(cmd);
+		return;
 	default:
 		zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
 		long_usage(CMD_REMOVE, B_TRUE);
@@ -3670,6 +3839,16 @@
 			bzero(&in_progress_mcaptab,
 			    sizeof (in_progress_mcaptab));
 		return;
+	case RT_ADMIN:
+		if ((err = fill_in_admintab(cmd, &old_admintab, B_FALSE))
+		    != Z_OK) {
+			z_cmd_rt_perror(CMD_SELECT, RT_ADMIN, err,
+			    B_TRUE);
+			global_scope = B_TRUE;
+		}
+		bcopy(&old_admintab, &in_progress_admintab,
+		    sizeof (struct zone_admintab));
+		return;
 	default:
 		zone_perror(rt_to_str(type), Z_NO_RESOURCE_TYPE, B_TRUE);
 		long_usage(CMD_SELECT, B_TRUE);
@@ -4535,8 +4714,26 @@
 			usage(B_FALSE, HELP_PROPS);
 			return;
 		}
-
-		return;
+		return;
+	case RT_ADMIN:
+		switch (prop_type) {
+		case PT_USER:
+			(void) strlcpy(in_progress_admintab.zone_admin_user,
+			    prop_id,
+			    sizeof (in_progress_admintab.zone_admin_user));
+			return;
+		case PT_AUTHS:
+			(void) strlcpy(in_progress_admintab.zone_admin_auths,
+			    prop_id,
+			    sizeof (in_progress_admintab.zone_admin_auths));
+			return;
+		default:
+			zone_perror(pt_to_str(prop_type), Z_NO_PROPERTY_TYPE,
+			    B_TRUE);
+			long_usage(CMD_SET, B_TRUE);
+			usage(B_FALSE, HELP_PROPS);
+			return;
+		}
 	default:
 		zone_perror(rt_to_str(res_type), Z_NO_RESOURCE_TYPE, B_TRUE);
 		long_usage(CMD_SET, B_TRUE);
@@ -5160,6 +5357,48 @@
 		output_mcap(fp, &lookup, res2, swap_limit, res3, locked_limit);
 }
 
+static void
+output_auth(FILE *fp, struct zone_admintab *admintab)
+{
+	(void) fprintf(fp, "%s:\n", rt_to_str(RT_ADMIN));
+	output_prop(fp, PT_USER, admintab->zone_admin_user, B_TRUE);
+	output_prop(fp, PT_AUTHS, admintab->zone_admin_auths, B_TRUE);
+}
+
+static void
+info_auth(zone_dochandle_t handle, FILE *fp, cmd_t *cmd)
+{
+	struct zone_admintab lookup, user;
+	boolean_t output = B_FALSE;
+	int err;
+
+	if ((err = zonecfg_setadminent(handle)) != Z_OK) {
+		zone_perror(zone, err, B_TRUE);
+		return;
+	}
+	while (zonecfg_getadminent(handle, &lookup) == Z_OK) {
+		if (cmd->cmd_prop_nv_pairs == 0) {
+			output_auth(fp, &lookup);
+			continue;
+		}
+		if (fill_in_admintab(cmd, &user, B_TRUE) != Z_OK)
+			continue;
+		if (strlen(user.zone_admin_user) > 0 &&
+		    strcmp(user.zone_admin_user, lookup.zone_admin_user) != 0)
+			continue;	/* no match */
+		output_auth(fp, &lookup);
+		output = B_TRUE;
+	}
+	(void) zonecfg_endadminent(handle);
+	/*
+	 * If a property n/v pair was specified, warn the user if there was
+	 * nothing to output.
+	 */
+	if (!output && cmd->cmd_prop_nv_pairs > 0)
+		(void) printf(gettext("No such %s resource.\n"),
+		    rt_to_str(RT_ADMIN));
+}
+
 void
 info_func(cmd_t *cmd)
 {
@@ -5232,6 +5471,9 @@
 			output_mcap(fp, &in_progress_mcaptab, res1, swap_limit,
 			    res2, locked_limit);
 			break;
+		case RT_ADMIN:
+			output_auth(fp, &in_progress_admintab);
+			break;
 		}
 		goto cleanup;
 	}
@@ -5284,6 +5526,7 @@
 		if (!global_zone) {
 			info_attr(handle, fp, cmd);
 			info_ds(handle, fp, cmd);
+			info_auth(handle, fp, cmd);
 		}
 		info_rctl(handle, fp, cmd);
 		break;
@@ -5365,6 +5608,9 @@
 	case RT_HOSTID:
 		info_hostid(handle, fp);
 		break;
+	case RT_ADMIN:
+		info_auth(handle, fp, cmd);
+		break;
 	default:
 		zone_perror(rt_to_str(cmd->cmd_res_type), Z_NO_RESOURCE_TYPE,
 		    B_TRUE);
@@ -5499,6 +5745,7 @@
 	struct zone_rctltab rctltab;
 	struct zone_dstab dstab;
 	struct zone_psettab psettab;
+	struct zone_admintab admintab;
 	char zonepath[MAXPATHLEN];
 	char sched[MAXNAMELEN];
 	char brand[MAXNAMELEN];
@@ -5737,6 +5984,29 @@
 	}
 	(void) zonecfg_enddsent(handle);
 
+	if ((err = zonecfg_setadminent(handle)) != Z_OK) {
+		zone_perror(zone, err, B_TRUE);
+		return;
+	}
+	while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
+		check_reqd_prop(admintab.zone_admin_user, RT_ADMIN,
+		    PT_USER, &ret_val);
+		check_reqd_prop(admintab.zone_admin_auths, RT_ADMIN,
+		    PT_AUTHS, &ret_val);
+		if ((ret_val == Z_OK) && (getpwnam(admintab.zone_admin_user)
+		    == NULL)) {
+			zerr(gettext("%s %s is not a valid username"),
+			    pt_to_str(PT_USER),
+			    admintab.zone_admin_user);
+			ret_val = Z_BAD_PROPERTY;
+		}
+		if ((ret_val == Z_OK) && (!zonecfg_valid_auths(
+		    admintab.zone_admin_auths, zone))) {
+			ret_val = Z_BAD_PROPERTY;
+		}
+	}
+	(void) zonecfg_endadminent(handle);
+
 	if (!global_scope) {
 		zerr(gettext("resource specification incomplete"));
 		saw_error = B_TRUE;
@@ -5895,6 +6165,7 @@
 	struct zone_rctltab tmp_rctltab;
 	struct zone_attrtab tmp_attrtab;
 	struct zone_dstab tmp_dstab;
+	struct zone_admintab tmp_admintab;
 	int err, arg, res1, res2, res3;
 	uint64_t swap_limit;
 	uint64_t locked_limit;
@@ -6289,6 +6560,58 @@
 			(void) zonecfg_delete_mcap(handle);
 		}
 		break;
+	case RT_ADMIN:
+		/* First make sure everything was filled in. */
+		if (end_check_reqd(in_progress_admintab.zone_admin_user,
+		    PT_USER, &validation_failed) == Z_OK) {
+			if (getpwnam(in_progress_admintab.zone_admin_user)
+			    == NULL) {
+				zerr(gettext("%s %s is not a valid username"),
+				    pt_to_str(PT_USER),
+				    in_progress_admintab.zone_admin_user);
+				validation_failed = B_TRUE;
+			}
+		}
+
+		if (end_check_reqd(in_progress_admintab.zone_admin_auths,
+		    PT_AUTHS, &validation_failed) == Z_OK) {
+			if (!zonecfg_valid_auths(
+			    in_progress_admintab.zone_admin_auths,
+			    zone)) {
+				validation_failed = B_TRUE;
+			}
+		}
+
+		if (validation_failed) {
+			saw_error = B_TRUE;
+			return;
+		}
+
+		if (end_op == CMD_ADD) {
+			/* Make sure there isn't already one like this. */
+			bzero(&tmp_admintab, sizeof (tmp_admintab));
+			(void) strlcpy(tmp_admintab.zone_admin_user,
+			    in_progress_admintab.zone_admin_user,
+			    sizeof (tmp_admintab.zone_admin_user));
+			err = zonecfg_lookup_admin(
+			    handle, &tmp_admintab);
+			if (err == Z_OK) {
+				zerr(gettext("A %s resource "
+				    "with the %s '%s' already exists."),
+				    rt_to_str(RT_ADMIN),
+				    pt_to_str(PT_USER),
+				    in_progress_admintab.zone_admin_user);
+				saw_error = B_TRUE;
+				return;
+			}
+			err = zonecfg_add_admin(handle,
+			    &in_progress_admintab, zone);
+		} else {
+			err = zonecfg_modify_admin(handle,
+			    &old_admintab, &in_progress_admintab,
+			    zone);
+		}
+		break;
 	default:
 		zone_perror(rt_to_str(resource_scope), Z_NO_RESOURCE_TYPE,
 		    B_TRUE);
@@ -6416,6 +6739,12 @@
 	}
 
 	/*
+	 * Reset any pending admins that were
+	 * removed from the previous zone
+	 */
+	zonecfg_remove_userauths(handle, "", zone, B_FALSE);
+
+	/*
 	 * Time for a new handle: finish the old one off first
 	 * then get a new one properly to avoid leaks.
 	 */
@@ -6424,6 +6753,7 @@
 		zone_perror(execname, Z_NOMEM, B_TRUE);
 		exit(Z_ERR);
 	}
+
 	if ((err = zonecfg_get_handle(revert_zone, handle)) != Z_OK) {
 		saw_error = B_TRUE;
 		got_handle = B_FALSE;
--- a/usr/src/cmd/zonecfg/zonecfg.h	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/cmd/zonecfg/zonecfg.h	Mon Jun 07 14:07:27 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef _ZONECFG_H
@@ -89,9 +88,10 @@
 #define	RT_IPTYPE	24	/* really a property, but for info ... */
 #define	RT_PCAP		25
 #define	RT_HOSTID	26	/* really a property, but for info ... */
+#define	RT_ADMIN	27
 
 #define	RT_MIN		RT_UNKNOWN
-#define	RT_MAX		RT_HOSTID
+#define	RT_MAX		RT_ADMIN
 
 /* property types: increment PT_MAX when expanding this list */
 #define	PT_UNKNOWN	0
@@ -131,9 +131,11 @@
 #define	PT_IPTYPE	34
 #define	PT_DEFROUTER	35
 #define	PT_HOSTID	36
+#define	PT_USER		37
+#define	PT_AUTHS	38
 
 #define	PT_MIN		PT_UNKNOWN
-#define	PT_MAX		PT_HOSTID
+#define	PT_MAX		PT_AUTHS
 
 #define	MAX_EQ_PROP_PAIRS	3
 
--- a/usr/src/cmd/zonecfg/zonecfg_grammar.y	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/cmd/zonecfg/zonecfg_grammar.y	Mon Jun 07 14:07:27 2010 -0700
@@ -21,8 +21,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <stdio.h>
@@ -128,15 +127,16 @@
 %token NAME MATCH PRIV LIMIT ACTION VALUE EQUAL OPEN_SQ_BRACKET CLOSE_SQ_BRACKET
 %token OPEN_PAREN CLOSE_PAREN COMMA DATASET LIMITPRIV BOOTARGS BRAND PSET PCAP
 %token MCAP NCPUS IMPORTANCE SHARES MAXLWPS MAXSHMMEM MAXSHMIDS MAXMSGIDS
-%token MAXSEMIDS LOCKED SWAP SCHED CLEAR DEFROUTER
+%token MAXSEMIDS LOCKED SWAP SCHED CLEAR DEFROUTER ADMIN USER AUTHS
 
 %type <strval> TOKEN EQUAL OPEN_SQ_BRACKET CLOSE_SQ_BRACKET
     property_value OPEN_PAREN CLOSE_PAREN COMMA simple_prop_val
 %type <complex> complex_piece complex_prop_val
 %type <ival> resource_type NET FS IPD DEVICE RCTL ATTR DATASET PSET PCAP MCAP
+    ADMIN
 %type <ival> property_name SPECIAL RAW DIR OPTIONS TYPE ADDRESS PHYSICAL NAME
     MATCH ZONENAME ZONEPATH AUTOBOOT POOL LIMITPRIV BOOTARGS VALUE PRIV LIMIT
-    ACTION BRAND SCHED IPTYPE DEFROUTER HOSTID
+    ACTION BRAND SCHED IPTYPE DEFROUTER HOSTID USER AUTHS
 %type <cmd> command
 %type <cmd> add_command ADD
 %type <cmd> cancel_command CANCEL
@@ -924,6 +924,7 @@
 	| PSET		{ $$ = RT_DCPU; }
 	| PCAP		{ $$ = RT_PCAP; }
 	| MCAP		{ $$ = RT_MCAP; }
+	| ADMIN		{ $$ = RT_ADMIN; }
 
 property_name: SPECIAL	{ $$ = PT_SPECIAL; }
 	| RAW		{ $$ = PT_RAW; }
@@ -959,6 +960,8 @@
 	| MAXSEMIDS	{ $$ = PT_MAXSEMIDS; }
 	| SCHED		{ $$ = PT_SCHED; }
 	| HOSTID	{ $$ = PT_HOSTID; }
+	| USER		{ $$ = PT_USER; }
+	| AUTHS 	{ $$ = PT_AUTHS; }
 
 /*
  * The grammar builds data structures from the bottom up.  Thus various
--- a/usr/src/cmd/zonecfg/zonecfg_lex.l	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/cmd/zonecfg/zonecfg_lex.l	Mon Jun 07 14:07:27 2010 -0700
@@ -21,8 +21,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <string.h>
@@ -38,8 +37,8 @@
 char *safe_strdup(char *s);
 %}
 
-%a 6000
-%p 4000
+%a 7000
+%p 5000
 %e 2000
 %n 1000
 
@@ -164,6 +163,8 @@
 
 <TSTATE>attr	{ return ATTR; }
 
+<TSTATE>admin	{ return ADMIN; }
+
 <TSTATE>zonename	{ return ZONENAME; }
 <CSTATE>zonename	{ return ZONENAME; }
 
@@ -274,6 +275,12 @@
 <TSTATE>hostid		{ return HOSTID; }
 <CSTATE>hostid		{ return HOSTID; }
 
+<TSTATE>user	{ return USER; }
+<CSTATE>user	{ return USER; }
+
+<TSTATE>auths	{ return AUTHS; }
+<CSTATE>auths	{ return AUTHS; }
+
 <TSTATE>=	{ return EQUAL; }
 <LSTATE>=	{ return EQUAL; }
 <CSTATE>=	{ return EQUAL; }
--- a/usr/src/head/auth_list.h	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/head/auth_list.h	Mon Jun 07 14:07:27 2010 -0700
@@ -18,9 +18,9 @@
  *
  * CDDL HEADER END
  */
+
 /*
- * 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.
  *
  * This is an internal header file. Not to be shipped.
  */
@@ -56,7 +56,16 @@
 #define	HP_MODIFY_AUTH		"solaris.hotplug.modify"
 
 /*
- * Authorizations used by Trusted Solaris.
+ * The following authorizations can be qualified by appending <zonename>
+ */
+#define	ZONE_CLONEFROM_AUTH	"solaris.zone.clonefrom"
+#define	ZONE_LOGIN_AUTH		"solaris.zone.login"
+#define	ZONE_MANAGE_AUTH	"solaris.zone.manage"
+
+#define	ZONE_AUTH_PREFIX	"solaris.zone."
+
+/*
+ * Authorizations used by Trusted Extensions.
  */
 #define	BYPASS_FILE_VIEW_AUTH	"solaris.label.win.noview"
 #define	DEVICE_CONFIG_AUTH	"solaris.device.config"
--- a/usr/src/head/libzonecfg.h	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/head/libzonecfg.h	Mon Jun 07 14:07:27 2010 -0700
@@ -20,8 +20,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.
  */
 
 #ifndef _LIBZONECFG_H
@@ -50,6 +49,8 @@
 #include <sys/uuid.h>
 #include <libuutil.h>
 #include <sys/mnttab.h>
+#include <limits.h>
+#include <utmpx.h>
 
 #define	ZONE_ID_UNDEFINED	-1
 
@@ -122,6 +123,10 @@
 #define	ZONE_CONFIG_ROOT	"/etc/zones"
 #define	ZONE_INDEX_FILE		ZONE_CONFIG_ROOT "/index"
 
+#define	MAXUSERNAME		(sizeof (((struct utmpx *)0)->ut_name))
+#define	MAXAUTHS		4096
+#define	ZONE_MGMT_PROF		"Zone Management"
+
 /* Owner, group, and mode (defined by packaging) for the config directory */
 #define	ZONE_CONFIG_UID		0		/* root */
 #define	ZONE_CONFIG_GID		3		/* sys */
@@ -244,6 +249,17 @@
 	char	*zone_devperm_acl;
 };
 
+struct zone_admintab {
+	char	zone_admin_user[MAXUSERNAME];
+	char	zone_admin_auths[MAXAUTHS];
+};
+
+typedef struct zone_userauths {
+	char			user[MAXUSERNAME];
+	char			zonename[ZONENAME_MAX];
+	struct zone_userauths	*next;
+} zone_userauths_t;
+
 typedef struct {
 	uu_avl_node_t	zpe_entry;
 	char		*zpe_name;
@@ -484,6 +500,9 @@
 extern	int	zonecfg_getdevperment(zone_dochandle_t,
     struct zone_devpermtab *);
 extern	int	zonecfg_enddevperment(zone_dochandle_t);
+extern	int	zonecfg_setadminent(zone_dochandle_t);
+extern	int	zonecfg_getadminent(zone_dochandle_t, struct zone_admintab *);
+extern	int	zonecfg_endadminent(zone_dochandle_t);
 
 /*
  * Privilege-related functions.
@@ -565,6 +584,22 @@
 extern int zonecfg_ping_zoneadmd(const char *);
 extern int zonecfg_call_zoneadmd(const char *, zone_cmd_arg_t *, char *,
     boolean_t);
+extern int zonecfg_insert_userauths(zone_dochandle_t, char *, char *);
+extern int zonecfg_remove_userauths(zone_dochandle_t, char *, char *,
+    boolean_t);
+extern int zonecfg_add_admin(zone_dochandle_t, struct zone_admintab *,
+    char *);
+extern int zonecfg_delete_admin(zone_dochandle_t,
+    struct zone_admintab *, char *);
+extern int zonecfg_modify_admin(zone_dochandle_t, struct zone_admintab *,
+    struct zone_admintab *, char *);
+extern int zonecfg_delete_admins(zone_dochandle_t, char *);
+extern int zonecfg_lookup_admin(zone_dochandle_t, struct zone_admintab *);
+extern int zonecfg_authorize_users(zone_dochandle_t, char *);
+extern int zonecfg_update_userauths(zone_dochandle_t, char *);
+extern int zonecfg_deauthorize_user(zone_dochandle_t, char *, char *);
+extern int zonecfg_deauthorize_users(zone_dochandle_t, char *);
+extern boolean_t zonecfg_valid_auths(const char *, const char *);
 
 #ifdef __cplusplus
 }
--- a/usr/src/head/secdb.h	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/head/secdb.h	Mon Jun 07 14:07:27 2010 -0700
@@ -50,6 +50,8 @@
 #define	KV_ACTION_WILDCARD	"*;*;*;*;*"
 #define	KV_SEPCHAR		','
 #define	KV_SEPSTR		","
+#define	KV_OBJECTCHAR		'/'
+#define	KV_OBJECT		"/"
 
 #define	KV_FLAG_NONE		0x0000
 #define	KV_FLAG_REQUIRED	0x0001
--- a/usr/src/lib/brand/ipkg/zone/config.xml	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/lib/brand/ipkg/zone/config.xml	Mon Jun 07 14:07:27 2010 -0700
@@ -20,8 +20,7 @@
 
  CDDL HEADER END
 
- 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.
 
  DO NOT EDIT THIS FILE.
 -->
@@ -33,7 +32,8 @@
 	<modname></modname>
 
 	<initname>/sbin/init</initname>
-	<login_cmd>/usr/bin/login -z %Z -f %u</login_cmd>
+	<login_cmd>/usr/bin/login -z %Z %u</login_cmd>
+	<forcedlogin_cmd>/usr/bin/login -z %Z -f %u</forcedlogin_cmd>
 	<user_cmd>/usr/bin/getent passwd %u</user_cmd>
 
 	<!-- We may not be able to do the create in pkg(1) proper. -->
--- a/usr/src/lib/brand/labeled/zone/config.xml	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/lib/brand/labeled/zone/config.xml	Mon Jun 07 14:07:27 2010 -0700
@@ -20,8 +20,7 @@
 
  CDDL HEADER END
 
- 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.
 
  DO NOT EDIT THIS FILE.
 -->
@@ -33,7 +32,9 @@
 	<modname></modname>
 
 	<initname>/sbin/init</initname>
-	<login_cmd>/usr/bin/login -z %Z -f %u</login_cmd>
+	<login_cmd>/usr/bin/login -z %Z %u</login_cmd>
+	<forcedlogin_cmd>/usr/bin/login -z %Z -f %u</forcedlogin_cmd>
+
 	<user_cmd>/usr/bin/getent passwd %u</user_cmd>
 
 	<!-- We may not be able to do the create in pkg(1) proper. -->
--- a/usr/src/lib/brand/lx/zone/config.xml	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/lib/brand/lx/zone/config.xml	Mon Jun 07 14:07:27 2010 -0700
@@ -20,10 +20,7 @@
 
  CDDL HEADER END
 
- Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- Use is subject to license terms.
-
- ident	"%Z%%M%	%I%	%E% SMI"
+ Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 
  DO NOT EDIT THIS FILE.
 -->
@@ -35,7 +32,8 @@
 	<modname>lx_brand</modname>
 
 	<initname>/sbin/init</initname>
-	<login_cmd>/bin/login -h zone:%Z -f %u</login_cmd>
+	<login_cmd>/bin/login -h zone:%Z %u</login_cmd>
+	<forcedlogin_cmd>/bin/login -h zone:%Z -f %u</forcedlogin_cmd>
 	<user_cmd>/usr/bin/getent passwd %u</user_cmd>
 
 	<install>/usr/lib/brand/lx/lx_install %z %R</install>
--- a/usr/src/lib/brand/sn1/zone/config.xml	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/lib/brand/sn1/zone/config.xml	Mon Jun 07 14:07:27 2010 -0700
@@ -20,8 +20,7 @@
 
  CDDL HEADER END
 
- 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.
 
  DO NOT EDIT THIS FILE.
 -->
@@ -33,7 +32,9 @@
 	<modname>sn1_brand</modname>
 
 	<initname>/sbin/init</initname>
-	<login_cmd>/usr/bin/login -z %Z -f %u</login_cmd>
+	<login_cmd>/usr/bin/login -z %Z %u</login_cmd>
+	<forcedlogin_cmd>/usr/bin/login -z %Z -f %u</forcedlogin_cmd>
+
 	<user_cmd>/usr/bin/getent passwd %u</user_cmd>
 
 	<install>/usr/lib/brand/ipkg/pkgcreatezone -z %z -R %R</install>
--- a/usr/src/lib/brand/solaris10/zone/config.xml	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/lib/brand/solaris10/zone/config.xml	Mon Jun 07 14:07:27 2010 -0700
@@ -20,8 +20,7 @@
 
  CDDL HEADER END
 
- 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.
 
  DO NOT EDIT THIS FILE.
 -->
@@ -32,7 +31,8 @@
 <brand name="solaris10">
 	<modname>s10_brand</modname>
 	<initname>/sbin/init</initname>
-	<login_cmd>/usr/bin/login -z %Z -f %u</login_cmd>
+	<login_cmd>/usr/bin/login -z %Z %u</login_cmd>
+	<forcedlogin_cmd>/usr/bin/login -z %Z -f %u</forcedlogin_cmd>
 	<user_cmd>/usr/bin/getent passwd %u</user_cmd>
 
 	<install>/usr/lib/brand/solaris10/image_install %z %R</install>
--- a/usr/src/lib/libbrand/common/libbrand.c	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/lib/libbrand/common/libbrand.c	Mon Jun 07 14:07:27 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <assert.h>
@@ -58,6 +57,7 @@
 #define	DTD_ELEM_INSTALL	((const xmlChar *) "install")
 #define	DTD_ELEM_INSTALLOPTS	((const xmlChar *) "installopts")
 #define	DTD_ELEM_LOGIN_CMD	((const xmlChar *) "login_cmd")
+#define	DTD_ELEM_FORCELOGIN_CMD	((const xmlChar *) "forcedlogin_cmd")
 #define	DTD_ELEM_MODNAME	((const xmlChar *) "modname")
 #define	DTD_ELEM_MOUNT		((const xmlChar *) "mount")
 #define	DTD_ELEM_POSTATTACH	((const xmlChar *) "postattach")
@@ -520,6 +520,16 @@
 }
 
 int
+brand_get_forcedlogin_cmd(brand_handle_t bh, const char *username,
+    char *buf, size_t len)
+{
+	struct brand_handle *bhp = (struct brand_handle *)bh;
+	const char *curr_zone = get_curr_zone();
+	return (brand_get_value(bhp, NULL, NULL, username, curr_zone,
+	    buf, len, DTD_ELEM_FORCELOGIN_CMD, B_TRUE, B_FALSE));
+}
+
+int
 brand_get_user_cmd(brand_handle_t bh, const char *username,
     char *buf, size_t len)
 {
--- a/usr/src/lib/libbrand/common/libbrand.h	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/lib/libbrand/common/libbrand.h	Mon Jun 07 14:07:27 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef	_LIBBRAND_H
@@ -62,6 +61,8 @@
     char *, size_t);
 extern int brand_get_installopts(brand_handle_t, char *, size_t);
 extern int brand_get_login_cmd(brand_handle_t, const char *, char *, size_t);
+extern int brand_get_forcedlogin_cmd(brand_handle_t, const char *,
+    char *, size_t);
 extern int brand_get_modname(brand_handle_t, char *, size_t);
 extern int brand_get_postattach(brand_handle_t, const char *, const char *,
     char *, size_t);
--- a/usr/src/lib/libbrand/common/mapfile-vers	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/lib/libbrand/common/mapfile-vers	Mon Jun 07 14:07:27 2010 -0700
@@ -19,8 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
+# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
 #
@@ -47,6 +46,7 @@
 	brand_get_brandname;
 	brand_get_clone;
 	brand_get_detach;
+	brand_get_forcedlogin_cmd;
 	brand_get_halt;
 	brand_get_initname;
 	brand_get_install;
--- a/usr/src/lib/libbrand/dtd/brand.dtd.1	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/lib/libbrand/dtd/brand.dtd.1	Mon Jun 07 14:07:27 2010 -0700
@@ -20,8 +20,7 @@
 
  CDDL HEADER END
 
- Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- Use is subject to license terms.
+ Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 
  DO NOT EDIT THIS FILE.
 -->
@@ -205,6 +204,22 @@
 <!ATTLIST login_cmd>
 
 <!--
+  forcedlogin_cmd
+
+    Path to the initial login binary that should be executed when
+    attempting to zlogin into a branded zone without authentication.
+
+    The following replacements are performed:
+
+      %Z	Name of the current zone
+      %u	User login name
+
+    It has no attributes.
+-->
+<!ELEMENT forcedlogin_cmd	(#PCDATA) >
+<!ATTLIST forcedlogin_cmd>
+
+<!--
   user_cmd
 
     Path to the binary that will translate a user name to a passwd(4) entry.
@@ -588,7 +603,8 @@
 		directory in which the configuration file is stored.
 -->
 
-<!ELEMENT brand		(modname?, initname, login_cmd, user_cmd, install,
+<!ELEMENT brand		(modname?, initname, login_cmd, forcedlogin_cmd,
+			user_cmd, install,
 			installopts?, boot?, sysboot?, halt?, verify_cfg?,
 			verify_adm?, postattach?, postclone?, postinstall?,
 			predetach?, attach?, detach?, clone?,
--- a/usr/src/lib/libsecdb/auth_attr.txt	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/lib/libsecdb/auth_attr.txt	Mon Jun 07 14:07:27 2010 -0700
@@ -202,3 +202,7 @@
 solaris.smf.value.isns:::Modify iSNS Service Property Values::help=isnsValue.html
 solaris.isnsmgr.write:::Modify iSNS configuration::help=AuthISNSmgrWrite.html
 solaris.smf.manage.wusb:::Manage Wireless USB Service::help=SmfWusbStates.html
+solaris.zone.:::Zone Management::help=ZoneHeader.html
+solaris.zone.clonefrom:::Clone another Zone::help=ZoneCloneFrom.html
+solaris.zone.login:::Zone Login::help=ZoneLogin.html
+solaris.zone.manage:::Zone Deployment::help=ZoneManage.html
--- a/usr/src/lib/libsecdb/common/chkauthattr.c	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/lib/libsecdb/common/chkauthattr.c	Mon Jun 07 14:07:27 2010 -0700
@@ -82,6 +82,8 @@
 /*
  * Enumerate profiles from listed profiles.
  */
+static int _auth_match_noun(const char *, const char *, size_t, const char *);
+
 int
 _enum_common_p(const char *cprofiles,
     int (*cb)(const char *, kva_t *, void *, void *),
@@ -288,45 +290,90 @@
 }
 
 int
-_auth_match(const char *pattern, const char *auth)
+_auth_match_noun(const char *pattern, const char *auth,
+    size_t auth_len, const char *auth_noun)
 {
-	size_t len;
+	size_t pattern_len;
 	char *grant;
+	char *pattern_noun;
+	char *slash;
 
-	len = strlen(pattern);
+	pattern_len = strlen(pattern);
+	/*
+	 * If the specified authorization has a trailing object
+	 * and the current authorization we're checking also has
+	 * a trailing object, the object names must match.
+	 *
+	 * If there is no object name failure, then we must
+	 * check for an exact match of the two authorizations
+	 */
+	if (auth_noun != NULL) {
+		if ((slash = strchr(pattern, KV_OBJECTCHAR)) != NULL) {
+			pattern_noun = slash + 1;
+			pattern_len -= strlen(slash);
+			if (strcmp(pattern_noun, auth_noun) != 0)
+				return (0);
+		} else if ((auth_len == pattern_len) &&
+		    (strncmp(pattern, auth, pattern_len) == 0)) {
+			return (1);
+		}
+	}
 
 	/*
 	 * If the wildcard is not in the last position in the string, don't
 	 * match against it.
 	 */
-	if (pattern[len-1] != KV_WILDCHAR)
+	if (pattern[pattern_len-1] != KV_WILDCHAR)
 		return (0);
 
 	/*
 	 * If the strings are identical up to the wildcard and auth does not
 	 * end in "grant", then we have a match.
 	 */
-	if (strncmp(pattern, auth, len-1) == 0) {
+	if (strncmp(pattern, auth, pattern_len - 1) == 0) {
 		grant = strrchr(auth, '.');
 		if (grant != NULL) {
 			if (strncmp(grant + 1, "grant", 5) != NULL)
 				return (1);
 		}
 	}
+	return (0);
+}
 
-	return (0);
+int
+_auth_match(const char *pattern, const char *auth)
+{
+	return (_auth_match_noun(pattern, auth, strlen(auth), NULL));
 }
 
 static int
 _is_authorized(const char *auth, void *authname, void *res)
 {
 	int *resp = res;
+	char	*authname_noun;
+	char	*slash;
+	size_t	auth_len;
+	size_t	noun_len;
 
-	if (strcmp(authname, auth) == 0 ||
-	    (strchr(auth, KV_WILDCHAR) != NULL &&
-	    _auth_match(auth, authname))) {
+	auth_len = strlen(authname);
+	if ((slash = strchr(authname, KV_OBJECTCHAR)) != NULL) {
+		authname_noun = slash + 1;
+		noun_len = strlen(slash);
+		auth_len -= noun_len;
+	} else {
+		authname_noun = NULL;
+	}
+
+	if (strcmp(authname, auth) == 0) {
+		/* exact match, we're done */
 		*resp = 1;
 		return (1);
+	} else if (noun_len || strchr(auth, KV_WILDCHAR) != NULL) {
+		if (_auth_match_noun(auth, authname,
+		    auth_len, authname_noun)) {
+			*resp = 1;
+			return (1);
+		}
 	}
 
 	return (0);
--- a/usr/src/lib/libsecdb/exec_attr.txt	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/lib/libsecdb/exec_attr.txt	Mon Jun 07 14:07:27 2010 -0700
@@ -305,8 +305,8 @@
 ZFS File System Management:solaris:cmd:::/sbin/zfs:euid=0
 ZFS Storage Management:solaris:cmd:::/sbin/zpool:uid=0
 ZFS Storage Management:solaris:cmd:::/usr/lib/zfs/availdevs:uid=0
-Zone Management:solaris:cmd:::/usr/sbin/txzonemgr:uid=0
-Zone Management:solaris:cmd:::/usr/sbin/zonecfg:uid=0
-Zone Management:solaris:cmd:::/usr/sbin/zoneadm:uid=0
-Zone Management:solaris:cmd:::/usr/sbin/zlogin:uid=0
+Zone Security:solaris:cmd:::/usr/sbin/txzonemgr:uid=0
+Zone Security:solaris:cmd:::/usr/sbin/zonecfg:uid=0
+Zone Management:solaris:cmd:::/usr/sbin/zoneadm:euid=0
+Zone Management:solaris:cmd:::/usr/sbin/zlogin:euid=0
 acctadm:solaris:cmd:::/usr/sbin/acctadm:euid=0;egid=0;privs=sys_acct,file_dac_write
--- a/usr/src/lib/libsecdb/help/auths/Makefile	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/lib/libsecdb/help/auths/Makefile	Mon Jun 07 14:07:27 2010 -0700
@@ -167,7 +167,11 @@
 	SysCpuPowerMgmt.html \
 	SysSyseventRead.html \
 	SysSyseventWrite.html \
-	SmfManageZFSSnap.html
+	SmfManageZFSSnap.html \
+	ZoneCloneFrom.html \
+	ZoneHeader.html \
+	ZoneLogin.html \
+	ZoneManage.html
 
 HELPDIR=$(ROOT)/usr/lib/help
 AUTHDIR=$(HELPDIR)/auths
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsecdb/help/auths/ZoneCloneFrom.html	Mon Jun 07 14:07:27 2010 -0700
@@ -0,0 +1,33 @@
+<HTML>
+<!--
+    Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+    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
+
+-->
+<!--
+   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+   <META NAME="GENERATOR" CONTENT="Mozilla/4.02 [en] (X11; U; SunOS 5.6 sun4u) [Netscape]">
+-->
+<BODY>
+This authorization allows a user to make a clone from an existing zone. The name of a specific zone may optionally be appended to the authorization, preceded by a slash.
+<BR>&nbsp;
+</BODY>
+</HTML>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsecdb/help/auths/ZoneHeader.html	Mon Jun 07 14:07:27 2010 -0700
@@ -0,0 +1,32 @@
+<HTML>
+<!--
+    Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+    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
+-->
+<!--
+   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+   <META NAME="GENERATOR" CONTENT="Mozilla/4.02 [en] (X11; U; SunOS 5.6 sun4u) [Netscape]">
+-->
+<BODY>
+These authorizations specify the zones management operations for the user. The name of a specific zone may optionally be appended to the authorization, preceded by a slash.
+<BR>&nbsp;
+</BODY>
+</HTML>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsecdb/help/auths/ZoneLogin.html	Mon Jun 07 14:07:27 2010 -0700
@@ -0,0 +1,32 @@
+<HTML>
+<!--
+    Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+    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
+-->
+<!--
+   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+   <META NAME="GENERATOR" CONTENT="Mozilla/4.02 [en] (X11; U; SunOS 5.6 sun4u) [Netscape]">
+-->
+<BODY>
+This authorization allows a user to login to a zone if authentication is successful.  The name of a specific zone may optionally be appended to the authorization, preceded by a slash.
+<BR>&nbsp;
+</BODY>
+</HTML>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsecdb/help/auths/ZoneManage.html	Mon Jun 07 14:07:27 2010 -0700
@@ -0,0 +1,32 @@
+<HTML>
+<!--
+    Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+    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
+-->
+<!--
+   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+   <META NAME="GENERATOR" CONTENT="Mozilla/4.02 [en] (X11; U; SunOS 5.6 sun4u) [Netscape]">
+-->
+<BODY>
+This authorization allows a user to install, update, boot or halt a zone.  It also allows unauthenticated access to a running zone and its console. The name of a specific zone may optionally be appended to the authorization, preceded by a slash.
+<BR>&nbsp;
+</BODY>
+</HTML>
--- a/usr/src/lib/libsecdb/help/profiles/Makefile	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/lib/libsecdb/help/profiles/Makefile	Mon Jun 07 14:07:27 2010 -0700
@@ -86,6 +86,7 @@
 	RtZFSFileSysMngmnt.html \
 	RtZFSStorageMngmnt.html \
 	RtZoneMngmnt.html \
+	RtZoneSecurity.html \
 	RtInfoSec.html \
 	RtObjectLabelMngmnt.html \
 	RtOutsideAccred.html \
--- a/usr/src/lib/libsecdb/help/profiles/RtZoneMngmnt.html	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/lib/libsecdb/help/profiles/RtZoneMngmnt.html	Mon Jun 07 14:07:27 2010 -0700
@@ -3,9 +3,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,8 +19,7 @@
 
     CDDL HEADER END
 
--- Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
--- Use is subject to license terms.
+    Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
 -->
 <HEAD>
 	<TITLE> </TITLE>
@@ -29,7 +27,6 @@
 	
 </HEAD>
 <BODY>
-<!-- ident	"%Z%%M%	%I%	%E% SMI" -->
 
 When Zones Management is in the Rights Included column, it grants the right to
 use commands needed to administer Solaris Zones.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsecdb/help/profiles/RtZoneSecurity.html	Mon Jun 07 14:07:27 2010 -0700
@@ -0,0 +1,37 @@
+<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>
+
+When Zones Security is in the Rights Included column, it grants the right to
+use commands needed to configure Solaris Zones and delegate authorizations.
+<p>
+If Zones Security is grayed, then you are not entitled to Add or Remove this right.
+<p>
+</BODY>
+</HTML>
--- a/usr/src/lib/libsecdb/prof_attr.txt	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/lib/libsecdb/prof_attr.txt	Mon Jun 07 14:07:27 2010 -0700
@@ -95,6 +95,7 @@
 STMF Management:::Start/Stop STMF service:auths=solaris.smf.manage.stmf
 ZFS File System Management:::Create and Manage ZFS File Systems:help=RtZFSFileSysMngmnt.html
 ZFS Storage Management:::Create and Manage ZFS Storage Pools:help=RtZFSStorageMngmnt.html
+Zone Security:::Zones Virtual Application Environment Security:auths=solaris.zone.*,solaris.zone.grant;help=RtZoneSecurity.html
 Zone Management:::Zones Virtual Application Environment Administration:help=RtZoneMngmnt.html
 IP Filter Management:::IP Filter Administration:help=RtIPFilterMngmnt.html
 Project Management:::Add/Modify/Remove projects:help=RtProjManagement.html
--- a/usr/src/lib/libzonecfg/Makefile.com	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/lib/libzonecfg/Makefile.com	Mon Jun 07 14:07:27 2010 -0700
@@ -19,8 +19,7 @@
 # CDDL HEADER END
 #
 #
-# 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.
 #
 
 LIBRARY=	libzonecfg.a
@@ -31,7 +30,7 @@
 
 LIBS =		$(DYNLIB) $(LINTLIB)
 LDLIBS +=	-lc -lsocket -lnsl -luuid -lnvpair -lsysevent -lsec -lbrand \
-		-lpool -lscf -lproc -luutil -lbsm
+		-lpool -lscf -lproc -luutil -lbsm -lsecdb
 # DYNLIB libraries do not have lint libs and are not linted
 $(DYNLIB) :=	LDLIBS += -lxml2
 
--- a/usr/src/lib/libzonecfg/common/libzonecfg.c	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/lib/libzonecfg/common/libzonecfg.c	Mon Jun 07 14:07:27 2010 -0700
@@ -20,8 +20,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.
  */
 
 #include <libsysevent.h>
@@ -53,6 +52,11 @@
 #include <libuutil.h>
 #include <wait.h>
 #include <bsm/adt.h>
+#include <auth_attr.h>
+#include <auth_list.h>
+#include <secdb.h>
+#include <user_attr.h>
+#include <prof_attr.h>
 
 #include <arpa/inet.h>
 #include <netdb.h>
@@ -92,6 +96,7 @@
 #define	DTD_ELEM_PATCH		(const xmlChar *) "patch"
 #define	DTD_ELEM_OBSOLETES	(const xmlChar *) "obsoletes"
 #define	DTD_ELEM_DEV_PERM	(const xmlChar *) "dev-perm"
+#define	DTD_ELEM_ADMIN		(const xmlChar *) "admin"
 
 #define	DTD_ATTR_ACTION		(const xmlChar *) "action"
 #define	DTD_ATTR_ADDRESS	(const xmlChar *) "address"
@@ -125,6 +130,8 @@
 #define	DTD_ATTR_ACL		(const xmlChar *) "acl"
 #define	DTD_ATTR_BRAND		(const xmlChar *) "brand"
 #define	DTD_ATTR_HOSTID		(const xmlChar *) "hostid"
+#define	DTD_ATTR_USER		(const xmlChar *) "user"
+#define	DTD_ATTR_AUTHS		(const xmlChar *) "auths"
 
 #define	DTD_ENTITY_BOOLEAN	"boolean"
 #define	DTD_ENTITY_DEVPATH	"devpath"
@@ -189,6 +196,7 @@
 	boolean_t	zone_dh_newzone;
 	boolean_t	zone_dh_snapshot;
 	boolean_t	zone_dh_sw_inv;
+	zone_userauths_t	*zone_dh_userauths;
 	char		zone_dh_delete_name[ZONENAME_MAX];
 };
 
@@ -802,6 +810,27 @@
 	return (getrootattr(handle, DTD_ATTR_NAME, name, namesize));
 }
 
+static int
+insert_admins(zone_dochandle_t handle, char *zonename)
+{
+	int err;
+	struct zone_admintab admintab;
+
+	if ((err = zonecfg_setadminent(handle)) != Z_OK) {
+		return (err);
+	}
+	while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
+		err = zonecfg_insert_userauths(handle,
+		    admintab.zone_admin_user, zonename);
+		if (err != Z_OK) {
+			(void) zonecfg_endadminent(handle);
+			return (err);
+		}
+	}
+	(void) zonecfg_endadminent(handle);
+	return (Z_OK);
+}
+
 int
 zonecfg_set_name(zone_dochandle_t handle, char *name)
 {
@@ -883,7 +912,14 @@
 		return (err);
 	}
 
-	return (Z_OK);
+	/*
+	 * Record the old admins from the old zonename
+	 * so that they can be deleted when the operation is committed.
+	 */
+	if ((err = insert_admins(handle, curname)) != Z_OK)
+		return (err);
+	else
+		return (Z_OK);
 }
 
 int
@@ -1258,6 +1294,11 @@
 	addcomment(handle, "\n    DO NOT EDIT THIS "
 	    "FILE.  Use zonecfg(1M) instead.\n");
 
+	/*
+	 * Update user_attr first so that it will be older
+	 * than the config file.
+	 */
+	(void) zonecfg_authorize_users(handle, zname);
 	err = zonecfg_save_impl(handle, path);
 
 	stripcomments(handle);
@@ -2571,6 +2612,157 @@
 	return (Z_OK);
 }
 
+static int
+zonecfg_add_auth_core(zone_dochandle_t handle, struct zone_admintab *tabptr,
+    char *zonename)
+{
+	xmlNodePtr newnode, cur = handle->zone_dh_cur;
+	int err;
+
+	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ADMIN, NULL);
+	err = newprop(newnode, DTD_ATTR_USER, tabptr->zone_admin_user);
+	if (err != Z_OK)
+		return (err);
+	err = newprop(newnode, DTD_ATTR_AUTHS, tabptr->zone_admin_auths);
+	if (err != Z_OK)
+		return (err);
+	if ((err = zonecfg_remove_userauths(
+	    handle, tabptr->zone_admin_user, zonename, B_FALSE)) != Z_OK)
+		return (err);
+	return (Z_OK);
+}
+
+int
+zonecfg_add_admin(zone_dochandle_t handle, struct zone_admintab *tabptr,
+    char *zonename)
+{
+	int err;
+
+	if (tabptr == NULL)
+		return (Z_INVAL);
+
+	if ((err = operation_prep(handle)) != Z_OK)
+		return (err);
+
+	if ((err = zonecfg_add_auth_core(handle, tabptr,
+	    zonename)) != Z_OK)
+		return (err);
+
+	return (Z_OK);
+}
+static int
+zonecfg_delete_auth_core(zone_dochandle_t handle, struct zone_admintab *tabptr,
+    char *zonename)
+{
+	xmlNodePtr cur = handle->zone_dh_cur;
+	boolean_t auth_match;
+	int err;
+
+	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
+		if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
+			continue;
+		auth_match = match_prop(cur, DTD_ATTR_USER,
+		    tabptr->zone_admin_user);
+		if (auth_match) {
+			if ((err = zonecfg_insert_userauths(
+			    handle, tabptr->zone_admin_user,
+			    zonename)) != Z_OK)
+				return (err);
+			xmlUnlinkNode(cur);
+			xmlFreeNode(cur);
+			return (Z_OK);
+		}
+	}
+	return (Z_NO_RESOURCE_ID);
+}
+
+int
+zonecfg_delete_admin(zone_dochandle_t handle, struct zone_admintab *tabptr,
+    char *zonename)
+{
+	int err;
+
+	if (tabptr == NULL)
+		return (Z_INVAL);
+
+	if ((err = operation_prep(handle)) != Z_OK)
+		return (err);
+
+	if ((err = zonecfg_delete_auth_core(handle, tabptr, zonename)) != Z_OK)
+		return (err);
+
+	return (Z_OK);
+}
+
+int
+zonecfg_modify_admin(zone_dochandle_t handle, struct zone_admintab *oldtabptr,
+    struct zone_admintab *newtabptr, char *zonename)
+{
+	int err;
+
+	if (oldtabptr == NULL || newtabptr == NULL)
+		return (Z_INVAL);
+
+	if ((err = operation_prep(handle)) != Z_OK)
+		return (err);
+
+	if ((err = zonecfg_delete_auth_core(handle, oldtabptr, zonename))
+	    != Z_OK)
+		return (err);
+
+	if ((err = zonecfg_add_auth_core(handle, newtabptr,
+	    zonename)) != Z_OK)
+		return (err);
+
+	return (Z_OK);
+}
+
+int
+zonecfg_lookup_admin(zone_dochandle_t handle, struct zone_admintab *tabptr)
+{
+	xmlNodePtr cur, firstmatch;
+	int err;
+	char user[MAXUSERNAME];
+
+	if (tabptr == NULL)
+		return (Z_INVAL);
+
+	if ((err = operation_prep(handle)) != Z_OK)
+		return (err);
+
+	cur = handle->zone_dh_cur;
+	firstmatch = NULL;
+	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
+		if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
+			continue;
+		if (strlen(tabptr->zone_admin_user) > 0) {
+			if ((fetchprop(cur, DTD_ATTR_USER, user,
+			    sizeof (user)) == Z_OK) &&
+			    (strcmp(tabptr->zone_admin_user, user) == 0)) {
+				if (firstmatch == NULL)
+					firstmatch = cur;
+				else
+					return (Z_INSUFFICIENT_SPEC);
+			}
+		}
+	}
+	if (firstmatch == NULL)
+		return (Z_NO_RESOURCE_ID);
+
+	cur = firstmatch;
+
+	if ((err = fetchprop(cur, DTD_ATTR_USER, tabptr->zone_admin_user,
+	    sizeof (tabptr->zone_admin_user))) != Z_OK)
+		return (err);
+
+	if ((err = fetchprop(cur, DTD_ATTR_AUTHS, tabptr->zone_admin_auths,
+	    sizeof (tabptr->zone_admin_auths))) != Z_OK)
+		return (err);
+
+	return (Z_OK);
+}
+
+
 /* Lock to serialize all devwalks */
 static pthread_mutex_t zonecfg_devwalk_lock = PTHREAD_MUTEX_INITIALIZER;
 /*
@@ -3699,6 +3891,8 @@
 		return (DTD_ELEM_RCTL);
 	if (strcmp(nm, "dataset") == 0)
 		return (DTD_ELEM_DATASET);
+	if (strcmp(nm, "admin") == 0)
+		return (DTD_ELEM_ADMIN);
 
 	return (NULL);
 }
@@ -4811,6 +5005,55 @@
 	return (zonecfg_endent(handle));
 }
 
+int
+zonecfg_setadminent(zone_dochandle_t handle)
+{
+	return (zonecfg_setent(handle));
+}
+
+int
+zonecfg_getadminent(zone_dochandle_t handle, struct zone_admintab *tabptr)
+{
+	xmlNodePtr cur;
+	int err;
+
+	if (handle == NULL)
+		return (Z_INVAL);
+
+	if ((cur = handle->zone_dh_cur) == NULL)
+		return (Z_NO_ENTRY);
+
+	for (; cur != NULL; cur = cur->next)
+		if (!xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
+			break;
+	if (cur == NULL) {
+		handle->zone_dh_cur = handle->zone_dh_top;
+		return (Z_NO_ENTRY);
+	}
+
+	if ((err = fetchprop(cur, DTD_ATTR_USER, tabptr->zone_admin_user,
+	    sizeof (tabptr->zone_admin_user))) != Z_OK) {
+		handle->zone_dh_cur = handle->zone_dh_top;
+		return (err);
+	}
+
+
+	if ((err = fetchprop(cur, DTD_ATTR_AUTHS, tabptr->zone_admin_auths,
+	    sizeof (tabptr->zone_admin_auths))) != Z_OK) {
+		handle->zone_dh_cur = handle->zone_dh_top;
+		return (err);
+	}
+
+	handle->zone_dh_cur = cur->next;
+	return (Z_OK);
+}
+
+int
+zonecfg_endadminent(zone_dochandle_t handle)
+{
+	return (zonecfg_endent(handle));
+}
+
 /*
  * The privileges available on the system and described in privileges(5)
  * fall into four categories with respect to non-global zones:
@@ -7482,3 +7725,547 @@
 	free(rvalp);
 	return (-1);
 }
+
+boolean_t
+zonecfg_valid_auths(const char *auths, const char *zonename)
+{
+	char *right;
+	char *tmpauths;
+	char *lasts;
+	char authname[MAXAUTHS];
+	boolean_t status = B_TRUE;
+
+	tmpauths = strdup(auths);
+	if (tmpauths == NULL) {
+		zerror(zonename, gettext("Out of memory"));
+		return (B_FALSE);
+	}
+	right = strtok_r(tmpauths, ",", &lasts);
+	while (right != NULL) {
+		(void) snprintf(authname, MAXAUTHS, "%s%s",
+		    ZONE_AUTH_PREFIX, right);
+		if (getauthnam(authname) == NULL) {
+			status = B_FALSE;
+			zerror(zonename, gettext("%s is not a valid right"),
+			    right);
+		}
+		right = strtok_r(NULL, ",", &lasts);
+	}
+	free(tmpauths);
+	return (status);
+}
+
+int
+zonecfg_delete_admins(zone_dochandle_t handle, char *zonename)
+{
+	int err;
+	struct zone_admintab admintab;
+	boolean_t changed = B_FALSE;
+
+	if ((err = zonecfg_setadminent(handle)) != Z_OK) {
+		return (err);
+	}
+	while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
+		err = zonecfg_delete_admin(handle, &admintab,
+		    zonename);
+		if (err != Z_OK) {
+			(void) zonecfg_endadminent(handle);
+			return (err);
+		} else {
+			changed = B_TRUE;
+		}
+		if ((err = zonecfg_setadminent(handle)) != Z_OK) {
+			return (err);
+		}
+	}
+	(void) zonecfg_endadminent(handle);
+	return (changed? Z_OK:Z_NO_ENTRY);
+}
+
+/*
+ * Checks if a long authorization applies to this zone.
+ * If so, it returns true, after destructively stripping
+ * the authorization of its prefix and zone suffix.
+ */
+static boolean_t
+is_zone_auth(char **auth, char *zonename, char *oldzonename)
+{
+	char *suffix;
+	size_t offset;
+
+	offset = strlen(ZONE_AUTH_PREFIX);
+	if ((strncmp(*auth, ZONE_AUTH_PREFIX, offset) == 0) &&
+	    ((suffix = strchr(*auth, '/')) != NULL)) {
+		if (strncmp(suffix + 1, zonename, strlen(zonename)) == 0) {
+			*auth += offset;
+			suffix[0] = '\0';
+			return (B_TRUE);
+		} else if ((oldzonename != NULL) &&
+		    (strncmp(suffix + 1, oldzonename,
+		    strlen(oldzonename)) == 0)) {
+			*auth += offset;
+			suffix[0] = '\0';
+			return (B_TRUE);
+		}
+	}
+	return (B_FALSE);
+}
+
+/*
+ * This function determines whether the zone-specific authorization
+ * assignments in /etc/user_attr have been changed more recently
+ * than the equivalent data stored in the zone's configuration file.
+ * This should only happen if the zone-specific authorizations in
+ * the user_attr file were modified using a tool other than zonecfg.
+ * If the configuration file is out-of-date with respect to these
+ * authorization assignments, it is updated to match those specified
+ * in /etc/user_attr.
+ */
+
+int
+zonecfg_update_userauths(zone_dochandle_t handle, char *zonename)
+{
+	userattr_t *ua_ptr;
+	char *authlist;
+	char *lasts;
+	FILE  *uaf;
+	struct zone_admintab admintab;
+	struct stat config_st, ua_st;
+	char config_file[MAXPATHLEN];
+	boolean_t changed = B_FALSE;
+	int err;
+
+	if ((uaf = fopen(USERATTR_FILENAME, "r")) == NULL) {
+		zerror(zonename, gettext("could not open file %s: %s"),
+		    USERATTR_FILENAME, strerror(errno));
+		if (errno == EACCES)
+			return (Z_ACCES);
+		if (errno == ENOENT)
+			return (Z_NO_ZONE);
+		return (Z_MISC_FS);
+	}
+	if ((err = fstat(fileno(uaf), &ua_st)) != 0) {
+		zerror(zonename, gettext("could not stat file %s: %s"),
+		    USERATTR_FILENAME, strerror(errno));
+		(void) fclose(uaf);
+		return (Z_MISC_FS);
+	}
+	if (!config_file_path(zonename, config_file)) {
+		(void) fclose(uaf);
+		return (Z_MISC_FS);
+	}
+
+	if ((err = stat(config_file, &config_st)) != 0) {
+		zerror(zonename, gettext("could not stat file %s: %s"),
+		    config_file, strerror(errno));
+		(void) fclose(uaf);
+		return (Z_MISC_FS);
+	}
+	if (config_st.st_mtime >= ua_st.st_mtime) {
+		(void) fclose(uaf);
+		return (Z_NO_ENTRY);
+	}
+	if ((err = zonecfg_delete_admins(handle, zonename)) == Z_OK) {
+		changed = B_TRUE;
+	} else if (err != Z_NO_ENTRY) {
+		(void) fclose(uaf);
+		return (err);
+	}
+	while ((ua_ptr = fgetuserattr(uaf)) != NULL) {
+		if (ua_ptr->name[0] == '#') {
+			continue;
+		}
+		authlist = kva_match(ua_ptr->attr, USERATTR_AUTHS_KW);
+		if (authlist != NULL) {
+			char *cur_auth;
+			boolean_t first;
+
+			first = B_TRUE;
+			bzero(&admintab.zone_admin_auths, MAXAUTHS);
+			cur_auth = strtok_r(authlist, ",", &lasts);
+			while (cur_auth != NULL) {
+				if (is_zone_auth(&cur_auth, zonename,
+				    NULL)) {
+					/*
+					 * Add auths for this zone
+					 */
+					if (first) {
+						first = B_FALSE;
+					} else {
+						(void) strlcat(
+						    admintab.zone_admin_auths,
+						    ",", MAXAUTHS);
+					}
+					(void) strlcat(
+					    admintab.zone_admin_auths,
+					    cur_auth, MAXAUTHS);
+				}
+				cur_auth = strtok_r(NULL, ",", &lasts);
+			}
+			if (!first) {
+				/*
+				 * Add this right to config file
+				 */
+				(void) strlcpy(admintab.zone_admin_user,
+				    ua_ptr->name,
+				    sizeof (admintab.zone_admin_user));
+				err = zonecfg_add_admin(handle,
+				    &admintab, zonename);
+				if (err != Z_OK) {
+					(void) fclose(uaf);
+					return (err);
+				} else {
+					changed = B_TRUE;
+				}
+			}
+		}
+	} /* end-of-while-loop */
+	(void) fclose(uaf);
+	return (changed? Z_OK: Z_NO_ENTRY);
+}
+
+static void
+update_profiles(char *rbac_profs, boolean_t add)
+{
+	char new_profs[MAXPROFS];
+	char *cur_prof;
+	boolean_t first = B_TRUE;
+	boolean_t found = B_FALSE;
+	char *lasts;
+
+	cur_prof = strtok_r(rbac_profs, ",", &lasts);
+	while (cur_prof != NULL) {
+		if (strcmp(cur_prof, ZONE_MGMT_PROF) == 0) {
+			found = B_TRUE;
+			if (!add) {
+				cur_prof = strtok_r(NULL, ",", &lasts);
+				continue;
+			}
+		}
+		if (first) {
+			first = B_FALSE;
+		} else {
+			(void) strlcat(new_profs, ",",
+			    MAXPROFS);
+		}
+		(void) strlcat(new_profs, cur_prof,
+		    MAXPROFS);
+		cur_prof = strtok_r(NULL, ",", &lasts);
+	}
+	/*
+	 * Now prepend the Zone Management profile at the beginning
+	 * of the list if it is needed, and append the rest.
+	 * Return the updated list in the original buffer.
+	 */
+	if (add && !found) {
+		first = B_FALSE;
+		(void) strlcpy(rbac_profs, ZONE_MGMT_PROF, MAXPROFS);
+	} else {
+		first = B_TRUE;
+		rbac_profs[0] = '\0';
+	}
+	if (strlen(new_profs) > 0) {
+		if (!first)
+			(void) strlcat(rbac_profs, ",", MAXPROFS);
+		(void) strlcat(rbac_profs, new_profs, MAXPROFS);
+	}
+}
+
+#define	MAX_CMD_LEN	1024
+
+static int
+do_subproc(char *zonename, char *cmdbuf)
+{
+	char inbuf[MAX_CMD_LEN];
+	FILE *file;
+	int status;
+
+	file = popen(cmdbuf, "r");
+	if (file == NULL) {
+		zerror(zonename, gettext("Could not launch: %s"), cmdbuf);
+		return (-1);
+	}
+
+	while (fgets(inbuf, sizeof (inbuf), file) != NULL)
+		(void) fprintf(stderr, "%s", inbuf);
+	status = pclose(file);
+
+	if (WIFSIGNALED(status)) {
+		zerror(zonename, gettext("%s unexpectedly terminated "
+		    "due to signal %d"),
+		    cmdbuf, WTERMSIG(status));
+		return (-1);
+	}
+	assert(WIFEXITED(status));
+	return (WEXITSTATUS(status));
+}
+
+/*
+ * This function updates the local /etc/user_attr file to
+ * correspond to the admin settings that are currently being
+ * committed. The updates are done via usermod and/or rolemod
+ * depending on the type of the specified user. It is also
+ * invoked to remove entries from user_attr corresponding to
+ * removed admin assignments, using an empty auths string.
+ *
+ * Because the removed entries are no longer included in the
+ * cofiguration that is being committed, a linked list of
+ * removed admin entries is maintained to keep track of such
+ * transactions. The head of the list is stored in the zone_dh_userauths
+ * element of the handle strcture.
+ */
+static int
+zonecfg_authorize_user_impl(zone_dochandle_t handle, char *user,
+    char *auths, char *zonename)
+{
+	char *right;
+	char old_auths[MAXAUTHS];
+	char new_auths[MAXAUTHS];
+	char rbac_profs[MAXPROFS];
+	char *lasts;
+	userattr_t *u;
+	boolean_t first = B_TRUE;
+	boolean_t is_zone_admin = B_FALSE;
+	char user_cmd[] = "/usr/sbin/usermod";
+	char role_cmd[] = "/usr/sbin/rolemod";
+	char *auths_cmd = user_cmd;
+
+	/*
+	 * First get the existing authorizations for this user
+	 */
+
+	bzero(&old_auths, sizeof (old_auths));
+	bzero(&new_auths, sizeof (new_auths));
+	bzero(&rbac_profs, sizeof (rbac_profs));
+	if ((u = getusernam(user)) != NULL) {
+		char *current_auths;
+		char *current_profs;
+		char *type;
+
+		type = kva_match(u->attr, USERATTR_TYPE_KW);
+		if (type != NULL) {
+			if (strcmp(type, USERATTR_TYPE_NONADMIN_KW) == 0)
+				auths_cmd = role_cmd;
+		}
+
+		current_auths = kva_match(u->attr, USERATTR_AUTHS_KW);
+		if (current_auths != NULL) {
+			char *cur_auth;
+			char *delete_name;
+			size_t offset;
+
+			offset = strlen(ZONE_AUTH_PREFIX);
+
+			(void) strlcpy(old_auths, current_auths, MAXAUTHS);
+			cur_auth = strtok_r(current_auths, ",", &lasts);
+
+			/*
+			 * Next, remove any existing authorizations
+			 * for this zone, and determine if the
+			 * user still needs the Zone Management Profile.
+			 */
+			if (is_renaming(handle))
+				delete_name = handle->zone_dh_delete_name;
+			else
+				delete_name = NULL;
+			while (cur_auth != NULL) {
+				if (!is_zone_auth(&cur_auth, zonename,
+				    delete_name)) {
+					if (first) {
+						first = B_FALSE;
+					} else {
+						(void) strlcat(new_auths, ",",
+						    MAXAUTHS);
+					}
+					(void) strlcat(new_auths, cur_auth,
+					    MAXAUTHS);
+					/*
+					 * If the user has authorizations
+					 * for other zones, then set a
+					 * flag indicate that the Zone
+					 * Management profile should be
+					 * preserved in user_attr.
+					 */
+					if (strncmp(cur_auth,
+					    ZONE_AUTH_PREFIX, offset) == 0)
+						is_zone_admin = B_TRUE;
+				}
+				cur_auth = strtok_r(NULL, ",", &lasts);
+			}
+		}
+		current_profs = kva_match(u->attr, USERATTR_PROFILES_KW);
+		if (current_profs != NULL) {
+			(void) strlcpy(rbac_profs, current_profs, MAXPROFS);
+		}
+		free_userattr(u);
+	}
+	/*
+	 * The following is done to avoid revisiting the
+	 * user_attr entry for this user
+	 */
+	(void) zonecfg_remove_userauths(handle, user, "", B_FALSE);
+
+	/*
+	 * Convert each right into a properly formatted authorization
+	 */
+	right = strtok_r(auths, ",", &lasts);
+	while (right != NULL) {
+		char auth[MAXAUTHS];
+
+		(void) snprintf(auth, MAXAUTHS, "%s%s/%s",
+		    ZONE_AUTH_PREFIX, right, zonename);
+		if (first) {
+			first = B_FALSE;
+		} else {
+			(void) strlcat(new_auths, ",", MAXAUTHS);
+		}
+		(void) strlcat(new_auths, auth, MAXAUTHS);
+		is_zone_admin = B_TRUE;
+		right = strtok_r(NULL, ",", &lasts);
+	}
+
+	/*
+	 * If the user's previous authorizations have changed
+	 * execute the usermod progam to update them in user_attr
+	 */
+	if (strcmp(old_auths, new_auths) != 0) {
+		char    *cmdbuf;
+		size_t  cmd_len;
+
+		update_profiles(rbac_profs, is_zone_admin);
+		cmd_len = snprintf(NULL, 0, "%s -A \"%s\" -P \"%s\" %s",
+		    auths_cmd, new_auths, rbac_profs, user) + 1;
+		if ((cmdbuf = malloc(cmd_len)) == NULL) {
+			return (Z_NOMEM);
+		}
+		(void) snprintf(cmdbuf, cmd_len, "%s -A \"%s\" -P \"%s\" %s",
+		    auths_cmd, new_auths, rbac_profs, user);
+		if (do_subproc(zonename, cmdbuf) != 0) {
+			free(cmdbuf);
+			return (Z_SYSTEM);
+		}
+		free(cmdbuf);
+	}
+
+	return (Z_OK);
+}
+
+int
+zonecfg_authorize_users(zone_dochandle_t handle, char *zonename)
+{
+	xmlNodePtr cur;
+	int err;
+	char user[MAXUSERNAME];
+	char auths[MAXAUTHS];
+
+	if ((err = operation_prep(handle)) != Z_OK)
+		return (err);
+
+	cur = handle->zone_dh_cur;
+	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
+		if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
+			continue;
+		if (fetchprop(cur, DTD_ATTR_USER, user,
+		    sizeof (user)) != Z_OK)
+			continue;
+		if (fetchprop(cur, DTD_ATTR_AUTHS, auths,
+		    sizeof (auths)) != Z_OK)
+			continue;
+		if (zonecfg_authorize_user_impl(handle, user, auths, zonename)
+		    != Z_OK)
+			return (Z_SYSTEM);
+	}
+	(void) zonecfg_remove_userauths(handle, "", "", B_TRUE);
+
+	return (Z_OK);
+}
+
+int
+zonecfg_deauthorize_user(zone_dochandle_t handle, char *user, char *zonename)
+{
+	return (zonecfg_authorize_user_impl(handle, user, "", zonename));
+}
+
+int
+zonecfg_deauthorize_users(zone_dochandle_t handle, char *zonename)
+{
+	xmlNodePtr cur;
+	int err;
+	char user[MAXUSERNAME];
+
+	if ((err = operation_prep(handle)) != Z_OK)
+		return (err);
+
+	cur = handle->zone_dh_cur;
+	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
+		if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
+			continue;
+		if (fetchprop(cur, DTD_ATTR_USER, user,
+		    sizeof (user)) != Z_OK)
+			continue;
+		if ((err = zonecfg_deauthorize_user(handle, user,
+		    zonename)) != Z_OK)
+			return (err);
+	}
+	return (Z_OK);
+}
+
+int
+zonecfg_insert_userauths(zone_dochandle_t handle, char *user, char *zonename)
+{
+	zone_userauths_t *new, **prev, *next;
+
+	prev = &handle->zone_dh_userauths;
+	next = *prev;
+	while (next) {
+		if ((strncmp(next->user, user, MAXUSERNAME) == 0) &&
+		    (strncmp(next->zonename, zonename,
+		    ZONENAME_MAX) == 0)) {
+			/*
+			 * user is already in list
+			 * which isn't supposed to happen!
+			 */
+			return (Z_OK);
+		}
+		prev = &next->next;
+		next = *prev;
+	}
+	new = (zone_userauths_t *)malloc(sizeof (zone_userauths_t));
+	if (new == NULL)
+		return (Z_NOMEM);
+
+	(void) strlcpy(new->user, user, sizeof (new->user));
+	(void) strlcpy(new->zonename, zonename, sizeof (new->zonename));
+	new->next = NULL;
+	*prev = new;
+	return (Z_OK);
+}
+
+int
+zonecfg_remove_userauths(zone_dochandle_t handle, char *user, char *zonename,
+	boolean_t deauthorize)
+{
+	zone_userauths_t *new, **prev, *next;
+
+	prev = &handle->zone_dh_userauths;
+	next = *prev;
+
+	while (next) {
+		if ((strlen(user) == 0 ||
+		    strncmp(next->user, user, MAXUSERNAME) == 0) &&
+		    (strlen(zonename) == 0 ||
+		    (strncmp(next->zonename, zonename, ZONENAME_MAX) == 0))) {
+			new = next;
+			*prev = next->next;
+			next =  *prev;
+			if (deauthorize)
+				(void) zonecfg_deauthorize_user(handle,
+				    new->user, new->zonename);
+			free(new);
+			continue;
+		}
+		prev = &next->next;
+		next = *prev;
+	}
+	return (Z_OK);
+}
--- a/usr/src/lib/libzonecfg/common/mapfile-vers	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/lib/libzonecfg/common/mapfile-vers	Mon Jun 07 14:07:27 2010 -0700
@@ -19,8 +19,7 @@
 # CDDL HEADER END
 #
 #
-# 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.
 #
 
 #
@@ -50,6 +49,7 @@
 	zonecfg_add_ds;
 	zonecfg_add_filesystem;
 	zonecfg_add_fs_option;
+	zonecfg_add_admin;
 	zonecfg_add_ipd;
 	zonecfg_add_nwif;
 	zonecfg_add_patch;
@@ -62,6 +62,7 @@
 	zonecfg_aliased_rctl_ok;
 	zonecfg_apply_rctls;
 	zonecfg_attach_manifest;
+	zonecfg_authorize_users;
 	zonecfg_bind_pool;
 	zonecfg_bind_tmp_pool;
 	zonecfg_call_zoneadmd;
@@ -69,8 +70,12 @@
 	zonecfg_close_scratch;
 	zonecfg_construct_rctlblk;
 	zonecfg_create_snapshot;
+	zonecfg_deauthorize_user;
+	zonecfg_deauthorize_users;
 	zonecfg_default_brand;
 	zonecfg_default_privset;
+	zonecfg_delete_admin;
+	zonecfg_delete_admins;
 	zonecfg_delete_attr;
 	zonecfg_delete_dev;
 	zonecfg_delete_ds;
@@ -90,6 +95,7 @@
 	zonecfg_devperms_apply;
 	zonecfg_dev_manifest;
 	zonecfg_enable_rcapd;
+	zonecfg_endadminent;
 	zonecfg_endattrent;
 	zonecfg_enddevent;
 	zonecfg_enddevperment;
@@ -106,6 +112,7 @@
 	zonecfg_get_aliased_rctl;
 	zonecfg_get_attach_handle;
 	zonecfg_get_attr_boolean;
+	zonecfg_getadminent;
 	zonecfg_getattrent;
 	zonecfg_get_attr_int;
 	zonecfg_get_attr_string;
@@ -144,12 +151,14 @@
 	zonecfg_grab_lock_file;
 	zonecfg_ifname_exists;
 	zonecfg_in_alt_root;
+	zonecfg_insert_userauths;
 	zonecfg_init_handle;
 	zonecfg_init_lock_file;
 	zonecfg_is_rctl;
 	zonecfg_is_scratch;
 	zonecfg_lock_file_held;
 	zonecfg_lock_scratch;
+	zonecfg_lookup_admin;
 	zonecfg_lookup_attr;
 	zonecfg_lookup_dev;
 	zonecfg_lookup_ds;
@@ -159,6 +168,7 @@
 	zonecfg_lookup_nwif;
 	zonecfg_lookup_pset;
 	zonecfg_lookup_rctl;
+	zonecfg_modify_admin;
 	zonecfg_modify_attr;
 	zonecfg_modify_dev;
 	zonecfg_modify_ds;
@@ -179,11 +189,13 @@
 	zonecfg_release_lock_file;
 	zonecfg_remove_fs_option;
 	zonecfg_remove_rctl_value;
+	zonecfg_remove_userauths;
 	zonecfg_reverse_scratch;
 	zonecfg_rm_aliased_rctl;
 	zonecfg_rm_detached;
 	zonecfg_same_net_address;
 	zonecfg_save;
+	zonecfg_setadminent;
 	zonecfg_setattrent;
 	zonecfg_set_aliased_rctl;
 	zonecfg_set_autoboot;
@@ -207,7 +219,9 @@
 	zonecfg_set_zonepath;
 	zonecfg_strerror;
 	zonecfg_str_to_bytes;
+	zonecfg_update_userauths;
 	zonecfg_validate_zonename;
+	zonecfg_valid_auths;
 	zonecfg_valid_alias_limit;
 	zonecfg_valid_fs_type;
 	zonecfg_valid_hostid;
--- a/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1	Mon Jun 07 14:07:27 2010 -0700
@@ -20,8 +20,7 @@
 
  CDDL HEADER END
 
- Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- Use is subject to license terms.
+ Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
 
 -->
 
@@ -131,9 +130,15 @@
 
 <!ATTLIST mcap		physcap		CDATA #REQUIRED>
 
+<!ELEMENT admin 	EMPTY>
+
+<!ATTLIST admin     	user		CDATA #REQUIRED
+                    	auths		CDATA #REQUIRED>
+
 <!ELEMENT zone		(filesystem | inherited-pkg-dir | network | device |
 			deleted-device | rctl | attr | dataset | package |
-			patch | dev-perm | tmp_pool | pset | mcap)*>
+			patch | dev-perm | tmp_pool | pset |
+			mcap | admin)*>
 
 <!ATTLIST zone		name		CDATA #REQUIRED
 			zonepath	CDATA #REQUIRED
--- a/usr/src/pkg/manifests/SUNWcs.mf	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/pkg/manifests/SUNWcs.mf	Mon Jun 07 14:07:27 2010 -0700
@@ -1037,6 +1037,10 @@
 file path=usr/lib/help/auths/locale/C/SysSyseventWrite.html
 file path=usr/lib/help/auths/locale/C/WifiConfig.html
 file path=usr/lib/help/auths/locale/C/WifiWep.html
+file path=usr/lib/help/auths/locale/C/ZoneCloneFrom.html
+file path=usr/lib/help/auths/locale/C/ZoneHeader.html
+file path=usr/lib/help/auths/locale/C/ZoneLogin.html
+file path=usr/lib/help/auths/locale/C/ZoneManage.html
 file path=usr/lib/help/profiles/locale/C/RtAcctadm.html
 file path=usr/lib/help/profiles/locale/C/RtAll.html
 file path=usr/lib/help/profiles/locale/C/RtAuditCtrl.html
@@ -1109,6 +1113,7 @@
 file path=usr/lib/help/profiles/locale/C/RtZFSFileSysMngmnt.html
 file path=usr/lib/help/profiles/locale/C/RtZFSStorageMngmnt.html
 file path=usr/lib/help/profiles/locale/C/RtZoneMngmnt.html
+file path=usr/lib/help/profiles/locale/C/RtZoneSecurity.html
 file path=usr/lib/hotplugd mode=0555
 file path=usr/lib/iconv/646da.8859.t mode=0444
 file path=usr/lib/iconv/646de.8859.t mode=0444
--- a/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf	Mon Jun 07 13:43:38 2010 -0700
+++ b/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf	Mon Jun 07 14:07:27 2010 -0700
@@ -212,6 +212,10 @@
 file path=usr/lib/help/auths/locale/ValueTND.html
 file path=usr/lib/help/auths/locale/WifiConfig.html
 file path=usr/lib/help/auths/locale/WifiWep.html
+file path=usr/lib/help/auths/locale/ZoneCloneFrom.html
+file path=usr/lib/help/auths/locale/ZoneHeader.html
+file path=usr/lib/help/auths/locale/ZoneLogin.html
+file path=usr/lib/help/auths/locale/ZoneManage.html
 file path=usr/lib/help/profiles/locale/RtAcctadm.html
 file path=usr/lib/help/profiles/locale/RtAll.html
 file path=usr/lib/help/profiles/locale/RtAuditCtrl.html
@@ -287,6 +291,7 @@
 file path=usr/lib/help/profiles/locale/RtZFSFileSysMngmnt.html
 file path=usr/lib/help/profiles/locale/RtZFSStorageMngmnt.html
 file path=usr/lib/help/profiles/locale/RtZoneMngmnt.html
+file path=usr/lib/help/profiles/locale/RtZoneSecurity.html
 file path=usr/lib/locale/C/LC_MESSAGES/AMD.po
 file path=usr/lib/locale/C/LC_MESSAGES/DISK.po
 file path=usr/lib/locale/C/LC_MESSAGES/FMD.po