xref: /onnv-gate/usr/src/lib/libzonecfg/common/libzonecfg.c (revision 13117:f5e08a0ff14b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51507Sgjelinek  * Common Development and Distribution License (the "License").
61507Sgjelinek  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211645Scomay 
220Sstevel@tonic-gate /*
2312582SGlenn.Faden@Sun.COM  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
261166Sdstaff #include <libsysevent.h>
271166Sdstaff #include <pthread.h>
281166Sdstaff #include <stdlib.h>
290Sstevel@tonic-gate #include <errno.h>
300Sstevel@tonic-gate #include <fnmatch.h>
310Sstevel@tonic-gate #include <strings.h>
320Sstevel@tonic-gate #include <unistd.h>
330Sstevel@tonic-gate #include <assert.h>
340Sstevel@tonic-gate #include <libgen.h>
350Sstevel@tonic-gate #include <libintl.h>
360Sstevel@tonic-gate #include <alloca.h>
370Sstevel@tonic-gate #include <ctype.h>
382712Snn35248 #include <sys/acl.h>
392712Snn35248 #include <sys/stat.h>
402712Snn35248 #include <sys/brand.h>
410Sstevel@tonic-gate #include <sys/mntio.h>
420Sstevel@tonic-gate #include <sys/mnttab.h>
432712Snn35248 #include <sys/nvpair.h>
44565Sdp #include <sys/types.h>
453448Sdh155122 #include <sys/sockio.h>
468662SJordan.Vaughan@Sun.com #include <sys/systeminfo.h>
471507Sgjelinek #include <ftw.h>
483247Sgjelinek #include <pool.h>
493247Sgjelinek #include <libscf.h>
503247Sgjelinek #include <libproc.h>
513247Sgjelinek #include <sys/priocntl.h>
524229Sgjelinek #include <libuutil.h>
537089Sgjelinek #include <wait.h>
547089Sgjelinek #include <bsm/adt.h>
5512578SGlenn.Faden@Sun.COM #include <auth_attr.h>
5612578SGlenn.Faden@Sun.COM #include <auth_list.h>
5712578SGlenn.Faden@Sun.COM #include <secdb.h>
5812578SGlenn.Faden@Sun.COM #include <user_attr.h>
5912578SGlenn.Faden@Sun.COM #include <prof_attr.h>
600Sstevel@tonic-gate 
610Sstevel@tonic-gate #include <arpa/inet.h>
620Sstevel@tonic-gate #include <netdb.h>
630Sstevel@tonic-gate 
640Sstevel@tonic-gate #include <libxml/xmlmemory.h>
650Sstevel@tonic-gate #include <libxml/parser.h>
660Sstevel@tonic-gate 
670Sstevel@tonic-gate #include <libdevinfo.h>
68766Scarlsonj #include <uuid/uuid.h>
691507Sgjelinek #include <dirent.h>
702712Snn35248 #include <libbrand.h>
711507Sgjelinek 
720Sstevel@tonic-gate #include <libzonecfg.h>
730Sstevel@tonic-gate #include "zonecfg_impl.h"
740Sstevel@tonic-gate 
750Sstevel@tonic-gate #define	_PATH_TMPFILE	"/zonecfg.XXXXXX"
761166Sdstaff #define	ZONE_CB_RETRY_COUNT		10
771166Sdstaff #define	ZONE_EVENT_PING_SUBCLASS	"ping"
781166Sdstaff #define	ZONE_EVENT_PING_PUBLISHER	"solaris"
790Sstevel@tonic-gate 
800Sstevel@tonic-gate /* Hard-code the DTD element/attribute/entity names just once, here. */
810Sstevel@tonic-gate #define	DTD_ELEM_ATTR		(const xmlChar *) "attr"
820Sstevel@tonic-gate #define	DTD_ELEM_COMMENT	(const xmlChar *) "comment"
830Sstevel@tonic-gate #define	DTD_ELEM_DEVICE		(const xmlChar *) "device"
840Sstevel@tonic-gate #define	DTD_ELEM_FS		(const xmlChar *) "filesystem"
850Sstevel@tonic-gate #define	DTD_ELEM_FSOPTION	(const xmlChar *) "fsoption"
860Sstevel@tonic-gate #define	DTD_ELEM_NET		(const xmlChar *) "network"
870Sstevel@tonic-gate #define	DTD_ELEM_RCTL		(const xmlChar *) "rctl"
880Sstevel@tonic-gate #define	DTD_ELEM_RCTLVALUE	(const xmlChar *) "rctl-value"
890Sstevel@tonic-gate #define	DTD_ELEM_ZONE		(const xmlChar *) "zone"
90789Sahrens #define	DTD_ELEM_DATASET	(const xmlChar *) "dataset"
913247Sgjelinek #define	DTD_ELEM_TMPPOOL	(const xmlChar *) "tmp_pool"
923247Sgjelinek #define	DTD_ELEM_PSET		(const xmlChar *) "pset"
933247Sgjelinek #define	DTD_ELEM_MCAP		(const xmlChar *) "mcap"
941507Sgjelinek #define	DTD_ELEM_PACKAGE	(const xmlChar *) "package"
951507Sgjelinek #define	DTD_ELEM_PATCH		(const xmlChar *) "patch"
965829Sgjelinek #define	DTD_ELEM_OBSOLETES	(const xmlChar *) "obsoletes"
971507Sgjelinek #define	DTD_ELEM_DEV_PERM	(const xmlChar *) "dev-perm"
9812578SGlenn.Faden@Sun.COM #define	DTD_ELEM_ADMIN		(const xmlChar *) "admin"
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate #define	DTD_ATTR_ACTION		(const xmlChar *) "action"
1010Sstevel@tonic-gate #define	DTD_ATTR_ADDRESS	(const xmlChar *) "address"
10212748SSowmini.Varadhan@oracle.COM #define	DTD_ATTR_ALLOWED_ADDRESS	(const xmlChar *) "allowed-address"
1030Sstevel@tonic-gate #define	DTD_ATTR_AUTOBOOT	(const xmlChar *) "autoboot"
1043448Sdh155122 #define	DTD_ATTR_IPTYPE		(const xmlChar *) "ip-type"
1056076Sgfaden #define	DTD_ATTR_DEFROUTER	(const xmlChar *) "defrouter"
1060Sstevel@tonic-gate #define	DTD_ATTR_DIR		(const xmlChar *) "directory"
1070Sstevel@tonic-gate #define	DTD_ATTR_LIMIT		(const xmlChar *) "limit"
1081645Scomay #define	DTD_ATTR_LIMITPRIV	(const xmlChar *) "limitpriv"
1092267Sdp #define	DTD_ATTR_BOOTARGS	(const xmlChar *) "bootargs"
1103247Sgjelinek #define	DTD_ATTR_SCHED		(const xmlChar *) "scheduling-class"
1110Sstevel@tonic-gate #define	DTD_ATTR_MATCH		(const xmlChar *) "match"
1120Sstevel@tonic-gate #define	DTD_ATTR_NAME		(const xmlChar *) "name"
1130Sstevel@tonic-gate #define	DTD_ATTR_PHYSICAL	(const xmlChar *) "physical"
1140Sstevel@tonic-gate #define	DTD_ATTR_POOL		(const xmlChar *) "pool"
1150Sstevel@tonic-gate #define	DTD_ATTR_PRIV		(const xmlChar *) "priv"
1160Sstevel@tonic-gate #define	DTD_ATTR_RAW		(const xmlChar *) "raw"
1170Sstevel@tonic-gate #define	DTD_ATTR_SPECIAL	(const xmlChar *) "special"
1180Sstevel@tonic-gate #define	DTD_ATTR_TYPE		(const xmlChar *) "type"
1190Sstevel@tonic-gate #define	DTD_ATTR_VALUE		(const xmlChar *) "value"
1200Sstevel@tonic-gate #define	DTD_ATTR_ZONEPATH	(const xmlChar *) "zonepath"
1213247Sgjelinek #define	DTD_ATTR_NCPU_MIN	(const xmlChar *) "ncpu_min"
1223247Sgjelinek #define	DTD_ATTR_NCPU_MAX	(const xmlChar *) "ncpu_max"
1233247Sgjelinek #define	DTD_ATTR_IMPORTANCE	(const xmlChar *) "importance"
1243247Sgjelinek #define	DTD_ATTR_PHYSCAP	(const xmlChar *) "physcap"
1251507Sgjelinek #define	DTD_ATTR_VERSION	(const xmlChar *) "version"
1261507Sgjelinek #define	DTD_ATTR_ID		(const xmlChar *) "id"
1271507Sgjelinek #define	DTD_ATTR_UID		(const xmlChar *) "uid"
1281507Sgjelinek #define	DTD_ATTR_GID		(const xmlChar *) "gid"
1291507Sgjelinek #define	DTD_ATTR_MODE		(const xmlChar *) "mode"
1301507Sgjelinek #define	DTD_ATTR_ACL		(const xmlChar *) "acl"
1312712Snn35248 #define	DTD_ATTR_BRAND		(const xmlChar *) "brand"
1328662SJordan.Vaughan@Sun.com #define	DTD_ATTR_HOSTID		(const xmlChar *) "hostid"
13312578SGlenn.Faden@Sun.COM #define	DTD_ATTR_USER		(const xmlChar *) "user"
13412578SGlenn.Faden@Sun.COM #define	DTD_ATTR_AUTHS		(const xmlChar *) "auths"
13512633Sjohn.levon@sun.com #define	DTD_ATTR_FS_ALLOWED	(const xmlChar *) "fs-allowed"
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate #define	DTD_ENTITY_BOOLEAN	"boolean"
1380Sstevel@tonic-gate #define	DTD_ENTITY_DEVPATH	"devpath"
1390Sstevel@tonic-gate #define	DTD_ENTITY_DRIVER	"driver"
1400Sstevel@tonic-gate #define	DTD_ENTITY_DRVMIN	"drv_min"
1410Sstevel@tonic-gate #define	DTD_ENTITY_FALSE	"false"
1420Sstevel@tonic-gate #define	DTD_ENTITY_INT		"int"
1430Sstevel@tonic-gate #define	DTD_ENTITY_STRING	"string"
1440Sstevel@tonic-gate #define	DTD_ENTITY_TRUE		"true"
1450Sstevel@tonic-gate #define	DTD_ENTITY_UINT		"uint"
1460Sstevel@tonic-gate 
147228Sdp #define	DTD_ENTITY_BOOL_LEN	6	/* "false" */
148228Sdp 
1491507Sgjelinek #define	ATTACH_FORCED	"SUNWattached.xml"
1501507Sgjelinek 
1513247Sgjelinek #define	TMP_POOL_NAME	"SUNWtmp_%s"
1523247Sgjelinek #define	MAX_TMP_POOL_NAME	(ZONENAME_MAX + 9)
1533247Sgjelinek #define	RCAP_SERVICE	"system/rcap:default"
1543247Sgjelinek #define	POOLD_SERVICE	"system/pools/dynamic:default"
1553247Sgjelinek 
1563247Sgjelinek /*
1573247Sgjelinek  * rctl alias definitions
1583247Sgjelinek  *
1593247Sgjelinek  * This holds the alias, the full rctl name, the default priv value, action
1603247Sgjelinek  * and lower limit.  The functions that handle rctl aliases step through
1613247Sgjelinek  * this table, matching on the alias, and using the full values for setting
1623247Sgjelinek  * the rctl entry as well the limit for validation.
1633247Sgjelinek  */
1643247Sgjelinek static struct alias {
1653247Sgjelinek 	char *shortname;
1663247Sgjelinek 	char *realname;
1673247Sgjelinek 	char *priv;
1683247Sgjelinek 	char *action;
1693247Sgjelinek 	uint64_t low_limit;
1703247Sgjelinek } aliases[] = {
1713247Sgjelinek 	{ALIAS_MAXLWPS, "zone.max-lwps", "privileged", "deny", 100},
1723247Sgjelinek 	{ALIAS_MAXSHMMEM, "zone.max-shm-memory", "privileged", "deny", 0},
1733247Sgjelinek 	{ALIAS_MAXSHMIDS, "zone.max-shm-ids", "privileged", "deny", 0},
1743247Sgjelinek 	{ALIAS_MAXMSGIDS, "zone.max-msg-ids", "privileged", "deny", 0},
1753247Sgjelinek 	{ALIAS_MAXSEMIDS, "zone.max-sem-ids", "privileged", "deny", 0},
1763247Sgjelinek 	{ALIAS_MAXLOCKEDMEM, "zone.max-locked-memory", "privileged", "deny", 0},
1773247Sgjelinek 	{ALIAS_MAXSWAP, "zone.max-swap", "privileged", "deny", 0},
1783247Sgjelinek 	{ALIAS_SHARES, "zone.cpu-shares", "privileged", "none", 0},
1793792Sakolb 	{ALIAS_CPUCAP, "zone.cpu-cap", "privileged", "deny", 0},
18012725SMenno.Lageman@Sun.COM 	{ALIAS_MAXPROCS, "zone.max-processes", "privileged", "deny", 100},
1813247Sgjelinek 	{NULL, NULL, NULL, NULL, 0}
1823247Sgjelinek };
1833247Sgjelinek 
1843247Sgjelinek /*
1853247Sgjelinek  * Structure for applying rctls to a running zone.  It allows important
1863247Sgjelinek  * process values to be passed together easily.
1873247Sgjelinek  */
1883247Sgjelinek typedef struct pr_info_handle {
1893247Sgjelinek 	struct ps_prochandle *pr;
1903247Sgjelinek 	pid_t pid;
1913247Sgjelinek } pr_info_handle_t;
1923247Sgjelinek 
1930Sstevel@tonic-gate struct zone_dochandle {
1940Sstevel@tonic-gate 	char		*zone_dh_rootdir;
1950Sstevel@tonic-gate 	xmlDocPtr	zone_dh_doc;
1960Sstevel@tonic-gate 	xmlNodePtr	zone_dh_cur;
1970Sstevel@tonic-gate 	xmlNodePtr	zone_dh_top;
198565Sdp 	boolean_t	zone_dh_newzone;
199565Sdp 	boolean_t	zone_dh_snapshot;
2001507Sgjelinek 	boolean_t	zone_dh_sw_inv;
20112578SGlenn.Faden@Sun.COM 	zone_userauths_t	*zone_dh_userauths;
202565Sdp 	char		zone_dh_delete_name[ZONENAME_MAX];
2030Sstevel@tonic-gate };
2040Sstevel@tonic-gate 
2051166Sdstaff struct znotify {
2061166Sdstaff 	void * zn_private;
2071166Sdstaff 	evchan_t *zn_eventchan;
2081166Sdstaff 	int (*zn_callback)(const  char *zonename, zoneid_t zid,
2091166Sdstaff 	    const char *newstate, const char *oldstate, hrtime_t when, void *p);
2101166Sdstaff 	pthread_mutex_t zn_mutex;
2111166Sdstaff 	pthread_cond_t zn_cond;
2121166Sdstaff 	pthread_mutex_t zn_bigmutex;
2131166Sdstaff 	volatile enum {ZN_UNLOCKED, ZN_LOCKED, ZN_PING_INFLIGHT,
2141166Sdstaff 	    ZN_PING_RECEIVED} zn_state;
2151166Sdstaff 	char zn_subscriber_id[MAX_SUBID_LEN];
2161166Sdstaff 	volatile boolean_t zn_failed;
2171166Sdstaff 	int zn_failure_count;
2181166Sdstaff };
2191166Sdstaff 
2207089Sgjelinek /* used to track nested zone-lock operations */
2217089Sgjelinek static int zone_lock_cnt = 0;
2227089Sgjelinek 
2237089Sgjelinek /* used to communicate lock status to children */
2247089Sgjelinek #define	LOCK_ENV_VAR	"_ZONEADM_LOCK_HELD"
2257089Sgjelinek static char zoneadm_lock_held[] = LOCK_ENV_VAR"=1";
2267089Sgjelinek static char zoneadm_lock_not_held[] = LOCK_ENV_VAR"=0";
2274229Sgjelinek 
228766Scarlsonj char *zonecfg_root = "";
229766Scarlsonj 
2300Sstevel@tonic-gate /*
2310Sstevel@tonic-gate  * For functions which return int, which is most of the functions herein,
2320Sstevel@tonic-gate  * the return values should be from the Z_foo set defined in <libzonecfg.h>.
2330Sstevel@tonic-gate  * In some instances, we take pains mapping some libc errno values to Z_foo
2340Sstevel@tonic-gate  * values from this set.
2350Sstevel@tonic-gate  */
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate /*
238766Scarlsonj  * Set the root (/) path for all zonecfg configuration files.  This is a
239766Scarlsonj  * private interface used by Live Upgrade extensions to access zone
240766Scarlsonj  * configuration inside mounted alternate boot environments.
241*13117SSusan.Kamm-Worrell@Sun.COM  * This interface is also used by zoneadm mount and unmount subcommands.
242766Scarlsonj  */
243766Scarlsonj void
zonecfg_set_root(const char * rootpath)244766Scarlsonj zonecfg_set_root(const char *rootpath)
245766Scarlsonj {
246766Scarlsonj 	if (*zonecfg_root != '\0')
247766Scarlsonj 		free(zonecfg_root);
248766Scarlsonj 	if (rootpath == NULL || rootpath[0] == '\0' || rootpath[1] == '\0' ||
249766Scarlsonj 	    (zonecfg_root = strdup(rootpath)) == NULL)
250766Scarlsonj 		zonecfg_root = "";
251766Scarlsonj }
252766Scarlsonj 
253766Scarlsonj const char *
zonecfg_get_root(void)254766Scarlsonj zonecfg_get_root(void)
255766Scarlsonj {
256766Scarlsonj 	return (zonecfg_root);
257766Scarlsonj }
258766Scarlsonj 
259766Scarlsonj boolean_t
zonecfg_in_alt_root(void)260766Scarlsonj zonecfg_in_alt_root(void)
261766Scarlsonj {
262766Scarlsonj 	return (*zonecfg_root != '\0');
263766Scarlsonj }
264766Scarlsonj 
265766Scarlsonj /*
2660Sstevel@tonic-gate  * Callers of the _file_path() functions are expected to have the second
2670Sstevel@tonic-gate  * parameter be a (char foo[MAXPATHLEN]).
2680Sstevel@tonic-gate  */
2690Sstevel@tonic-gate 
270766Scarlsonj static boolean_t
config_file_path(const char * zonename,char * answer)2710Sstevel@tonic-gate config_file_path(const char *zonename, char *answer)
2720Sstevel@tonic-gate {
273766Scarlsonj 	return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root,
274766Scarlsonj 	    ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN);
2750Sstevel@tonic-gate }
2760Sstevel@tonic-gate 
277766Scarlsonj static boolean_t
snap_file_path(const char * zonename,char * answer)278766Scarlsonj snap_file_path(const char *zonename, char *answer)
2790Sstevel@tonic-gate {
280766Scarlsonj 	return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml",
281766Scarlsonj 	    zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN);
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate /*ARGSUSED*/
2850Sstevel@tonic-gate static void
zonecfg_error_func(void * ctx,const char * msg,...)2860Sstevel@tonic-gate zonecfg_error_func(void *ctx, const char *msg, ...)
2870Sstevel@tonic-gate {
2880Sstevel@tonic-gate 	/*
2890Sstevel@tonic-gate 	 * This function does nothing by design.  Its purpose is to prevent
2900Sstevel@tonic-gate 	 * libxml from dumping unwanted messages to stdout/stderr.
2910Sstevel@tonic-gate 	 */
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate zone_dochandle_t
zonecfg_init_handle(void)2950Sstevel@tonic-gate zonecfg_init_handle(void)
2960Sstevel@tonic-gate {
297565Sdp 	zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle));
2980Sstevel@tonic-gate 	if (handle == NULL) {
2990Sstevel@tonic-gate 		errno = Z_NOMEM;
3000Sstevel@tonic-gate 		return (NULL);
3010Sstevel@tonic-gate 	}
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	/* generic libxml initialization */
30411318SJordan.Vaughan@Sun.com 	(void) xmlLineNumbersDefault(1);
3050Sstevel@tonic-gate 	xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
3060Sstevel@tonic-gate 	xmlDoValidityCheckingDefaultValue = 1;
3070Sstevel@tonic-gate 	(void) xmlKeepBlanksDefault(0);
3080Sstevel@tonic-gate 	xmlGetWarningsDefaultValue = 0;
3090Sstevel@tonic-gate 	xmlSetGenericErrorFunc(NULL, zonecfg_error_func);
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	return (handle);
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate int
zonecfg_check_handle(zone_dochandle_t handle)3150Sstevel@tonic-gate zonecfg_check_handle(zone_dochandle_t handle)
3160Sstevel@tonic-gate {
3170Sstevel@tonic-gate 	if (handle == NULL || handle->zone_dh_doc == NULL)
3180Sstevel@tonic-gate 		return (Z_BAD_HANDLE);
3190Sstevel@tonic-gate 	return (Z_OK);
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate void
zonecfg_fini_handle(zone_dochandle_t handle)3230Sstevel@tonic-gate zonecfg_fini_handle(zone_dochandle_t handle)
3240Sstevel@tonic-gate {
3250Sstevel@tonic-gate 	if (zonecfg_check_handle(handle) == Z_OK)
3260Sstevel@tonic-gate 		xmlFreeDoc(handle->zone_dh_doc);
3270Sstevel@tonic-gate 	if (handle != NULL)
3280Sstevel@tonic-gate 		free(handle);
3290Sstevel@tonic-gate }
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate static int
zonecfg_destroy_impl(char * filename)3320Sstevel@tonic-gate zonecfg_destroy_impl(char *filename)
3330Sstevel@tonic-gate {
3340Sstevel@tonic-gate 	if (unlink(filename) == -1) {
3350Sstevel@tonic-gate 		if (errno == EACCES)
3360Sstevel@tonic-gate 			return (Z_ACCES);
3370Sstevel@tonic-gate 		if (errno == ENOENT)
3380Sstevel@tonic-gate 			return (Z_NO_ZONE);
3390Sstevel@tonic-gate 		return (Z_MISC_FS);
3400Sstevel@tonic-gate 	}
3410Sstevel@tonic-gate 	return (Z_OK);
3420Sstevel@tonic-gate }
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate int
zonecfg_destroy(const char * zonename,boolean_t force)345565Sdp zonecfg_destroy(const char *zonename, boolean_t force)
3460Sstevel@tonic-gate {
3470Sstevel@tonic-gate 	char path[MAXPATHLEN];
348565Sdp 	struct zoneent ze;
349565Sdp 	int err, state_err;
350565Sdp 	zone_state_t state;
3510Sstevel@tonic-gate 
352766Scarlsonj 	if (!config_file_path(zonename, path))
353766Scarlsonj 		return (Z_MISC_FS);
354565Sdp 
355565Sdp 	state_err = zone_get_state((char *)zonename, &state);
356565Sdp 	err = access(path, W_OK);
357565Sdp 
358565Sdp 	/*
359565Sdp 	 * If there is no file, and no index entry, reliably indicate that no
360565Sdp 	 * such zone exists.
361565Sdp 	 */
362565Sdp 	if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT))
363565Sdp 		return (Z_NO_ZONE);
364565Sdp 
365565Sdp 	/*
366565Sdp 	 * Handle any other filesystem related errors (except if the XML
367565Sdp 	 * file is missing, which we treat silently), unless we're forcing,
368565Sdp 	 * in which case we plow on.
369565Sdp 	 */
370565Sdp 	if (err == -1 && errno != ENOENT) {
371565Sdp 		if (errno == EACCES)
372565Sdp 			return (Z_ACCES);
373565Sdp 		else if (!force)
374565Sdp 			return (Z_MISC_FS);
375565Sdp 	}
376565Sdp 
377565Sdp 	if (state > ZONE_STATE_INSTALLED)
378565Sdp 		return (Z_BAD_ZONE_STATE);
379565Sdp 
380565Sdp 	if (!force && state > ZONE_STATE_CONFIGURED)
381565Sdp 		return (Z_BAD_ZONE_STATE);
382565Sdp 
383565Sdp 	/*
384565Sdp 	 * Index deletion succeeds even if the entry doesn't exist.  So this
385565Sdp 	 * will fail only if we've had some more severe problem.
386565Sdp 	 */
387565Sdp 	bzero(&ze, sizeof (ze));
388565Sdp 	(void) strlcpy(ze.zone_name, zonename, sizeof (ze.zone_name));
389565Sdp 	if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK)
390565Sdp 		if (!force)
391565Sdp 			return (err);
392565Sdp 
393565Sdp 	err = zonecfg_destroy_impl(path);
394565Sdp 
395565Sdp 	/*
396565Sdp 	 * Treat failure to find the XML file silently, since, well, it's
397565Sdp 	 * gone, and with the index file cleaned up, we're done.
398565Sdp 	 */
399565Sdp 	if (err == Z_OK || err == Z_NO_ZONE)
400565Sdp 		return (Z_OK);
401565Sdp 	return (err);
4020Sstevel@tonic-gate }
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate int
zonecfg_destroy_snapshot(const char * zonename)405766Scarlsonj zonecfg_destroy_snapshot(const char *zonename)
4060Sstevel@tonic-gate {
4070Sstevel@tonic-gate 	char path[MAXPATHLEN];
4080Sstevel@tonic-gate 
409766Scarlsonj 	if (!snap_file_path(zonename, path))
410766Scarlsonj 		return (Z_MISC_FS);
4110Sstevel@tonic-gate 	return (zonecfg_destroy_impl(path));
4120Sstevel@tonic-gate }
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate static int
getroot(zone_dochandle_t handle,xmlNodePtr * root)415228Sdp getroot(zone_dochandle_t handle, xmlNodePtr *root)
4160Sstevel@tonic-gate {
4170Sstevel@tonic-gate 	if (zonecfg_check_handle(handle) == Z_BAD_HANDLE)
4180Sstevel@tonic-gate 		return (Z_BAD_HANDLE);
4190Sstevel@tonic-gate 
420228Sdp 	*root = xmlDocGetRootElement(handle->zone_dh_doc);
421228Sdp 
422228Sdp 	if (*root == NULL)
4230Sstevel@tonic-gate 		return (Z_EMPTY_DOCUMENT);
424228Sdp 
425228Sdp 	if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE))
4260Sstevel@tonic-gate 		return (Z_WRONG_DOC_TYPE);
427228Sdp 
428228Sdp 	return (Z_OK);
429228Sdp }
430228Sdp 
431228Sdp static int
operation_prep(zone_dochandle_t handle)432228Sdp operation_prep(zone_dochandle_t handle)
433228Sdp {
434228Sdp 	xmlNodePtr root;
435228Sdp 	int err;
436228Sdp 
437228Sdp 	if ((err = getroot(handle, &root)) != 0)
438228Sdp 		return (err);
439228Sdp 
440228Sdp 	handle->zone_dh_cur = root;
441228Sdp 	handle->zone_dh_top = root;
442228Sdp 	return (Z_OK);
443228Sdp }
444228Sdp 
445228Sdp static int
fetchprop(xmlNodePtr cur,const xmlChar * propname,char * dst,size_t dstsize)4461645Scomay fetchprop(xmlNodePtr cur, const xmlChar *propname, char *dst, size_t dstsize)
4471645Scomay {
4481645Scomay 	xmlChar *property;
4491645Scomay 	size_t srcsize;
4501645Scomay 
4511645Scomay 	if ((property = xmlGetProp(cur, propname)) == NULL)
4521645Scomay 		return (Z_BAD_PROPERTY);
4531645Scomay 	srcsize = strlcpy(dst, (char *)property, dstsize);
4541645Scomay 	xmlFree(property);
4551645Scomay 	if (srcsize >= dstsize)
4561645Scomay 		return (Z_TOO_BIG);
4571645Scomay 	return (Z_OK);
4581645Scomay }
4591645Scomay 
4601645Scomay static int
fetch_alloc_prop(xmlNodePtr cur,const xmlChar * propname,char ** dst)4611645Scomay fetch_alloc_prop(xmlNodePtr cur, const xmlChar *propname, char **dst)
4621645Scomay {
4631645Scomay 	xmlChar *property;
4641645Scomay 
4651645Scomay 	if ((property = xmlGetProp(cur, propname)) == NULL)
4661645Scomay 		return (Z_BAD_PROPERTY);
4671645Scomay 	if ((*dst = strdup((char *)property)) == NULL) {
4681645Scomay 		xmlFree(property);
4691645Scomay 		return (Z_NOMEM);
4701645Scomay 	}
4711645Scomay 	xmlFree(property);
4721645Scomay 	return (Z_OK);
4731645Scomay }
4741645Scomay 
4751645Scomay static int
getrootattr(zone_dochandle_t handle,const xmlChar * propname,char * propval,size_t propsize)476228Sdp getrootattr(zone_dochandle_t handle, const xmlChar *propname,
477228Sdp     char *propval, size_t propsize)
478228Sdp {
479228Sdp 	xmlNodePtr root;
480228Sdp 	int err;
481228Sdp 
482228Sdp 	if ((err = getroot(handle, &root)) != 0)
483228Sdp 		return (err);
484228Sdp 
4851645Scomay 	return (fetchprop(root, propname, propval, propsize));
4861645Scomay }
4871645Scomay 
4881645Scomay static int
get_alloc_rootattr(zone_dochandle_t handle,const xmlChar * propname,char ** propval)4891645Scomay get_alloc_rootattr(zone_dochandle_t handle, const xmlChar *propname,
4901645Scomay     char **propval)
4911645Scomay {
4921645Scomay 	xmlNodePtr root;
4931645Scomay 	int err;
4941645Scomay 
4951645Scomay 	if ((err = getroot(handle, &root)) != 0)
4961645Scomay 		return (err);
4971645Scomay 
4981645Scomay 	return (fetch_alloc_prop(root, propname, propval));
499228Sdp }
500228Sdp 
501228Sdp static int
setrootattr(zone_dochandle_t handle,const xmlChar * propname,const char * propval)502766Scarlsonj setrootattr(zone_dochandle_t handle, const xmlChar *propname,
503766Scarlsonj     const char *propval)
504228Sdp {
505228Sdp 	int err;
506228Sdp 	xmlNodePtr root;
507228Sdp 
508228Sdp 	if ((err = getroot(handle, &root)) != Z_OK)
509228Sdp 		return (err);
510228Sdp 
5113247Sgjelinek 	/*
5123247Sgjelinek 	 * If we get a null propval remove the property (ignore return since it
5133247Sgjelinek 	 * may not be set to begin with).
5143247Sgjelinek 	 */
5153247Sgjelinek 	if (propval == NULL) {
5163247Sgjelinek 		(void) xmlUnsetProp(root, propname);
5173247Sgjelinek 	} else {
5183247Sgjelinek 		if (xmlSetProp(root, propname, (const xmlChar *) propval)
5193247Sgjelinek 		    == NULL)
5203247Sgjelinek 			return (Z_INVAL);
5213247Sgjelinek 	}
5220Sstevel@tonic-gate 	return (Z_OK);
5230Sstevel@tonic-gate }
5240Sstevel@tonic-gate 
525565Sdp static void
addcomment(zone_dochandle_t handle,const char * comment)526565Sdp addcomment(zone_dochandle_t handle, const char *comment)
527565Sdp {
528565Sdp 	xmlNodePtr node;
529565Sdp 	node = xmlNewComment((xmlChar *) comment);
530565Sdp 
531565Sdp 	if (node != NULL)
532565Sdp 		(void) xmlAddPrevSibling(handle->zone_dh_top, node);
533565Sdp }
534565Sdp 
535565Sdp static void
stripcomments(zone_dochandle_t handle)536565Sdp stripcomments(zone_dochandle_t handle)
537565Sdp {
538565Sdp 	xmlDocPtr top;
539565Sdp 	xmlNodePtr child, next;
540565Sdp 
541565Sdp 	top = handle->zone_dh_doc;
542565Sdp 	for (child = top->xmlChildrenNode; child != NULL; child = next) {
543565Sdp 		next = child->next;
544565Sdp 		if (child->name == NULL)
545565Sdp 			continue;
546565Sdp 		if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) {
547565Sdp 			next = child->next;
548565Sdp 			xmlUnlinkNode(child);
549565Sdp 			xmlFreeNode(child);
550565Sdp 		}
551565Sdp 	}
552565Sdp }
553565Sdp 
5541507Sgjelinek static void
strip_sw_inv(zone_dochandle_t handle)5551507Sgjelinek strip_sw_inv(zone_dochandle_t handle)
5561507Sgjelinek {
5571507Sgjelinek 	xmlNodePtr root, child, next;
5581507Sgjelinek 
5591507Sgjelinek 	root = xmlDocGetRootElement(handle->zone_dh_doc);
5601507Sgjelinek 	for (child = root->xmlChildrenNode; child != NULL; child = next) {
5611507Sgjelinek 		next = child->next;
5621507Sgjelinek 		if (child->name == NULL)
5631507Sgjelinek 			continue;
5641507Sgjelinek 		if (xmlStrcmp(child->name, DTD_ELEM_PACKAGE) == 0 ||
5651507Sgjelinek 		    xmlStrcmp(child->name, DTD_ELEM_PATCH) == 0) {
5661507Sgjelinek 			next = child->next;
5671507Sgjelinek 			xmlUnlinkNode(child);
5681507Sgjelinek 			xmlFreeNode(child);
5691507Sgjelinek 		}
5701507Sgjelinek 	}
5711507Sgjelinek }
5721507Sgjelinek 
5730Sstevel@tonic-gate static int
zonecfg_get_handle_impl(const char * zonename,const char * filename,zone_dochandle_t handle)574766Scarlsonj zonecfg_get_handle_impl(const char *zonename, const char *filename,
575766Scarlsonj     zone_dochandle_t handle)
5760Sstevel@tonic-gate {
5770Sstevel@tonic-gate 	xmlValidCtxtPtr cvp;
5780Sstevel@tonic-gate 	struct stat statbuf;
5790Sstevel@tonic-gate 	int valid;
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 	if (zonename == NULL)
5820Sstevel@tonic-gate 		return (Z_NO_ZONE);
5832712Snn35248 
5840Sstevel@tonic-gate 	if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) {
5850Sstevel@tonic-gate 		/* distinguish file not found vs. found but not parsed */
5860Sstevel@tonic-gate 		if (stat(filename, &statbuf) == 0)
5870Sstevel@tonic-gate 			return (Z_INVALID_DOCUMENT);
5880Sstevel@tonic-gate 		return (Z_NO_ZONE);
5890Sstevel@tonic-gate 	}
5900Sstevel@tonic-gate 	if ((cvp = xmlNewValidCtxt()) == NULL)
5910Sstevel@tonic-gate 		return (Z_NOMEM);
5920Sstevel@tonic-gate 	cvp->error = zonecfg_error_func;
5930Sstevel@tonic-gate 	cvp->warning = zonecfg_error_func;
5940Sstevel@tonic-gate 	valid = xmlValidateDocument(cvp, handle->zone_dh_doc);
5950Sstevel@tonic-gate 	xmlFreeValidCtxt(cvp);
5960Sstevel@tonic-gate 	if (valid == 0)
5970Sstevel@tonic-gate 		return (Z_INVALID_DOCUMENT);
598565Sdp 
5990Sstevel@tonic-gate 	/* delete any comments such as inherited Sun copyright / ident str */
600565Sdp 	stripcomments(handle);
6010Sstevel@tonic-gate 	return (Z_OK);
6020Sstevel@tonic-gate }
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate int
zonecfg_get_handle(const char * zonename,zone_dochandle_t handle)605766Scarlsonj zonecfg_get_handle(const char *zonename, zone_dochandle_t handle)
6060Sstevel@tonic-gate {
6070Sstevel@tonic-gate 	char path[MAXPATHLEN];
6080Sstevel@tonic-gate 
609766Scarlsonj 	if (!config_file_path(zonename, path))
610766Scarlsonj 		return (Z_MISC_FS);
611565Sdp 	handle->zone_dh_newzone = B_FALSE;
612565Sdp 
6130Sstevel@tonic-gate 	return (zonecfg_get_handle_impl(zonename, path, handle));
6140Sstevel@tonic-gate }
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate int
zonecfg_get_attach_handle(const char * path,const char * fname,const char * zonename,boolean_t preserve_sw,zone_dochandle_t handle)6177257Sgjelinek zonecfg_get_attach_handle(const char *path, const char *fname,
6187257Sgjelinek     const char *zonename, boolean_t preserve_sw, zone_dochandle_t handle)
6191507Sgjelinek {
6201507Sgjelinek 	char		migpath[MAXPATHLEN];
6211507Sgjelinek 	int		err;
6221507Sgjelinek 	struct stat	buf;
6231507Sgjelinek 
6241507Sgjelinek 	if (snprintf(migpath, sizeof (migpath), "%s/root", path) >=
6251507Sgjelinek 	    sizeof (migpath))
6261507Sgjelinek 		return (Z_NOMEM);
6271507Sgjelinek 
6281507Sgjelinek 	if (stat(migpath, &buf) == -1 || !S_ISDIR(buf.st_mode))
6291507Sgjelinek 		return (Z_NO_ZONE);
6301507Sgjelinek 
6317257Sgjelinek 	if (snprintf(migpath, sizeof (migpath), "%s/%s", path, fname) >=
6321507Sgjelinek 	    sizeof (migpath))
6331507Sgjelinek 		return (Z_NOMEM);
6341507Sgjelinek 
6351507Sgjelinek 	if ((err = zonecfg_get_handle_impl(zonename, migpath, handle)) != Z_OK)
6361507Sgjelinek 		return (err);
6371507Sgjelinek 
6381507Sgjelinek 	if (!preserve_sw)
6391507Sgjelinek 		strip_sw_inv(handle);
6401507Sgjelinek 
6411507Sgjelinek 	handle->zone_dh_newzone = B_TRUE;
6421507Sgjelinek 	if ((err = setrootattr(handle, DTD_ATTR_ZONEPATH, path)) != Z_OK)
6431507Sgjelinek 		return (err);
6441507Sgjelinek 
6451507Sgjelinek 	return (setrootattr(handle, DTD_ATTR_NAME, zonename));
6461507Sgjelinek }
6471507Sgjelinek 
6481507Sgjelinek int
zonecfg_get_snapshot_handle(const char * zonename,zone_dochandle_t handle)649766Scarlsonj zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle)
6500Sstevel@tonic-gate {
6510Sstevel@tonic-gate 	char path[MAXPATHLEN];
6520Sstevel@tonic-gate 
653766Scarlsonj 	if (!snap_file_path(zonename, path))
654766Scarlsonj 		return (Z_MISC_FS);
655565Sdp 	handle->zone_dh_newzone = B_FALSE;
6560Sstevel@tonic-gate 	return (zonecfg_get_handle_impl(zonename, path, handle));
6570Sstevel@tonic-gate }
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate int
zonecfg_get_template_handle(const char * template,const char * zonename,zone_dochandle_t handle)660766Scarlsonj zonecfg_get_template_handle(const char *template, const char *zonename,
661565Sdp     zone_dochandle_t handle)
662565Sdp {
663565Sdp 	char path[MAXPATHLEN];
664565Sdp 	int err;
665565Sdp 
666766Scarlsonj 	if (!config_file_path(template, path))
667766Scarlsonj 		return (Z_MISC_FS);
668565Sdp 
669565Sdp 	if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK)
670565Sdp 		return (err);
671565Sdp 	handle->zone_dh_newzone = B_TRUE;
672565Sdp 	return (setrootattr(handle, DTD_ATTR_NAME, zonename));
673565Sdp }
674565Sdp 
6752712Snn35248 int
zonecfg_get_xml_handle(const char * path,zone_dochandle_t handle)6762712Snn35248 zonecfg_get_xml_handle(const char *path, zone_dochandle_t handle)
6772712Snn35248 {
6782712Snn35248 	struct stat buf;
6792712Snn35248 	int err;
6802712Snn35248 
6812712Snn35248 	if (stat(path, &buf) == -1)
6822712Snn35248 		return (Z_MISC_FS);
6832712Snn35248 
6842712Snn35248 	if ((err = zonecfg_get_handle_impl("xml", path, handle)) != Z_OK)
6852712Snn35248 		return (err);
6862712Snn35248 	handle->zone_dh_newzone = B_TRUE;
6872712Snn35248 	return (Z_OK);
6882712Snn35248 }
6892712Snn35248 
6902078Sgjelinek /*
6912078Sgjelinek  * Initialize two handles from the manifest read on fd.  The rem_handle
6922078Sgjelinek  * is initialized from the input file, including the sw inventory.  The
6932078Sgjelinek  * local_handle is initialized with the same zone configuration but with
6942078Sgjelinek  * no sw inventory.
6952078Sgjelinek  */
6962078Sgjelinek int
zonecfg_attach_manifest(int fd,zone_dochandle_t local_handle,zone_dochandle_t rem_handle)6972078Sgjelinek zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle,
6982078Sgjelinek     zone_dochandle_t rem_handle)
6992078Sgjelinek {
7002078Sgjelinek 	xmlValidCtxtPtr cvp;
7012078Sgjelinek 	int valid;
7022078Sgjelinek 
7032078Sgjelinek 	/* load the manifest into the handle for the remote system */
7042078Sgjelinek 	if ((rem_handle->zone_dh_doc = xmlReadFd(fd, NULL, NULL, 0)) == NULL) {
7052078Sgjelinek 		return (Z_INVALID_DOCUMENT);
7062078Sgjelinek 	}
7072078Sgjelinek 	if ((cvp = xmlNewValidCtxt()) == NULL)
7082078Sgjelinek 		return (Z_NOMEM);
7092078Sgjelinek 	cvp->error = zonecfg_error_func;
7102078Sgjelinek 	cvp->warning = zonecfg_error_func;
7112078Sgjelinek 	valid = xmlValidateDocument(cvp, rem_handle->zone_dh_doc);
7122078Sgjelinek 	xmlFreeValidCtxt(cvp);
7132078Sgjelinek 	if (valid == 0)
7142078Sgjelinek 		return (Z_INVALID_DOCUMENT);
7152078Sgjelinek 
7162078Sgjelinek 	/* delete any comments such as inherited Sun copyright / ident str */
7172078Sgjelinek 	stripcomments(rem_handle);
7182078Sgjelinek 
7192078Sgjelinek 	rem_handle->zone_dh_newzone = B_TRUE;
7202078Sgjelinek 	rem_handle->zone_dh_sw_inv = B_TRUE;
7212078Sgjelinek 
7222078Sgjelinek 	/*
7232078Sgjelinek 	 * Now use the remote system handle to generate a local system handle
7242078Sgjelinek 	 * with an identical zones configuration but no sw inventory.
7252078Sgjelinek 	 */
7262078Sgjelinek 	if ((local_handle->zone_dh_doc = xmlCopyDoc(rem_handle->zone_dh_doc,
7272078Sgjelinek 	    1)) == NULL) {
7282078Sgjelinek 		return (Z_INVALID_DOCUMENT);
7292078Sgjelinek 	}
7302078Sgjelinek 
7312078Sgjelinek 	/*
7322078Sgjelinek 	 * We need to re-run xmlValidateDocument on local_handle to properly
7332078Sgjelinek 	 * update the in-core representation of the configuration.
7342078Sgjelinek 	 */
7352078Sgjelinek 	if ((cvp = xmlNewValidCtxt()) == NULL)
7362078Sgjelinek 		return (Z_NOMEM);
7372078Sgjelinek 	cvp->error = zonecfg_error_func;
7382078Sgjelinek 	cvp->warning = zonecfg_error_func;
7392078Sgjelinek 	valid = xmlValidateDocument(cvp, local_handle->zone_dh_doc);
7402078Sgjelinek 	xmlFreeValidCtxt(cvp);
7412078Sgjelinek 	if (valid == 0)
7422078Sgjelinek 		return (Z_INVALID_DOCUMENT);
7432078Sgjelinek 
7442078Sgjelinek 	strip_sw_inv(local_handle);
7452078Sgjelinek 
7462078Sgjelinek 	local_handle->zone_dh_newzone = B_TRUE;
7472078Sgjelinek 	local_handle->zone_dh_sw_inv = B_FALSE;
7482078Sgjelinek 
7492078Sgjelinek 	return (Z_OK);
7502078Sgjelinek }
7512078Sgjelinek 
752565Sdp static boolean_t
is_renaming(zone_dochandle_t handle)753565Sdp is_renaming(zone_dochandle_t handle)
754565Sdp {
755565Sdp 	if (handle->zone_dh_newzone)
756565Sdp 		return (B_FALSE);
757565Sdp 	if (strlen(handle->zone_dh_delete_name) > 0)
758565Sdp 		return (B_TRUE);
759565Sdp 	return (B_FALSE);
760565Sdp }
761565Sdp 
762565Sdp static boolean_t
is_new(zone_dochandle_t handle)763565Sdp is_new(zone_dochandle_t handle)
764565Sdp {
765565Sdp 	return (handle->zone_dh_newzone || handle->zone_dh_snapshot);
766565Sdp }
767565Sdp 
768565Sdp static boolean_t
is_snapshot(zone_dochandle_t handle)769565Sdp is_snapshot(zone_dochandle_t handle)
770565Sdp {
771565Sdp 	return (handle->zone_dh_snapshot);
772565Sdp }
773565Sdp 
774565Sdp /*
775565Sdp  * It would be great to be able to use libc's ctype(3c) macros, but we
776565Sdp  * can't, as they are locale sensitive, and it would break our limited thread
777565Sdp  * safety if this routine had to change the app locale on the fly.
778565Sdp  */
779565Sdp int
zonecfg_validate_zonename(const char * zone)780766Scarlsonj zonecfg_validate_zonename(const char *zone)
781565Sdp {
782565Sdp 	int i;
783565Sdp 
784565Sdp 	if (strcmp(zone, GLOBAL_ZONENAME) == 0)
785565Sdp 		return (Z_BOGUS_ZONE_NAME);
786565Sdp 
787565Sdp 	if (strlen(zone) >= ZONENAME_MAX)
788565Sdp 		return (Z_BOGUS_ZONE_NAME);
789565Sdp 
790565Sdp 	if (!((zone[0] >= 'a' && zone[0] <= 'z') ||
791565Sdp 	    (zone[0] >= 'A' && zone[0] <= 'Z') ||
792565Sdp 	    (zone[0] >= '0' && zone[0] <= '9')))
793565Sdp 		return (Z_BOGUS_ZONE_NAME);
794565Sdp 
795565Sdp 	for (i = 1; zone[i] != '\0'; i++) {
796565Sdp 		if (!((zone[i] >= 'a' && zone[i] <= 'z') ||
797565Sdp 		    (zone[i] >= 'A' && zone[i] <= 'Z') ||
798565Sdp 		    (zone[i] >= '0' && zone[i] <= '9') ||
799565Sdp 		    (zone[i] == '-') || (zone[i] == '_') || (zone[i] == '.')))
800565Sdp 			return (Z_BOGUS_ZONE_NAME);
801565Sdp 	}
802565Sdp 
803565Sdp 	return (Z_OK);
804565Sdp }
805565Sdp 
806565Sdp /*
807565Sdp  * Changing the zone name requires us to track both the old and new
808565Sdp  * name of the zone until commit time.
809565Sdp  */
810565Sdp int
zonecfg_get_name(zone_dochandle_t handle,char * name,size_t namesize)8110Sstevel@tonic-gate zonecfg_get_name(zone_dochandle_t handle, char *name, size_t namesize)
8120Sstevel@tonic-gate {
813228Sdp 	return (getrootattr(handle, DTD_ATTR_NAME, name, namesize));
814228Sdp }
815228Sdp 
81612578SGlenn.Faden@Sun.COM static int
insert_admins(zone_dochandle_t handle,char * zonename)81712578SGlenn.Faden@Sun.COM insert_admins(zone_dochandle_t handle, char *zonename)
81812578SGlenn.Faden@Sun.COM {
81912578SGlenn.Faden@Sun.COM 	int err;
82012578SGlenn.Faden@Sun.COM 	struct zone_admintab admintab;
82112578SGlenn.Faden@Sun.COM 
82212578SGlenn.Faden@Sun.COM 	if ((err = zonecfg_setadminent(handle)) != Z_OK) {
82312578SGlenn.Faden@Sun.COM 		return (err);
82412578SGlenn.Faden@Sun.COM 	}
82512578SGlenn.Faden@Sun.COM 	while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
82612578SGlenn.Faden@Sun.COM 		err = zonecfg_insert_userauths(handle,
82712578SGlenn.Faden@Sun.COM 		    admintab.zone_admin_user, zonename);
82812578SGlenn.Faden@Sun.COM 		if (err != Z_OK) {
82912578SGlenn.Faden@Sun.COM 			(void) zonecfg_endadminent(handle);
83012578SGlenn.Faden@Sun.COM 			return (err);
83112578SGlenn.Faden@Sun.COM 		}
83212578SGlenn.Faden@Sun.COM 	}
83312578SGlenn.Faden@Sun.COM 	(void) zonecfg_endadminent(handle);
83412578SGlenn.Faden@Sun.COM 	return (Z_OK);
83512578SGlenn.Faden@Sun.COM }
83612578SGlenn.Faden@Sun.COM 
837228Sdp int
zonecfg_set_name(zone_dochandle_t handle,char * name)838228Sdp zonecfg_set_name(zone_dochandle_t handle, char *name)
839228Sdp {
840565Sdp 	zone_state_t state;
841565Sdp 	char curname[ZONENAME_MAX], old_delname[ZONENAME_MAX];
842565Sdp 	int err;
843565Sdp 
844565Sdp 	if ((err = getrootattr(handle, DTD_ATTR_NAME, curname,
845565Sdp 	    sizeof (curname))) != Z_OK)
846565Sdp 		return (err);
847565Sdp 
848565Sdp 	if (strcmp(name, curname) == 0)
849565Sdp 		return (Z_OK);
850565Sdp 
851565Sdp 	/*
852565Sdp 	 * Switching zone names to one beginning with SUNW is not permitted.
853565Sdp 	 */
854565Sdp 	if (strncmp(name, "SUNW", 4) == 0)
855565Sdp 		return (Z_BOGUS_ZONE_NAME);
856565Sdp 
857565Sdp 	if ((err = zonecfg_validate_zonename(name)) != Z_OK)
858565Sdp 		return (err);
859565Sdp 
860565Sdp 	/*
861565Sdp 	 * Setting the name back to the original name (effectively a revert of
862565Sdp 	 * the name) is fine.  But if we carry on, we'll falsely identify the
863565Sdp 	 * name as "in use," so special case here.
864565Sdp 	 */
865565Sdp 	if (strcmp(name, handle->zone_dh_delete_name) == 0) {
866565Sdp 		err = setrootattr(handle, DTD_ATTR_NAME, name);
867565Sdp 		handle->zone_dh_delete_name[0] = '\0';
868565Sdp 		return (err);
869565Sdp 	}
870565Sdp 
871565Sdp 	/* Check to see if new name chosen is already in use */
872565Sdp 	if (zone_get_state(name, &state) != Z_NO_ZONE)
873565Sdp 		return (Z_NAME_IN_USE);
874565Sdp 
875565Sdp 	/*
876565Sdp 	 * If this isn't already "new" or in a renaming transition, then
877565Sdp 	 * we're initiating a rename here; so stash the "delete name"
878565Sdp 	 * (i.e. the name of the zone we'll be removing) for the rename.
879565Sdp 	 */
880565Sdp 	(void) strlcpy(old_delname, handle->zone_dh_delete_name,
881565Sdp 	    sizeof (old_delname));
882565Sdp 	if (!is_new(handle) && !is_renaming(handle)) {
883565Sdp 		/*
884565Sdp 		 * Name change is allowed only when the zone we're altering
885565Sdp 		 * is not ready or running.
886565Sdp 		 */
887565Sdp 		err = zone_get_state(curname, &state);
888565Sdp 		if (err == Z_OK) {
889565Sdp 			if (state > ZONE_STATE_INSTALLED)
890565Sdp 				return (Z_BAD_ZONE_STATE);
891565Sdp 		} else if (err != Z_NO_ZONE) {
892565Sdp 			return (err);
893565Sdp 		}
894565Sdp 
895565Sdp 		(void) strlcpy(handle->zone_dh_delete_name, curname,
896565Sdp 		    sizeof (handle->zone_dh_delete_name));
897565Sdp 		assert(is_renaming(handle));
898565Sdp 	} else if (is_renaming(handle)) {
899565Sdp 		err = zone_get_state(handle->zone_dh_delete_name, &state);
900565Sdp 		if (err == Z_OK) {
901565Sdp 			if (state > ZONE_STATE_INSTALLED)
902565Sdp 				return (Z_BAD_ZONE_STATE);
903565Sdp 		} else if (err != Z_NO_ZONE) {
904565Sdp 			return (err);
905565Sdp 		}
906565Sdp 	}
907565Sdp 
908565Sdp 	if ((err = setrootattr(handle, DTD_ATTR_NAME, name)) != Z_OK) {
909565Sdp 		/*
910565Sdp 		 * Restore the deletename to whatever it was at the
911565Sdp 		 * top of the routine, since we've had a failure.
912565Sdp 		 */
913565Sdp 		(void) strlcpy(handle->zone_dh_delete_name, old_delname,
914565Sdp 		    sizeof (handle->zone_dh_delete_name));
915565Sdp 		return (err);
916565Sdp 	}
917565Sdp 
91812578SGlenn.Faden@Sun.COM 	/*
91912578SGlenn.Faden@Sun.COM 	 * Record the old admins from the old zonename
92012578SGlenn.Faden@Sun.COM 	 * so that they can be deleted when the operation is committed.
92112578SGlenn.Faden@Sun.COM 	 */
92212578SGlenn.Faden@Sun.COM 	if ((err = insert_admins(handle, curname)) != Z_OK)
92312578SGlenn.Faden@Sun.COM 		return (err);
92412578SGlenn.Faden@Sun.COM 	else
92512578SGlenn.Faden@Sun.COM 		return (Z_OK);
926228Sdp }
927228Sdp 
928228Sdp int
zonecfg_get_zonepath(zone_dochandle_t handle,char * path,size_t pathsize)929228Sdp zonecfg_get_zonepath(zone_dochandle_t handle, char *path, size_t pathsize)
930228Sdp {
931766Scarlsonj 	size_t len;
932766Scarlsonj 
933766Scarlsonj 	if ((len = strlcpy(path, zonecfg_root, pathsize)) >= pathsize)
934766Scarlsonj 		return (Z_TOO_BIG);
935766Scarlsonj 	return (getrootattr(handle, DTD_ATTR_ZONEPATH, path + len,
936766Scarlsonj 	    pathsize - len));
937228Sdp }
938228Sdp 
939228Sdp int
zonecfg_set_zonepath(zone_dochandle_t handle,char * zonepath)940228Sdp zonecfg_set_zonepath(zone_dochandle_t handle, char *zonepath)
941228Sdp {
9422303Scarlsonj 	size_t len;
94312715SSusan.Kamm-Worrell@Sun.COM 	char *modpath, *copy_mp, *curr_mp;	/* modified path ptrs */
94412715SSusan.Kamm-Worrell@Sun.COM 	char last_copied;
94512715SSusan.Kamm-Worrell@Sun.COM 	int ret;
94612715SSusan.Kamm-Worrell@Sun.COM 
94712715SSusan.Kamm-Worrell@Sun.COM 	/*
94812715SSusan.Kamm-Worrell@Sun.COM 	 * Collapse multiple contiguous slashes and remove trailing slash.
94912715SSusan.Kamm-Worrell@Sun.COM 	 */
95012715SSusan.Kamm-Worrell@Sun.COM 	modpath = strdup(zonepath);
95112715SSusan.Kamm-Worrell@Sun.COM 	if (modpath == NULL)
95212715SSusan.Kamm-Worrell@Sun.COM 		return (Z_NOMEM);
95312715SSusan.Kamm-Worrell@Sun.COM 	last_copied = '\0';
95412715SSusan.Kamm-Worrell@Sun.COM 	for (copy_mp = curr_mp = modpath; *curr_mp != '\0'; curr_mp++) {
95512715SSusan.Kamm-Worrell@Sun.COM 		if (*curr_mp != '/' || last_copied != '/') {
95612715SSusan.Kamm-Worrell@Sun.COM 			last_copied = *copy_mp = *curr_mp;
95712715SSusan.Kamm-Worrell@Sun.COM 			copy_mp++;
95812715SSusan.Kamm-Worrell@Sun.COM 		}
95912715SSusan.Kamm-Worrell@Sun.COM 	}
96012715SSusan.Kamm-Worrell@Sun.COM 	if (last_copied == '/')
96112715SSusan.Kamm-Worrell@Sun.COM 		copy_mp--;
96212715SSusan.Kamm-Worrell@Sun.COM 	*copy_mp = '\0';
9632303Scarlsonj 
9642303Scarlsonj 	/*
9652303Scarlsonj 	 * The user deals in absolute paths in the running global zone, but the
9662303Scarlsonj 	 * internal configuration files deal with boot environment relative
9672303Scarlsonj 	 * paths.  Strip out the alternate root when specified.
9682303Scarlsonj 	 */
9692303Scarlsonj 	len = strlen(zonecfg_root);
97012715SSusan.Kamm-Worrell@Sun.COM 	if (strncmp(modpath, zonecfg_root, len) != 0 || modpath[len] != '/') {
97112715SSusan.Kamm-Worrell@Sun.COM 		free(modpath);
9722303Scarlsonj 		return (Z_BAD_PROPERTY);
97312715SSusan.Kamm-Worrell@Sun.COM 	}
97412715SSusan.Kamm-Worrell@Sun.COM 	curr_mp = modpath + len;
97512715SSusan.Kamm-Worrell@Sun.COM 	ret = setrootattr(handle, DTD_ATTR_ZONEPATH, curr_mp);
97612715SSusan.Kamm-Worrell@Sun.COM 	free(modpath);
97712715SSusan.Kamm-Worrell@Sun.COM 	return (ret);
978228Sdp }
979228Sdp 
98010943SEdward.Pilatowicz@Sun.COM static int
i_zonecfg_get_brand(zone_dochandle_t handle,char * brand,size_t brandsize,boolean_t default_query)98110943SEdward.Pilatowicz@Sun.COM i_zonecfg_get_brand(zone_dochandle_t handle, char *brand, size_t brandsize,
98210943SEdward.Pilatowicz@Sun.COM     boolean_t default_query)
9832712Snn35248 {
9842712Snn35248 	int ret, sz;
9852712Snn35248 
9862712Snn35248 	ret = getrootattr(handle, DTD_ATTR_BRAND, brand, brandsize);
9872712Snn35248 
98810943SEdward.Pilatowicz@Sun.COM 	/*
98910943SEdward.Pilatowicz@Sun.COM 	 * If the lookup failed, or succeeded in finding a non-null brand
99010943SEdward.Pilatowicz@Sun.COM 	 * string then return.
99110943SEdward.Pilatowicz@Sun.COM 	 */
99210943SEdward.Pilatowicz@Sun.COM 	if (ret != Z_OK || brand[0] != '\0')
99310943SEdward.Pilatowicz@Sun.COM 		return (ret);
99410943SEdward.Pilatowicz@Sun.COM 
99510943SEdward.Pilatowicz@Sun.COM 	if (!default_query) {
99610943SEdward.Pilatowicz@Sun.COM 		/* If the zone has no brand, it is the default brand. */
99710953SEdward.Pilatowicz@Sun.COM 		return (zonecfg_default_brand(brand, brandsize));
99810943SEdward.Pilatowicz@Sun.COM 	}
99910943SEdward.Pilatowicz@Sun.COM 
100010943SEdward.Pilatowicz@Sun.COM 	/* if SUNWdefault didn't specify a brand, fallback to "native" */
100110943SEdward.Pilatowicz@Sun.COM 	sz = strlcpy(brand, NATIVE_BRAND_NAME, brandsize);
100210943SEdward.Pilatowicz@Sun.COM 	if (sz >= brandsize)
100310943SEdward.Pilatowicz@Sun.COM 		return (Z_TOO_BIG);
100410943SEdward.Pilatowicz@Sun.COM 	return (Z_OK);
100510943SEdward.Pilatowicz@Sun.COM }
100610943SEdward.Pilatowicz@Sun.COM 
100710943SEdward.Pilatowicz@Sun.COM int
zonecfg_get_brand(zone_dochandle_t handle,char * brand,size_t brandsize)100810943SEdward.Pilatowicz@Sun.COM zonecfg_get_brand(zone_dochandle_t handle, char *brand, size_t brandsize)
100910943SEdward.Pilatowicz@Sun.COM {
101010943SEdward.Pilatowicz@Sun.COM 	return (i_zonecfg_get_brand(handle, brand, brandsize, B_FALSE));
10112712Snn35248 }
10122712Snn35248 
10132712Snn35248 int
zonecfg_set_brand(zone_dochandle_t handle,char * brand)10142712Snn35248 zonecfg_set_brand(zone_dochandle_t handle, char *brand)
10152712Snn35248 {
10162712Snn35248 	return (setrootattr(handle, DTD_ATTR_BRAND, brand));
10172712Snn35248 }
10182712Snn35248 
10192712Snn35248 int
zonecfg_get_autoboot(zone_dochandle_t handle,boolean_t * autoboot)1020228Sdp zonecfg_get_autoboot(zone_dochandle_t handle, boolean_t *autoboot)
1021228Sdp {
1022228Sdp 	char autobootstr[DTD_ENTITY_BOOL_LEN];
1023228Sdp 	int ret;
1024228Sdp 
1025228Sdp 	if ((ret = getrootattr(handle, DTD_ATTR_AUTOBOOT, autobootstr,
1026228Sdp 	    sizeof (autobootstr))) != Z_OK)
1027228Sdp 		return (ret);
1028228Sdp 
1029228Sdp 	if (strcmp(autobootstr, DTD_ENTITY_TRUE) == 0)
1030228Sdp 		*autoboot = B_TRUE;
1031228Sdp 	else if (strcmp(autobootstr, DTD_ENTITY_FALSE) == 0)
1032228Sdp 		*autoboot = B_FALSE;
1033228Sdp 	else
1034228Sdp 		ret = Z_BAD_PROPERTY;
1035228Sdp 	return (ret);
1036228Sdp }
1037228Sdp 
1038228Sdp int
zonecfg_set_autoboot(zone_dochandle_t handle,boolean_t autoboot)1039228Sdp zonecfg_set_autoboot(zone_dochandle_t handle, boolean_t autoboot)
1040228Sdp {
1041228Sdp 	return (setrootattr(handle, DTD_ATTR_AUTOBOOT,
1042228Sdp 	    autoboot ? DTD_ENTITY_TRUE : DTD_ENTITY_FALSE));
1043228Sdp }
1044228Sdp 
1045228Sdp int
zonecfg_get_pool(zone_dochandle_t handle,char * pool,size_t poolsize)1046228Sdp zonecfg_get_pool(zone_dochandle_t handle, char *pool, size_t poolsize)
1047228Sdp {
1048228Sdp 	return (getrootattr(handle, DTD_ATTR_POOL, pool, poolsize));
1049228Sdp }
1050228Sdp 
1051228Sdp int
zonecfg_set_pool(zone_dochandle_t handle,char * pool)1052228Sdp zonecfg_set_pool(zone_dochandle_t handle, char *pool)
1053228Sdp {
1054228Sdp 	return (setrootattr(handle, DTD_ATTR_POOL, pool));
1055228Sdp }
1056228Sdp 
10571645Scomay int
zonecfg_get_limitpriv(zone_dochandle_t handle,char ** limitpriv)10581645Scomay zonecfg_get_limitpriv(zone_dochandle_t handle, char **limitpriv)
10591645Scomay {
10601645Scomay 	return (get_alloc_rootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv));
10611645Scomay }
10621645Scomay 
10631645Scomay int
zonecfg_set_limitpriv(zone_dochandle_t handle,char * limitpriv)10642267Sdp zonecfg_set_limitpriv(zone_dochandle_t handle, char *limitpriv)
10652267Sdp {
10662267Sdp 	return (setrootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv));
10672267Sdp }
10682267Sdp 
10692267Sdp int
zonecfg_get_bootargs(zone_dochandle_t handle,char * bargs,size_t bargssize)10702267Sdp zonecfg_get_bootargs(zone_dochandle_t handle, char *bargs, size_t bargssize)
10712267Sdp {
10722267Sdp 	return (getrootattr(handle, DTD_ATTR_BOOTARGS, bargs, bargssize));
10732267Sdp }
10742267Sdp 
10752267Sdp int
zonecfg_set_bootargs(zone_dochandle_t handle,char * bargs)10762267Sdp zonecfg_set_bootargs(zone_dochandle_t handle, char *bargs)
10772267Sdp {
10782267Sdp 	return (setrootattr(handle, DTD_ATTR_BOOTARGS, bargs));
10791645Scomay }
10801645Scomay 
10813247Sgjelinek int
zonecfg_get_sched_class(zone_dochandle_t handle,char * sched,size_t schedsize)10823247Sgjelinek zonecfg_get_sched_class(zone_dochandle_t handle, char *sched, size_t schedsize)
10833247Sgjelinek {
10843247Sgjelinek 	return (getrootattr(handle, DTD_ATTR_SCHED, sched, schedsize));
10853247Sgjelinek }
10863247Sgjelinek 
10873247Sgjelinek int
zonecfg_set_sched(zone_dochandle_t handle,char * sched)10883247Sgjelinek zonecfg_set_sched(zone_dochandle_t handle, char *sched)
10893247Sgjelinek {
10903247Sgjelinek 	return (setrootattr(handle, DTD_ATTR_SCHED, sched));
10913247Sgjelinek }
10923247Sgjelinek 
1093228Sdp /*
1094228Sdp  * /etc/zones/index caches a vital piece of information which is also
1095228Sdp  * in the <zonename>.xml file: the path to the zone.  This is for performance,
1096228Sdp  * since we need to walk all zonepath's in order to be able to detect conflicts
1097228Sdp  * (see crosscheck_zonepaths() in the zoneadm command).
1098565Sdp  *
1099565Sdp  * An additional complexity is that when doing a rename, we'd like the entire
1100565Sdp  * index update operation (rename, and potential state changes) to be atomic.
1101565Sdp  * In general, the operation of this function should succeed or fail as
1102565Sdp  * a unit.
1103228Sdp  */
1104228Sdp int
zonecfg_refresh_index_file(zone_dochandle_t handle)1105228Sdp zonecfg_refresh_index_file(zone_dochandle_t handle)
1106228Sdp {
1107228Sdp 	char name[ZONENAME_MAX], zonepath[MAXPATHLEN];
1108228Sdp 	struct zoneent ze;
1109228Sdp 	int err;
1110565Sdp 	int opcode;
1111565Sdp 	char *zn;
1112565Sdp 
1113565Sdp 	bzero(&ze, sizeof (ze));
1114565Sdp 	ze.zone_state = -1;	/* Preserve existing state in index */
1115228Sdp 
1116228Sdp 	if ((err = zonecfg_get_name(handle, name, sizeof (name))) != Z_OK)
1117228Sdp 		return (err);
1118565Sdp 	(void) strlcpy(ze.zone_name, name, sizeof (ze.zone_name));
1119565Sdp 
1120228Sdp 	if ((err = zonecfg_get_zonepath(handle, zonepath,
1121228Sdp 	    sizeof (zonepath))) != Z_OK)
1122228Sdp 		return (err);
11232303Scarlsonj 	(void) strlcpy(ze.zone_path, zonepath + strlen(zonecfg_root),
11242303Scarlsonj 	    sizeof (ze.zone_path));
1125565Sdp 
1126565Sdp 	if (is_renaming(handle)) {
1127565Sdp 		opcode = PZE_MODIFY;
1128565Sdp 		(void) strlcpy(ze.zone_name, handle->zone_dh_delete_name,
1129565Sdp 		    sizeof (ze.zone_name));
1130565Sdp 		(void) strlcpy(ze.zone_newname, name, sizeof (ze.zone_newname));
1131565Sdp 	} else if (is_new(handle)) {
1132565Sdp 		FILE *cookie;
1133565Sdp 		/*
1134565Sdp 		 * Be tolerant of the zone already existing in the index file,
1135565Sdp 		 * since we might be forcibly overwriting an existing
1136565Sdp 		 * configuration with a new one (for example 'create -F'
1137565Sdp 		 * in zonecfg).
1138565Sdp 		 */
1139565Sdp 		opcode = PZE_ADD;
1140565Sdp 		cookie = setzoneent();
1141565Sdp 		while ((zn = getzoneent(cookie)) != NULL) {
1142565Sdp 			if (strcmp(zn, name) == 0) {
1143565Sdp 				opcode = PZE_MODIFY;
1144565Sdp 				free(zn);
1145565Sdp 				break;
1146565Sdp 			}
1147565Sdp 			free(zn);
1148565Sdp 		}
1149565Sdp 		endzoneent(cookie);
1150565Sdp 		ze.zone_state = ZONE_STATE_CONFIGURED;
1151565Sdp 	} else {
1152565Sdp 		opcode = PZE_MODIFY;
1153565Sdp 	}
1154565Sdp 
1155565Sdp 	if ((err = putzoneent(&ze, opcode)) != Z_OK)
1156565Sdp 		return (err);
1157565Sdp 
1158565Sdp 	return (Z_OK);
11590Sstevel@tonic-gate }
11600Sstevel@tonic-gate 
1161565Sdp /*
1162565Sdp  * The goal of this routine is to cause the index file update and the
1163565Sdp  * document save to happen as an atomic operation.  We do the document
1164565Sdp  * first, saving a backup copy using a hard link; if that succeeds, we go
1165565Sdp  * on to the index.  If that fails, we roll the document back into place.
1166565Sdp  *
1167565Sdp  * Strategy:
1168565Sdp  *
1169565Sdp  * New zone 'foo' configuration:
1170565Sdp  * 	Create tmpfile (zonecfg.xxxxxx)
1171565Sdp  * 	Write XML to tmpfile
1172565Sdp  * 	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
1173565Sdp  * 	Add entry to index file
1174565Sdp  * 	If it fails, delete foo.xml, leaving nothing behind.
1175565Sdp  *
1176565Sdp  * Save existing zone 'foo':
1177565Sdp  * 	Make backup of foo.xml -> .backup
1178565Sdp  * 	Create tmpfile (zonecfg.xxxxxx)
1179565Sdp  * 	Write XML to tmpfile
1180565Sdp  * 	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
1181565Sdp  * 	Modify index file as needed
1182565Sdp  * 	If it fails, recover from .backup -> foo.xml
1183565Sdp  *
1184565Sdp  * Rename 'foo' to 'bar':
1185565Sdp  * 	Create tmpfile (zonecfg.xxxxxx)
1186565Sdp  * 	Write XML to tmpfile
1187565Sdp  * 	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml)
1188565Sdp  * 	Add entry for 'bar' to index file, Remove entry for 'foo' (refresh)
1189565Sdp  * 	If it fails, delete bar.xml; foo.xml is left behind.
1190565Sdp  */
11910Sstevel@tonic-gate static int
zonecfg_save_impl(zone_dochandle_t handle,char * filename)11920Sstevel@tonic-gate zonecfg_save_impl(zone_dochandle_t handle, char *filename)
11930Sstevel@tonic-gate {
11940Sstevel@tonic-gate 	char tmpfile[MAXPATHLEN];
1195565Sdp 	char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN];
11962712Snn35248 	int tmpfd, err, valid;
11970Sstevel@tonic-gate 	xmlValidCtxt cvp = { NULL };
1198565Sdp 	boolean_t backup;
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate 	(void) strlcpy(tmpfile, filename, sizeof (tmpfile));
12010Sstevel@tonic-gate 	(void) dirname(tmpfile);
12020Sstevel@tonic-gate 	(void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile));
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 	tmpfd = mkstemp(tmpfile);
12050Sstevel@tonic-gate 	if (tmpfd == -1) {
12060Sstevel@tonic-gate 		(void) unlink(tmpfile);
12070Sstevel@tonic-gate 		return (Z_TEMP_FILE);
12080Sstevel@tonic-gate 	}
12090Sstevel@tonic-gate 	(void) close(tmpfd);
12100Sstevel@tonic-gate 
12110Sstevel@tonic-gate 	cvp.error = zonecfg_error_func;
12120Sstevel@tonic-gate 	cvp.warning = zonecfg_error_func;
12130Sstevel@tonic-gate 
1214565Sdp 	/*
12152712Snn35248 	 * We do a final validation of the document.  Since the library has
12162712Snn35248 	 * malfunctioned if it fails to validate, we follow-up with an
12172712Snn35248 	 * assert() that the doc is valid.
1218565Sdp 	 */
12192712Snn35248 	valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
12202712Snn35248 	assert(valid != 0);
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate 	if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0)
12230Sstevel@tonic-gate 		goto err;
1224565Sdp 
12250Sstevel@tonic-gate 	(void) chmod(tmpfile, 0644);
12260Sstevel@tonic-gate 
1227565Sdp 	/*
1228565Sdp 	 * In the event we are doing a standard save, hard link a copy of the
1229565Sdp 	 * original file in .backup.<pid>.filename so we can restore it if
1230565Sdp 	 * something goes wrong.
1231565Sdp 	 */
1232565Sdp 	if (!is_new(handle) && !is_renaming(handle)) {
1233565Sdp 		backup = B_TRUE;
1234565Sdp 
1235565Sdp 		(void) strlcpy(bakdir, filename, sizeof (bakdir));
1236565Sdp 		(void) strlcpy(bakbase, filename, sizeof (bakbase));
1237565Sdp 		(void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s",
1238565Sdp 		    dirname(bakdir), getpid(), basename(bakbase));
1239565Sdp 
1240565Sdp 		if (link(filename, bakfile) == -1) {
1241565Sdp 			err = errno;
1242565Sdp 			(void) unlink(tmpfile);
1243565Sdp 			if (errno == EACCES)
1244565Sdp 				return (Z_ACCES);
1245565Sdp 			return (Z_MISC_FS);
1246565Sdp 		}
1247565Sdp 	}
1248565Sdp 
1249565Sdp 	/*
1250565Sdp 	 * Move the new document over top of the old.
1251565Sdp 	 * i.e.:   zonecfg.XXXXXX  ->  myzone.xml
1252565Sdp 	 */
12530Sstevel@tonic-gate 	if (rename(tmpfile, filename) == -1) {
1254565Sdp 		err = errno;
12550Sstevel@tonic-gate 		(void) unlink(tmpfile);
1256565Sdp 		if (backup)
1257565Sdp 			(void) unlink(bakfile);
1258565Sdp 		if (err == EACCES)
12590Sstevel@tonic-gate 			return (Z_ACCES);
12600Sstevel@tonic-gate 		return (Z_MISC_FS);
12610Sstevel@tonic-gate 	}
1262228Sdp 
1263565Sdp 	/*
1264565Sdp 	 * If this is a snapshot, we're done-- don't add an index entry.
1265565Sdp 	 */
1266565Sdp 	if (is_snapshot(handle))
1267565Sdp 		return (Z_OK);
1268565Sdp 
1269565Sdp 	/* now update the index file to reflect whatever we just did */
1270565Sdp 	if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) {
1271565Sdp 		if (backup) {
1272565Sdp 			/*
1273565Sdp 			 * Try to restore from our backup.
1274565Sdp 			 */
1275565Sdp 			(void) unlink(filename);
1276565Sdp 			(void) rename(bakfile, filename);
1277565Sdp 		} else {
1278565Sdp 			/*
1279565Sdp 			 * Either the zone is new, in which case we can delete
1280565Sdp 			 * new.xml, or we're doing a rename, so ditto.
1281565Sdp 			 */
1282565Sdp 			assert(is_new(handle) || is_renaming(handle));
1283565Sdp 			(void) unlink(filename);
1284565Sdp 		}
1285565Sdp 		return (Z_UPDATING_INDEX);
1286565Sdp 	}
1287565Sdp 
1288565Sdp 	if (backup)
1289565Sdp 		(void) unlink(bakfile);
1290565Sdp 
1291565Sdp 	return (Z_OK);
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate err:
12940Sstevel@tonic-gate 	(void) unlink(tmpfile);
12950Sstevel@tonic-gate 	return (Z_SAVING_FILE);
12960Sstevel@tonic-gate }
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate int
zonecfg_save(zone_dochandle_t handle)12990Sstevel@tonic-gate zonecfg_save(zone_dochandle_t handle)
13000Sstevel@tonic-gate {
1301565Sdp 	char zname[ZONENAME_MAX], path[MAXPATHLEN];
1302565Sdp 	char delpath[MAXPATHLEN];
1303565Sdp 	int err = Z_SAVING_FILE;
1304565Sdp 
1305565Sdp 	if (zonecfg_check_handle(handle) != Z_OK)
1306565Sdp 		return (Z_BAD_HANDLE);
1307565Sdp 
1308565Sdp 	/*
13091507Sgjelinek 	 * We don't support saving snapshots or a tree containing a sw
13101507Sgjelinek 	 * inventory at this time.
1311565Sdp 	 */
13121507Sgjelinek 	if (handle->zone_dh_snapshot || handle->zone_dh_sw_inv)
1313565Sdp 		return (Z_INVAL);
1314565Sdp 
1315565Sdp 	if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK)
13160Sstevel@tonic-gate 		return (err);
1317565Sdp 
1318766Scarlsonj 	if (!config_file_path(zname, path))
1319766Scarlsonj 		return (Z_MISC_FS);
1320565Sdp 
1321565Sdp 	addcomment(handle, "\n    DO NOT EDIT THIS "
1322565Sdp 	    "FILE.  Use zonecfg(1M) instead.\n");
1323565Sdp 
132412578SGlenn.Faden@Sun.COM 	/*
132512578SGlenn.Faden@Sun.COM 	 * Update user_attr first so that it will be older
132612578SGlenn.Faden@Sun.COM 	 * than the config file.
132712578SGlenn.Faden@Sun.COM 	 */
132812578SGlenn.Faden@Sun.COM 	(void) zonecfg_authorize_users(handle, zname);
1329565Sdp 	err = zonecfg_save_impl(handle, path);
1330565Sdp 
1331565Sdp 	stripcomments(handle);
1332565Sdp 
1333565Sdp 	if (err != Z_OK)
1334565Sdp 		return (err);
1335565Sdp 
1336565Sdp 	handle->zone_dh_newzone = B_FALSE;
1337565Sdp 
1338565Sdp 	if (is_renaming(handle)) {
1339766Scarlsonj 		if (config_file_path(handle->zone_dh_delete_name, delpath))
1340766Scarlsonj 			(void) unlink(delpath);
1341565Sdp 		handle->zone_dh_delete_name[0] = '\0';
1342565Sdp 	}
1343565Sdp 
1344565Sdp 	return (Z_OK);
13450Sstevel@tonic-gate }
13460Sstevel@tonic-gate 
13471507Sgjelinek int
zonecfg_verify_save(zone_dochandle_t handle,char * filename)13482712Snn35248 zonecfg_verify_save(zone_dochandle_t handle, char *filename)
13492712Snn35248 {
13502712Snn35248 	int valid;
13512712Snn35248 
13522712Snn35248 	xmlValidCtxt cvp = { NULL };
13532712Snn35248 
13542712Snn35248 	if (zonecfg_check_handle(handle) != Z_OK)
13552712Snn35248 		return (Z_BAD_HANDLE);
13562712Snn35248 
13572712Snn35248 	cvp.error = zonecfg_error_func;
13582712Snn35248 	cvp.warning = zonecfg_error_func;
13592712Snn35248 
13602712Snn35248 	/*
13612712Snn35248 	 * We do a final validation of the document.  Since the library has
13622712Snn35248 	 * malfunctioned if it fails to validate, we follow-up with an
13632712Snn35248 	 * assert() that the doc is valid.
13642712Snn35248 	 */
13652712Snn35248 	valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
13662712Snn35248 	assert(valid != 0);
13672712Snn35248 
13682712Snn35248 	if (xmlSaveFormatFile(filename, handle->zone_dh_doc, 1) <= 0)
13692712Snn35248 		return (Z_SAVING_FILE);
13702712Snn35248 
13712712Snn35248 	return (Z_OK);
13722712Snn35248 }
13732712Snn35248 
13742712Snn35248 int
zonecfg_detach_save(zone_dochandle_t handle,uint_t flags)13752078Sgjelinek zonecfg_detach_save(zone_dochandle_t handle, uint_t flags)
13761507Sgjelinek {
13771507Sgjelinek 	char zname[ZONENAME_MAX];
13781507Sgjelinek 	char path[MAXPATHLEN];
13791507Sgjelinek 	char migpath[MAXPATHLEN];
13801507Sgjelinek 	xmlValidCtxt cvp = { NULL };
13811507Sgjelinek 	int err = Z_SAVING_FILE;
13822712Snn35248 	int valid;
13831507Sgjelinek 
13841507Sgjelinek 	if (zonecfg_check_handle(handle) != Z_OK)
13851507Sgjelinek 		return (Z_BAD_HANDLE);
13861507Sgjelinek 
13872078Sgjelinek 	if (flags & ZONE_DRY_RUN) {
13882078Sgjelinek 		(void) strlcpy(migpath, "-", sizeof (migpath));
13892078Sgjelinek 	} else {
13902078Sgjelinek 		if ((err = zonecfg_get_name(handle, zname, sizeof (zname)))
13912078Sgjelinek 		    != Z_OK)
13922078Sgjelinek 			return (err);
13932078Sgjelinek 
13942078Sgjelinek 		if ((err = zone_get_zonepath(zname, path, sizeof (path)))
13952078Sgjelinek 		    != Z_OK)
13962078Sgjelinek 			return (err);
13972078Sgjelinek 
13987257Sgjelinek 		if (snprintf(migpath, sizeof (migpath), "%s/%s", path,
13997257Sgjelinek 		    ZONE_DETACHED) >= sizeof (migpath))
14002078Sgjelinek 			return (Z_NOMEM);
14012078Sgjelinek 	}
14021507Sgjelinek 
14031507Sgjelinek 	if ((err = operation_prep(handle)) != Z_OK)
14041507Sgjelinek 		return (err);
14051507Sgjelinek 
14061507Sgjelinek 	addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
14071507Sgjelinek 	    "Use zonecfg(1M) and zoneadm(1M) attach.\n");
14081507Sgjelinek 
14091507Sgjelinek 	cvp.error = zonecfg_error_func;
14101507Sgjelinek 	cvp.warning = zonecfg_error_func;
14111507Sgjelinek 
14121507Sgjelinek 	/*
14132712Snn35248 	 * We do a final validation of the document.  Since the library has
14142712Snn35248 	 * malfunctioned if it fails to validate, we follow-up with an
14152712Snn35248 	 * assert() that the doc is valid.
14161507Sgjelinek 	 */
14172712Snn35248 	valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
14182712Snn35248 	assert(valid != 0);
14191507Sgjelinek 
14201507Sgjelinek 	if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0)
14211507Sgjelinek 		return (Z_SAVING_FILE);
14221507Sgjelinek 
14232078Sgjelinek 	if (!(flags & ZONE_DRY_RUN))
14242078Sgjelinek 		(void) chmod(migpath, 0644);
14251507Sgjelinek 
14261507Sgjelinek 	stripcomments(handle);
14271507Sgjelinek 
14281507Sgjelinek 	handle->zone_dh_newzone = B_FALSE;
14291507Sgjelinek 
14301507Sgjelinek 	return (Z_OK);
14311507Sgjelinek }
14321507Sgjelinek 
14331507Sgjelinek boolean_t
zonecfg_detached(const char * path)14341507Sgjelinek zonecfg_detached(const char *path)
14351507Sgjelinek {
14361507Sgjelinek 	char		migpath[MAXPATHLEN];
14371507Sgjelinek 	struct stat	buf;
14381507Sgjelinek 
14397257Sgjelinek 	if (snprintf(migpath, sizeof (migpath), "%s/%s", path, ZONE_DETACHED) >=
14401507Sgjelinek 	    sizeof (migpath))
14411507Sgjelinek 		return (B_FALSE);
14421507Sgjelinek 
14431507Sgjelinek 	if (stat(migpath, &buf) != -1)
14441507Sgjelinek 		return (B_TRUE);
14451507Sgjelinek 
14461507Sgjelinek 	return (B_FALSE);
14471507Sgjelinek }
14481507Sgjelinek 
14491507Sgjelinek void
zonecfg_rm_detached(zone_dochandle_t handle,boolean_t forced)14501507Sgjelinek zonecfg_rm_detached(zone_dochandle_t handle, boolean_t forced)
14511507Sgjelinek {
14521507Sgjelinek 	char zname[ZONENAME_MAX];
14531507Sgjelinek 	char path[MAXPATHLEN];
14541507Sgjelinek 	char detached[MAXPATHLEN];
14551507Sgjelinek 	char attached[MAXPATHLEN];
14561507Sgjelinek 
14571507Sgjelinek 	if (zonecfg_check_handle(handle) != Z_OK)
14581507Sgjelinek 		return;
14591507Sgjelinek 
14601507Sgjelinek 	if (zonecfg_get_name(handle, zname, sizeof (zname)) != Z_OK)
14611507Sgjelinek 		return;
14621507Sgjelinek 
14631507Sgjelinek 	if (zone_get_zonepath(zname, path, sizeof (path)) != Z_OK)
14641507Sgjelinek 		return;
14651507Sgjelinek 
14667257Sgjelinek 	(void) snprintf(detached, sizeof (detached), "%s/%s", path,
14677257Sgjelinek 	    ZONE_DETACHED);
14681507Sgjelinek 	(void) snprintf(attached, sizeof (attached), "%s/%s", path,
14691507Sgjelinek 	    ATTACH_FORCED);
14701507Sgjelinek 
14711507Sgjelinek 	if (forced) {
14721507Sgjelinek 		(void) rename(detached, attached);
14731507Sgjelinek 	} else {
14741507Sgjelinek 		(void) unlink(attached);
14751507Sgjelinek 		(void) unlink(detached);
14761507Sgjelinek 	}
14771507Sgjelinek }
14781507Sgjelinek 
14790Sstevel@tonic-gate /*
14800Sstevel@tonic-gate  * Special case: if access(2) fails with ENOENT, then try again using
14810Sstevel@tonic-gate  * ZONE_CONFIG_ROOT instead of config_file_path(zonename).  This is how we
14820Sstevel@tonic-gate  * work around the case of a config file which has not been created yet:
14830Sstevel@tonic-gate  * the user will need access to the directory so use that as a heuristic.
14840Sstevel@tonic-gate  */
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate int
zonecfg_access(const char * zonename,int amode)14870Sstevel@tonic-gate zonecfg_access(const char *zonename, int amode)
14880Sstevel@tonic-gate {
14890Sstevel@tonic-gate 	char path[MAXPATHLEN];
14900Sstevel@tonic-gate 
1491766Scarlsonj 	if (!config_file_path(zonename, path))
1492766Scarlsonj 		return (Z_INVAL);
14930Sstevel@tonic-gate 	if (access(path, amode) == 0)
14940Sstevel@tonic-gate 		return (Z_OK);
1495766Scarlsonj 	if (errno == ENOENT) {
1496766Scarlsonj 		if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1497766Scarlsonj 		    ZONE_CONFIG_ROOT) >= sizeof (path))
1498766Scarlsonj 			return (Z_INVAL);
1499766Scarlsonj 		if (access(path, amode) == 0)
1500766Scarlsonj 			return (Z_OK);
1501766Scarlsonj 	}
15020Sstevel@tonic-gate 	if (errno == EACCES)
15030Sstevel@tonic-gate 		return (Z_ACCES);
15040Sstevel@tonic-gate 	if (errno == EINVAL)
15050Sstevel@tonic-gate 		return (Z_INVAL);
15060Sstevel@tonic-gate 	return (Z_MISC_FS);
15070Sstevel@tonic-gate }
15080Sstevel@tonic-gate 
15090Sstevel@tonic-gate int
zonecfg_create_snapshot(const char * zonename)1510766Scarlsonj zonecfg_create_snapshot(const char *zonename)
15110Sstevel@tonic-gate {
15120Sstevel@tonic-gate 	zone_dochandle_t handle;
15130Sstevel@tonic-gate 	char path[MAXPATHLEN], zonepath[MAXPATHLEN], rpath[MAXPATHLEN];
15140Sstevel@tonic-gate 	int error = Z_OK, res;
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate 	if ((handle = zonecfg_init_handle()) == NULL) {
15170Sstevel@tonic-gate 		return (Z_NOMEM);
15180Sstevel@tonic-gate 	}
15190Sstevel@tonic-gate 
1520565Sdp 	handle->zone_dh_newzone = B_TRUE;
1521565Sdp 	handle->zone_dh_snapshot = B_TRUE;
1522565Sdp 
15230Sstevel@tonic-gate 	if ((error = zonecfg_get_handle(zonename, handle)) != Z_OK)
15240Sstevel@tonic-gate 		goto out;
15250Sstevel@tonic-gate 	if ((error = operation_prep(handle)) != Z_OK)
15260Sstevel@tonic-gate 		goto out;
15270Sstevel@tonic-gate 	error = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath));
15280Sstevel@tonic-gate 	if (error != Z_OK)
15290Sstevel@tonic-gate 		goto out;
15300Sstevel@tonic-gate 	if ((res = resolvepath(zonepath, rpath, sizeof (rpath))) == -1) {
15310Sstevel@tonic-gate 		error = Z_RESOLVED_PATH;
15320Sstevel@tonic-gate 		goto out;
15330Sstevel@tonic-gate 	}
15340Sstevel@tonic-gate 	/*
15350Sstevel@tonic-gate 	 * If the resolved path is not the same as the original path, then
15360Sstevel@tonic-gate 	 * save the resolved path in the snapshot, thus preventing any
15370Sstevel@tonic-gate 	 * potential problems down the line when zoneadmd goes to unmount
15380Sstevel@tonic-gate 	 * file systems and depends on initial string matches with resolved
15390Sstevel@tonic-gate 	 * paths.
15400Sstevel@tonic-gate 	 */
15410Sstevel@tonic-gate 	rpath[res] = '\0';
15420Sstevel@tonic-gate 	if (strcmp(zonepath, rpath) != 0) {
15430Sstevel@tonic-gate 		if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK)
15440Sstevel@tonic-gate 			goto out;
15450Sstevel@tonic-gate 	}
1546766Scarlsonj 	if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1547766Scarlsonj 	    ZONE_SNAPSHOT_ROOT) >= sizeof (path)) {
15480Sstevel@tonic-gate 		error = Z_MISC_FS;
15490Sstevel@tonic-gate 		goto out;
15500Sstevel@tonic-gate 	}
1551766Scarlsonj 	if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) {
1552766Scarlsonj 		error = Z_MISC_FS;
1553766Scarlsonj 		goto out;
1554766Scarlsonj 	}
1555766Scarlsonj 
1556766Scarlsonj 	if (!snap_file_path(zonename, path)) {
1557766Scarlsonj 		error = Z_MISC_FS;
1558766Scarlsonj 		goto out;
1559766Scarlsonj 	}
1560565Sdp 
1561565Sdp 	addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
1562565Sdp 	    "It is a snapshot of running zone state.\n");
1563565Sdp 
15640Sstevel@tonic-gate 	error = zonecfg_save_impl(handle, path);
15650Sstevel@tonic-gate 
1566565Sdp 	stripcomments(handle);
1567565Sdp 
15680Sstevel@tonic-gate out:
15690Sstevel@tonic-gate 	zonecfg_fini_handle(handle);
15700Sstevel@tonic-gate 	return (error);
15710Sstevel@tonic-gate }
15720Sstevel@tonic-gate 
15733448Sdh155122 int
zonecfg_get_iptype(zone_dochandle_t handle,zone_iptype_t * iptypep)15743448Sdh155122 zonecfg_get_iptype(zone_dochandle_t handle, zone_iptype_t *iptypep)
15753448Sdh155122 {
15763448Sdh155122 	char property[10]; /* 10 is big enough for "shared"/"exclusive" */
15773448Sdh155122 	int err;
15783448Sdh155122 
15793448Sdh155122 	err = getrootattr(handle, DTD_ATTR_IPTYPE, property, sizeof (property));
15803448Sdh155122 	if (err == Z_BAD_PROPERTY) {
15813448Sdh155122 		/* Return default value */
15823448Sdh155122 		*iptypep = ZS_SHARED;
15833448Sdh155122 		return (Z_OK);
15843448Sdh155122 	} else if (err != Z_OK) {
15853448Sdh155122 		return (err);
15863448Sdh155122 	}
15873448Sdh155122 
15883448Sdh155122 	if (strlen(property) == 0 ||
15893448Sdh155122 	    strcmp(property, "shared") == 0)
15903448Sdh155122 		*iptypep = ZS_SHARED;
15913448Sdh155122 	else if (strcmp(property, "exclusive") == 0)
15923448Sdh155122 		*iptypep = ZS_EXCLUSIVE;
15933448Sdh155122 	else
15943448Sdh155122 		return (Z_INVAL);
15953448Sdh155122 
15963448Sdh155122 	return (Z_OK);
15973448Sdh155122 }
15983448Sdh155122 
15993448Sdh155122 int
zonecfg_set_iptype(zone_dochandle_t handle,zone_iptype_t iptype)16003448Sdh155122 zonecfg_set_iptype(zone_dochandle_t handle, zone_iptype_t iptype)
16013448Sdh155122 {
16023448Sdh155122 	xmlNodePtr cur;
16033448Sdh155122 
16043448Sdh155122 	if (handle == NULL)
16053448Sdh155122 		return (Z_INVAL);
16063448Sdh155122 
16073448Sdh155122 	cur = xmlDocGetRootElement(handle->zone_dh_doc);
16083448Sdh155122 	if (cur == NULL) {
16093448Sdh155122 		return (Z_EMPTY_DOCUMENT);
16103448Sdh155122 	}
16113448Sdh155122 
16123448Sdh155122 	if (xmlStrcmp(cur->name, DTD_ELEM_ZONE) != 0) {
16133448Sdh155122 		return (Z_WRONG_DOC_TYPE);
16143448Sdh155122 	}
16153448Sdh155122 	switch (iptype) {
16163448Sdh155122 	case ZS_SHARED:
16173448Sdh155122 		/*
16183448Sdh155122 		 * Since "shared" is the default, we don't write it to the
16193448Sdh155122 		 * configuration file, so that it's easier to migrate those
16203448Sdh155122 		 * zones elsewhere, eg., to systems which are not IP-Instances
16213448Sdh155122 		 * aware.
16223448Sdh155122 		 * xmlUnsetProp only fails when the attribute doesn't exist,
16233448Sdh155122 		 * which we don't care.
16243448Sdh155122 		 */
16253448Sdh155122 		(void) xmlUnsetProp(cur, DTD_ATTR_IPTYPE);
16263448Sdh155122 		break;
16273448Sdh155122 	case ZS_EXCLUSIVE:
16283448Sdh155122 		if (xmlSetProp(cur, DTD_ATTR_IPTYPE,
16293448Sdh155122 		    (const xmlChar *) "exclusive") == NULL)
16303448Sdh155122 			return (Z_INVAL);
16313448Sdh155122 		break;
16323448Sdh155122 	}
16333448Sdh155122 	return (Z_OK);
16343448Sdh155122 }
16353448Sdh155122 
16360Sstevel@tonic-gate static int
newprop(xmlNodePtr node,const xmlChar * attrname,char * src)1637228Sdp newprop(xmlNodePtr node, const xmlChar *attrname, char *src)
16380Sstevel@tonic-gate {
16390Sstevel@tonic-gate 	xmlAttrPtr newattr;
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate 	newattr = xmlNewProp(node, attrname, (xmlChar *)src);
16420Sstevel@tonic-gate 	if (newattr == NULL) {
16430Sstevel@tonic-gate 		xmlUnlinkNode(node);
16440Sstevel@tonic-gate 		xmlFreeNode(node);
16450Sstevel@tonic-gate 		return (Z_BAD_PROPERTY);
16460Sstevel@tonic-gate 	}
16470Sstevel@tonic-gate 	return (Z_OK);
16480Sstevel@tonic-gate }
16490Sstevel@tonic-gate 
16500Sstevel@tonic-gate static int
zonecfg_add_filesystem_core(zone_dochandle_t handle,struct zone_fstab * tabptr)16510Sstevel@tonic-gate zonecfg_add_filesystem_core(zone_dochandle_t handle, struct zone_fstab *tabptr)
16520Sstevel@tonic-gate {
16530Sstevel@tonic-gate 	xmlNodePtr newnode, cur = handle->zone_dh_cur, options_node;
16540Sstevel@tonic-gate 	zone_fsopt_t *ptr;
16550Sstevel@tonic-gate 	int err;
16560Sstevel@tonic-gate 
16570Sstevel@tonic-gate 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_FS, NULL);
1658228Sdp 	if ((err = newprop(newnode, DTD_ATTR_SPECIAL,
16590Sstevel@tonic-gate 	    tabptr->zone_fs_special)) != Z_OK)
16600Sstevel@tonic-gate 		return (err);
16610Sstevel@tonic-gate 	if (tabptr->zone_fs_raw[0] != '\0' &&
1662228Sdp 	    (err = newprop(newnode, DTD_ATTR_RAW, tabptr->zone_fs_raw)) != Z_OK)
16630Sstevel@tonic-gate 		return (err);
1664228Sdp 	if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK)
16650Sstevel@tonic-gate 		return (err);
1666228Sdp 	if ((err = newprop(newnode, DTD_ATTR_TYPE,
16670Sstevel@tonic-gate 	    tabptr->zone_fs_type)) != Z_OK)
16680Sstevel@tonic-gate 		return (err);
16690Sstevel@tonic-gate 	if (tabptr->zone_fs_options != NULL) {
16700Sstevel@tonic-gate 		for (ptr = tabptr->zone_fs_options; ptr != NULL;
16710Sstevel@tonic-gate 		    ptr = ptr->zone_fsopt_next) {
16720Sstevel@tonic-gate 			options_node = xmlNewTextChild(newnode, NULL,
16730Sstevel@tonic-gate 			    DTD_ELEM_FSOPTION, NULL);
1674228Sdp 			if ((err = newprop(options_node, DTD_ATTR_NAME,
16750Sstevel@tonic-gate 			    ptr->zone_fsopt_opt)) != Z_OK)
16760Sstevel@tonic-gate 				return (err);
16770Sstevel@tonic-gate 		}
16780Sstevel@tonic-gate 	}
16790Sstevel@tonic-gate 	return (Z_OK);
16800Sstevel@tonic-gate }
16810Sstevel@tonic-gate 
16820Sstevel@tonic-gate int
zonecfg_add_filesystem(zone_dochandle_t handle,struct zone_fstab * tabptr)16830Sstevel@tonic-gate zonecfg_add_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
16840Sstevel@tonic-gate {
16850Sstevel@tonic-gate 	int err;
16860Sstevel@tonic-gate 
16870Sstevel@tonic-gate 	if (tabptr == NULL)
16880Sstevel@tonic-gate 		return (Z_INVAL);
16890Sstevel@tonic-gate 
16900Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK)
16910Sstevel@tonic-gate 		return (err);
16920Sstevel@tonic-gate 
16930Sstevel@tonic-gate 	if ((err = zonecfg_add_filesystem_core(handle, tabptr)) != Z_OK)
16940Sstevel@tonic-gate 		return (err);
16950Sstevel@tonic-gate 
16960Sstevel@tonic-gate 	return (Z_OK);
16970Sstevel@tonic-gate }
16980Sstevel@tonic-gate 
16990Sstevel@tonic-gate int
zonecfg_add_fs_option(struct zone_fstab * tabptr,char * option)17000Sstevel@tonic-gate zonecfg_add_fs_option(struct zone_fstab *tabptr, char *option)
17010Sstevel@tonic-gate {
17020Sstevel@tonic-gate 	zone_fsopt_t *last, *old, *new;
17030Sstevel@tonic-gate 
17040Sstevel@tonic-gate 	last = tabptr->zone_fs_options;
17050Sstevel@tonic-gate 	for (old = last; old != NULL; old = old->zone_fsopt_next)
17060Sstevel@tonic-gate 		last = old;	/* walk to the end of the list */
17070Sstevel@tonic-gate 	new = (zone_fsopt_t *)malloc(sizeof (zone_fsopt_t));
17080Sstevel@tonic-gate 	if (new == NULL)
17090Sstevel@tonic-gate 		return (Z_NOMEM);
17100Sstevel@tonic-gate 	(void) strlcpy(new->zone_fsopt_opt, option,
17110Sstevel@tonic-gate 	    sizeof (new->zone_fsopt_opt));
17120Sstevel@tonic-gate 	new->zone_fsopt_next = NULL;
17130Sstevel@tonic-gate 	if (last == NULL)
17140Sstevel@tonic-gate 		tabptr->zone_fs_options = new;
17150Sstevel@tonic-gate 	else
17160Sstevel@tonic-gate 		last->zone_fsopt_next = new;
17170Sstevel@tonic-gate 	return (Z_OK);
17180Sstevel@tonic-gate }
17190Sstevel@tonic-gate 
17200Sstevel@tonic-gate int
zonecfg_remove_fs_option(struct zone_fstab * tabptr,char * option)17210Sstevel@tonic-gate zonecfg_remove_fs_option(struct zone_fstab *tabptr, char *option)
17220Sstevel@tonic-gate {
17230Sstevel@tonic-gate 	zone_fsopt_t *last, *this, *next;
17240Sstevel@tonic-gate 
17250Sstevel@tonic-gate 	last = tabptr->zone_fs_options;
17260Sstevel@tonic-gate 	for (this = last; this != NULL; this = this->zone_fsopt_next) {
17270Sstevel@tonic-gate 		if (strcmp(this->zone_fsopt_opt, option) == 0) {
17280Sstevel@tonic-gate 			next = this->zone_fsopt_next;
17290Sstevel@tonic-gate 			if (this == tabptr->zone_fs_options)
17300Sstevel@tonic-gate 				tabptr->zone_fs_options = next;
17310Sstevel@tonic-gate 			else
17320Sstevel@tonic-gate 				last->zone_fsopt_next = next;
17330Sstevel@tonic-gate 			free(this);
17340Sstevel@tonic-gate 			return (Z_OK);
17350Sstevel@tonic-gate 		} else
17360Sstevel@tonic-gate 			last = this;
17370Sstevel@tonic-gate 	}
17380Sstevel@tonic-gate 	return (Z_NO_PROPERTY_ID);
17390Sstevel@tonic-gate }
17400Sstevel@tonic-gate 
17410Sstevel@tonic-gate void
zonecfg_free_fs_option_list(zone_fsopt_t * list)17420Sstevel@tonic-gate zonecfg_free_fs_option_list(zone_fsopt_t *list)
17430Sstevel@tonic-gate {
17440Sstevel@tonic-gate 	zone_fsopt_t *this, *next;
17450Sstevel@tonic-gate 
17460Sstevel@tonic-gate 	for (this = list; this != NULL; this = next) {
17470Sstevel@tonic-gate 		next = this->zone_fsopt_next;
17480Sstevel@tonic-gate 		free(this);
17490Sstevel@tonic-gate 	}
17500Sstevel@tonic-gate }
17510Sstevel@tonic-gate 
17520Sstevel@tonic-gate void
zonecfg_free_rctl_value_list(struct zone_rctlvaltab * valtab)17530Sstevel@tonic-gate zonecfg_free_rctl_value_list(struct zone_rctlvaltab *valtab)
17540Sstevel@tonic-gate {
17550Sstevel@tonic-gate 	if (valtab == NULL)
17560Sstevel@tonic-gate 		return;
17570Sstevel@tonic-gate 	zonecfg_free_rctl_value_list(valtab->zone_rctlval_next);
17580Sstevel@tonic-gate 	free(valtab);
17590Sstevel@tonic-gate }
17600Sstevel@tonic-gate 
17610Sstevel@tonic-gate static boolean_t
match_prop(xmlNodePtr cur,const xmlChar * attr,char * user_prop)17620Sstevel@tonic-gate match_prop(xmlNodePtr cur, const xmlChar *attr, char *user_prop)
17630Sstevel@tonic-gate {
17640Sstevel@tonic-gate 	xmlChar *gotten_prop;
17650Sstevel@tonic-gate 	int prop_result;
17660Sstevel@tonic-gate 
17670Sstevel@tonic-gate 	gotten_prop = xmlGetProp(cur, attr);
17680Sstevel@tonic-gate 	if (gotten_prop == NULL)	/* shouldn't happen */
17690Sstevel@tonic-gate 		return (B_FALSE);
17700Sstevel@tonic-gate 	prop_result = xmlStrcmp(gotten_prop, (const xmlChar *) user_prop);
17710Sstevel@tonic-gate 	xmlFree(gotten_prop);
17720Sstevel@tonic-gate 	return ((prop_result == 0));
17730Sstevel@tonic-gate }
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate static int
zonecfg_delete_filesystem_core(zone_dochandle_t handle,struct zone_fstab * tabptr)17760Sstevel@tonic-gate zonecfg_delete_filesystem_core(zone_dochandle_t handle,
17770Sstevel@tonic-gate     struct zone_fstab *tabptr)
17780Sstevel@tonic-gate {
17790Sstevel@tonic-gate 	xmlNodePtr cur = handle->zone_dh_cur;
17800Sstevel@tonic-gate 	boolean_t dir_match, spec_match, raw_match, type_match;
17810Sstevel@tonic-gate 
17820Sstevel@tonic-gate 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
17830Sstevel@tonic-gate 		if (xmlStrcmp(cur->name, DTD_ELEM_FS))
17840Sstevel@tonic-gate 			continue;
17850Sstevel@tonic-gate 		dir_match = match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir);
17860Sstevel@tonic-gate 		spec_match = match_prop(cur, DTD_ATTR_SPECIAL,
17870Sstevel@tonic-gate 		    tabptr->zone_fs_special);
17880Sstevel@tonic-gate 		raw_match = match_prop(cur, DTD_ATTR_RAW,
17890Sstevel@tonic-gate 		    tabptr->zone_fs_raw);
17900Sstevel@tonic-gate 		type_match = match_prop(cur, DTD_ATTR_TYPE,
17910Sstevel@tonic-gate 		    tabptr->zone_fs_type);
17920Sstevel@tonic-gate 		if (dir_match && spec_match && raw_match && type_match) {
17930Sstevel@tonic-gate 			xmlUnlinkNode(cur);
17940Sstevel@tonic-gate 			xmlFreeNode(cur);
17950Sstevel@tonic-gate 			return (Z_OK);
17960Sstevel@tonic-gate 		}
17970Sstevel@tonic-gate 	}
17980Sstevel@tonic-gate 	return (Z_NO_RESOURCE_ID);
17990Sstevel@tonic-gate }
18000Sstevel@tonic-gate 
18010Sstevel@tonic-gate int
zonecfg_delete_filesystem(zone_dochandle_t handle,struct zone_fstab * tabptr)18020Sstevel@tonic-gate zonecfg_delete_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
18030Sstevel@tonic-gate {
18040Sstevel@tonic-gate 	int err;
18050Sstevel@tonic-gate 
18060Sstevel@tonic-gate 	if (tabptr == NULL)
18070Sstevel@tonic-gate 		return (Z_INVAL);
18080Sstevel@tonic-gate 
18090Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK)
18100Sstevel@tonic-gate 		return (err);
18110Sstevel@tonic-gate 
18120Sstevel@tonic-gate 	if ((err = zonecfg_delete_filesystem_core(handle, tabptr)) != Z_OK)
18130Sstevel@tonic-gate 		return (err);
18140Sstevel@tonic-gate 
18150Sstevel@tonic-gate 	return (Z_OK);
18160Sstevel@tonic-gate }
18170Sstevel@tonic-gate 
18180Sstevel@tonic-gate int
zonecfg_modify_filesystem(zone_dochandle_t handle,struct zone_fstab * oldtabptr,struct zone_fstab * newtabptr)18190Sstevel@tonic-gate zonecfg_modify_filesystem(
18200Sstevel@tonic-gate 	zone_dochandle_t handle,
18210Sstevel@tonic-gate 	struct zone_fstab *oldtabptr,
18220Sstevel@tonic-gate 	struct zone_fstab *newtabptr)
18230Sstevel@tonic-gate {
18240Sstevel@tonic-gate 	int err;
18250Sstevel@tonic-gate 
18260Sstevel@tonic-gate 	if (oldtabptr == NULL || newtabptr == NULL)
18270Sstevel@tonic-gate 		return (Z_INVAL);
18280Sstevel@tonic-gate 
18290Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK)
18300Sstevel@tonic-gate 		return (err);
18310Sstevel@tonic-gate 
18320Sstevel@tonic-gate 	if ((err = zonecfg_delete_filesystem_core(handle, oldtabptr)) != Z_OK)
18330Sstevel@tonic-gate 		return (err);
18340Sstevel@tonic-gate 
18350Sstevel@tonic-gate 	if ((err = zonecfg_add_filesystem_core(handle, newtabptr)) != Z_OK)
18360Sstevel@tonic-gate 		return (err);
18370Sstevel@tonic-gate 
18380Sstevel@tonic-gate 	return (Z_OK);
18390Sstevel@tonic-gate }
18400Sstevel@tonic-gate 
18410Sstevel@tonic-gate int
zonecfg_lookup_filesystem(zone_dochandle_t handle,struct zone_fstab * tabptr)18420Sstevel@tonic-gate zonecfg_lookup_filesystem(
18430Sstevel@tonic-gate 	zone_dochandle_t handle,
18440Sstevel@tonic-gate 	struct zone_fstab *tabptr)
18450Sstevel@tonic-gate {
18460Sstevel@tonic-gate 	xmlNodePtr cur, options, firstmatch;
18470Sstevel@tonic-gate 	int err;
18480Sstevel@tonic-gate 	char dirname[MAXPATHLEN], special[MAXPATHLEN], raw[MAXPATHLEN];
18490Sstevel@tonic-gate 	char type[FSTYPSZ];
18500Sstevel@tonic-gate 	char options_str[MAX_MNTOPT_STR];
18510Sstevel@tonic-gate 
18520Sstevel@tonic-gate 	if (tabptr == NULL)
18530Sstevel@tonic-gate 		return (Z_INVAL);
18540Sstevel@tonic-gate 
18550Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK)
18560Sstevel@tonic-gate 		return (err);
18570Sstevel@tonic-gate 
18580Sstevel@tonic-gate 	/*
18590Sstevel@tonic-gate 	 * Walk the list of children looking for matches on any properties
18600Sstevel@tonic-gate 	 * specified in the fstab parameter.  If more than one resource
18610Sstevel@tonic-gate 	 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return
18620Sstevel@tonic-gate 	 * Z_NO_RESOURCE_ID.
18630Sstevel@tonic-gate 	 */
18640Sstevel@tonic-gate 	cur = handle->zone_dh_cur;
18650Sstevel@tonic-gate 	firstmatch = NULL;
18660Sstevel@tonic-gate 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
18670Sstevel@tonic-gate 		if (xmlStrcmp(cur->name, DTD_ELEM_FS))
18680Sstevel@tonic-gate 			continue;
18690Sstevel@tonic-gate 		if (strlen(tabptr->zone_fs_dir) > 0) {
18700Sstevel@tonic-gate 			if ((fetchprop(cur, DTD_ATTR_DIR, dirname,
18710Sstevel@tonic-gate 			    sizeof (dirname)) == Z_OK) &&
18720Sstevel@tonic-gate 			    (strcmp(tabptr->zone_fs_dir, dirname) == 0)) {
18730Sstevel@tonic-gate 				if (firstmatch == NULL)
18740Sstevel@tonic-gate 					firstmatch = cur;
18750Sstevel@tonic-gate 				else
18760Sstevel@tonic-gate 					return (Z_INSUFFICIENT_SPEC);
18770Sstevel@tonic-gate 			}
18780Sstevel@tonic-gate 		}
18790Sstevel@tonic-gate 		if (strlen(tabptr->zone_fs_special) > 0) {
18800Sstevel@tonic-gate 			if ((fetchprop(cur, DTD_ATTR_SPECIAL, special,
18810Sstevel@tonic-gate 			    sizeof (special)) == Z_OK)) {
18820Sstevel@tonic-gate 				if (strcmp(tabptr->zone_fs_special,
18830Sstevel@tonic-gate 				    special) == 0) {
18840Sstevel@tonic-gate 					if (firstmatch == NULL)
18850Sstevel@tonic-gate 						firstmatch = cur;
18860Sstevel@tonic-gate 					else if (firstmatch != cur)
18870Sstevel@tonic-gate 						return (Z_INSUFFICIENT_SPEC);
18880Sstevel@tonic-gate 				} else {
18890Sstevel@tonic-gate 					/*
18900Sstevel@tonic-gate 					 * If another property matched but this
18910Sstevel@tonic-gate 					 * one doesn't then reset firstmatch.
18920Sstevel@tonic-gate 					 */
18930Sstevel@tonic-gate 					if (firstmatch == cur)
18940Sstevel@tonic-gate 						firstmatch = NULL;
18950Sstevel@tonic-gate 				}
18960Sstevel@tonic-gate 			}
18970Sstevel@tonic-gate 		}
18980Sstevel@tonic-gate 		if (strlen(tabptr->zone_fs_raw) > 0) {
18990Sstevel@tonic-gate 			if ((fetchprop(cur, DTD_ATTR_RAW, raw,
19000Sstevel@tonic-gate 			    sizeof (raw)) == Z_OK)) {
19010Sstevel@tonic-gate 				if (strcmp(tabptr->zone_fs_raw, raw) == 0) {
19020Sstevel@tonic-gate 					if (firstmatch == NULL)
19030Sstevel@tonic-gate 						firstmatch = cur;
19040Sstevel@tonic-gate 					else if (firstmatch != cur)
19050Sstevel@tonic-gate 						return (Z_INSUFFICIENT_SPEC);
19060Sstevel@tonic-gate 				} else {
19070Sstevel@tonic-gate 					/*
19080Sstevel@tonic-gate 					 * If another property matched but this
19090Sstevel@tonic-gate 					 * one doesn't then reset firstmatch.
19100Sstevel@tonic-gate 					 */
19110Sstevel@tonic-gate 					if (firstmatch == cur)
19120Sstevel@tonic-gate 						firstmatch = NULL;
19130Sstevel@tonic-gate 				}
19140Sstevel@tonic-gate 			}
19150Sstevel@tonic-gate 		}
19160Sstevel@tonic-gate 		if (strlen(tabptr->zone_fs_type) > 0) {
19170Sstevel@tonic-gate 			if ((fetchprop(cur, DTD_ATTR_TYPE, type,
19180Sstevel@tonic-gate 			    sizeof (type)) == Z_OK)) {
19190Sstevel@tonic-gate 				if (strcmp(tabptr->zone_fs_type, type) == 0) {
19200Sstevel@tonic-gate 					if (firstmatch == NULL)
19210Sstevel@tonic-gate 						firstmatch = cur;
19220Sstevel@tonic-gate 					else if (firstmatch != cur)
19230Sstevel@tonic-gate 						return (Z_INSUFFICIENT_SPEC);
19240Sstevel@tonic-gate 				} else {
19250Sstevel@tonic-gate 					/*
19260Sstevel@tonic-gate 					 * If another property matched but this
19270Sstevel@tonic-gate 					 * one doesn't then reset firstmatch.
19280Sstevel@tonic-gate 					 */
19290Sstevel@tonic-gate 					if (firstmatch == cur)
19300Sstevel@tonic-gate 						firstmatch = NULL;
19310Sstevel@tonic-gate 				}
19320Sstevel@tonic-gate 			}
19330Sstevel@tonic-gate 		}
19340Sstevel@tonic-gate 	}
19350Sstevel@tonic-gate 
19360Sstevel@tonic-gate 	if (firstmatch == NULL)
19370Sstevel@tonic-gate 		return (Z_NO_RESOURCE_ID);
19380Sstevel@tonic-gate 
19390Sstevel@tonic-gate 	cur = firstmatch;
19400Sstevel@tonic-gate 
19410Sstevel@tonic-gate 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
19420Sstevel@tonic-gate 	    sizeof (tabptr->zone_fs_dir))) != Z_OK)
19430Sstevel@tonic-gate 		return (err);
19440Sstevel@tonic-gate 
19450Sstevel@tonic-gate 	if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
19460Sstevel@tonic-gate 	    sizeof (tabptr->zone_fs_special))) != Z_OK)
19470Sstevel@tonic-gate 		return (err);
19480Sstevel@tonic-gate 
19490Sstevel@tonic-gate 	if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
19500Sstevel@tonic-gate 	    sizeof (tabptr->zone_fs_raw))) != Z_OK)
19510Sstevel@tonic-gate 		return (err);
19520Sstevel@tonic-gate 
19530Sstevel@tonic-gate 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
19540Sstevel@tonic-gate 	    sizeof (tabptr->zone_fs_type))) != Z_OK)
19550Sstevel@tonic-gate 		return (err);
19560Sstevel@tonic-gate 
19570Sstevel@tonic-gate 	/* options are optional */
19580Sstevel@tonic-gate 	tabptr->zone_fs_options = NULL;
19590Sstevel@tonic-gate 	for (options = cur->xmlChildrenNode; options != NULL;
19600Sstevel@tonic-gate 	    options = options->next) {
19610Sstevel@tonic-gate 		if ((fetchprop(options, DTD_ATTR_NAME, options_str,
19620Sstevel@tonic-gate 		    sizeof (options_str)) != Z_OK))
19630Sstevel@tonic-gate 			break;
19640Sstevel@tonic-gate 		if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
19650Sstevel@tonic-gate 			break;
19660Sstevel@tonic-gate 	}
19670Sstevel@tonic-gate 	return (Z_OK);
19680Sstevel@tonic-gate }
19690Sstevel@tonic-gate 
19700Sstevel@tonic-gate /*
19710Sstevel@tonic-gate  * Compare two IP addresses in string form.  Allow for the possibility that
19720Sstevel@tonic-gate  * one might have "/<prefix-length>" at the end: allow a match on just the
19730Sstevel@tonic-gate  * IP address (or host name) part.
19740Sstevel@tonic-gate  */
19750Sstevel@tonic-gate 
19760Sstevel@tonic-gate boolean_t
zonecfg_same_net_address(char * a1,char * a2)19770Sstevel@tonic-gate zonecfg_same_net_address(char *a1, char *a2)
19780Sstevel@tonic-gate {
19790Sstevel@tonic-gate 	char *slashp, *slashp1, *slashp2;
19800Sstevel@tonic-gate 	int result;
19810Sstevel@tonic-gate 
19820Sstevel@tonic-gate 	if (strcmp(a1, a2) == 0)
19830Sstevel@tonic-gate 		return (B_TRUE);
19840Sstevel@tonic-gate 
19850Sstevel@tonic-gate 	/*
19860Sstevel@tonic-gate 	 * If neither has a slash or both do, they need to match to be
19870Sstevel@tonic-gate 	 * considered the same, but they did not match above, so fail.
19880Sstevel@tonic-gate 	 */
19890Sstevel@tonic-gate 	slashp1 = strchr(a1, '/');
19900Sstevel@tonic-gate 	slashp2 = strchr(a2, '/');
19910Sstevel@tonic-gate 	if ((slashp1 == NULL && slashp2 == NULL) ||
19920Sstevel@tonic-gate 	    (slashp1 != NULL && slashp2 != NULL))
19930Sstevel@tonic-gate 		return (B_FALSE);
19940Sstevel@tonic-gate 
19950Sstevel@tonic-gate 	/*
19960Sstevel@tonic-gate 	 * Only one had a slash: pick that one, zero out the slash, compare
19970Sstevel@tonic-gate 	 * the "address only" strings, restore the slash, and return the
19980Sstevel@tonic-gate 	 * result of the comparison.
19990Sstevel@tonic-gate 	 */
20000Sstevel@tonic-gate 	slashp = (slashp1 == NULL) ? slashp2 : slashp1;
20010Sstevel@tonic-gate 	*slashp = '\0';
20020Sstevel@tonic-gate 	result = strcmp(a1, a2);
20030Sstevel@tonic-gate 	*slashp = '/';
20040Sstevel@tonic-gate 	return ((result == 0));
20050Sstevel@tonic-gate }
20060Sstevel@tonic-gate 
20070Sstevel@tonic-gate int
zonecfg_valid_net_address(char * address,struct lifreq * lifr)20080Sstevel@tonic-gate zonecfg_valid_net_address(char *address, struct lifreq *lifr)
20090Sstevel@tonic-gate {
20100Sstevel@tonic-gate 	struct sockaddr_in *sin4;
20110Sstevel@tonic-gate 	struct sockaddr_in6 *sin6;
20120Sstevel@tonic-gate 	struct addrinfo hints, *result;
20130Sstevel@tonic-gate 	char *slashp = strchr(address, '/');
20140Sstevel@tonic-gate 
20150Sstevel@tonic-gate 	bzero(lifr, sizeof (struct lifreq));
20160Sstevel@tonic-gate 	sin4 = (struct sockaddr_in *)&lifr->lifr_addr;
20170Sstevel@tonic-gate 	sin6 = (struct sockaddr_in6 *)&lifr->lifr_addr;
20180Sstevel@tonic-gate 	if (slashp != NULL)
20190Sstevel@tonic-gate 		*slashp = '\0';
20200Sstevel@tonic-gate 	if (inet_pton(AF_INET, address, &sin4->sin_addr) == 1) {
20210Sstevel@tonic-gate 		sin4->sin_family = AF_INET;
20220Sstevel@tonic-gate 	} else if (inet_pton(AF_INET6, address, &sin6->sin6_addr) == 1) {
20230Sstevel@tonic-gate 		if (slashp == NULL)
20240Sstevel@tonic-gate 			return (Z_IPV6_ADDR_PREFIX_LEN);
20250Sstevel@tonic-gate 		sin6->sin6_family = AF_INET6;
20260Sstevel@tonic-gate 	} else {
20270Sstevel@tonic-gate 		/* "address" may be a host name */
20280Sstevel@tonic-gate 		(void) memset(&hints, 0, sizeof (hints));
20290Sstevel@tonic-gate 		hints.ai_family = PF_INET;
20300Sstevel@tonic-gate 		if (getaddrinfo(address, NULL, &hints, &result) != 0)
20310Sstevel@tonic-gate 			return (Z_BOGUS_ADDRESS);
20320Sstevel@tonic-gate 		sin4->sin_family = result->ai_family;
2033228Sdp 
20340Sstevel@tonic-gate 		(void) memcpy(&sin4->sin_addr,
20350Sstevel@tonic-gate 		    /* LINTED E_BAD_PTR_CAST_ALIGN */
20360Sstevel@tonic-gate 		    &((struct sockaddr_in *)result->ai_addr)->sin_addr,
20370Sstevel@tonic-gate 		    sizeof (struct in_addr));
2038228Sdp 
20390Sstevel@tonic-gate 		freeaddrinfo(result);
20400Sstevel@tonic-gate 	}
20410Sstevel@tonic-gate 	return (Z_OK);
20420Sstevel@tonic-gate }
20430Sstevel@tonic-gate 
20443448Sdh155122 boolean_t
zonecfg_ifname_exists(sa_family_t af,char * ifname)20453448Sdh155122 zonecfg_ifname_exists(sa_family_t af, char *ifname)
20463448Sdh155122 {
20473448Sdh155122 	struct lifreq lifr;
20483448Sdh155122 	int so;
20493448Sdh155122 	int save_errno;
20503448Sdh155122 
20513448Sdh155122 	(void) memset(&lifr, 0, sizeof (lifr));
20523448Sdh155122 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
20533448Sdh155122 	lifr.lifr_addr.ss_family = af;
20543448Sdh155122 	if ((so = socket(af, SOCK_DGRAM, 0)) < 0) {
20553448Sdh155122 		/* Odd - can't tell if the ifname exists */
20563448Sdh155122 		return (B_FALSE);
20573448Sdh155122 	}
20583448Sdh155122 	if (ioctl(so, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
20593448Sdh155122 		save_errno = errno;
20603448Sdh155122 		(void) close(so);
20613448Sdh155122 		errno = save_errno;
20623448Sdh155122 		return (B_FALSE);
20633448Sdh155122 	}
20643448Sdh155122 	(void) close(so);
20653448Sdh155122 	return (B_TRUE);
20663448Sdh155122 }
20673448Sdh155122 
20687267Sjv227347 /*
206911435SJordan.Vaughan@Sun.com  * Determines whether there is a net resource with the physical interface, IP
207011435SJordan.Vaughan@Sun.com  * address, and default router specified by 'tabptr' in the zone configuration
207111435SJordan.Vaughan@Sun.com  * to which 'handle' refers.  'tabptr' must have an interface, an address, a
207211435SJordan.Vaughan@Sun.com  * default router, or a combination of the three.  This function returns Z_OK
207311435SJordan.Vaughan@Sun.com  * iff there is exactly one net resource matching the query specified by
207411435SJordan.Vaughan@Sun.com  * 'tabptr'.  The function returns Z_INSUFFICIENT_SPEC if there are multiple
207511435SJordan.Vaughan@Sun.com  * matches or 'tabptr' does not specify a physical interface, address, or
207611435SJordan.Vaughan@Sun.com  * default router.  The function returns Z_NO_RESOURCE_ID if are no matches.
20777267Sjv227347  *
20787267Sjv227347  * Errors might also be returned if the entry that exactly matches the
20797267Sjv227347  * query lacks critical network resource information.
20807267Sjv227347  *
208111435SJordan.Vaughan@Sun.com  * If there is a single match, then the matching entry's physical interface, IP
208211435SJordan.Vaughan@Sun.com  * address, and default router information are stored in 'tabptr'.
20837267Sjv227347  */
20840Sstevel@tonic-gate int
zonecfg_lookup_nwif(zone_dochandle_t handle,struct zone_nwiftab * tabptr)20850Sstevel@tonic-gate zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
20860Sstevel@tonic-gate {
20877267Sjv227347 	xmlNodePtr cur;
20887267Sjv227347 	xmlNodePtr firstmatch;
20890Sstevel@tonic-gate 	int err;
20907267Sjv227347 	char address[INET6_ADDRSTRLEN];
20917267Sjv227347 	char physical[LIFNAMSIZ];
20927267Sjv227347 	size_t addrspec;		/* nonzero if tabptr has IP addr */
20937267Sjv227347 	size_t physspec;		/* nonzero if tabptr has interface */
209411435SJordan.Vaughan@Sun.com 	size_t defrouterspec;		/* nonzero if tabptr has def. router */
209512748SSowmini.Varadhan@oracle.COM 	size_t allowed_addrspec;
209612748SSowmini.Varadhan@oracle.COM 	zone_iptype_t iptype;
20970Sstevel@tonic-gate 
20980Sstevel@tonic-gate 	if (tabptr == NULL)
20990Sstevel@tonic-gate 		return (Z_INVAL);
21000Sstevel@tonic-gate 
21017267Sjv227347 	/*
210211435SJordan.Vaughan@Sun.com 	 * Determine the fields that will be searched.  There must be at least
210311435SJordan.Vaughan@Sun.com 	 * one.
210411435SJordan.Vaughan@Sun.com 	 *
210511435SJordan.Vaughan@Sun.com 	 * zone_nwif_address, zone_nwif_physical, and zone_nwif_defrouter are
210611435SJordan.Vaughan@Sun.com 	 * arrays, so no NULL checks are necessary.
21077267Sjv227347 	 */
21087267Sjv227347 	addrspec = strlen(tabptr->zone_nwif_address);
21097267Sjv227347 	physspec = strlen(tabptr->zone_nwif_physical);
211011435SJordan.Vaughan@Sun.com 	defrouterspec = strlen(tabptr->zone_nwif_defrouter);
211112748SSowmini.Varadhan@oracle.COM 	allowed_addrspec = strlen(tabptr->zone_nwif_allowed_address);
211212748SSowmini.Varadhan@oracle.COM 	if (addrspec != 0 && allowed_addrspec != 0)
211312748SSowmini.Varadhan@oracle.COM 		return (Z_INVAL); /* can't specify both */
211412748SSowmini.Varadhan@oracle.COM 	if (addrspec == 0 && physspec == 0 && defrouterspec == 0 &&
211512748SSowmini.Varadhan@oracle.COM 	    allowed_addrspec == 0)
211611435SJordan.Vaughan@Sun.com 		return (Z_INSUFFICIENT_SPEC);
21177267Sjv227347 
21180Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK)
21190Sstevel@tonic-gate 		return (err);
21200Sstevel@tonic-gate 
212112748SSowmini.Varadhan@oracle.COM 	if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK)
212212748SSowmini.Varadhan@oracle.COM 		return (err);
212311435SJordan.Vaughan@Sun.com 	/*
212411435SJordan.Vaughan@Sun.com 	 * Iterate over the configuration's elements and look for net elements
212511435SJordan.Vaughan@Sun.com 	 * that match the query.
212611435SJordan.Vaughan@Sun.com 	 */
21277267Sjv227347 	firstmatch = NULL;
21280Sstevel@tonic-gate 	cur = handle->zone_dh_cur;
21290Sstevel@tonic-gate 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
21307267Sjv227347 		/* Skip non-net elements */
21310Sstevel@tonic-gate 		if (xmlStrcmp(cur->name, DTD_ELEM_NET))
21320Sstevel@tonic-gate 			continue;
21337267Sjv227347 
21347267Sjv227347 		/*
213511435SJordan.Vaughan@Sun.com 		 * If any relevant fields don't match the query, then skip
213611435SJordan.Vaughan@Sun.com 		 * the current net element.
21377267Sjv227347 		 */
213811435SJordan.Vaughan@Sun.com 		if (physspec != 0 && (fetchprop(cur, DTD_ATTR_PHYSICAL,
213911435SJordan.Vaughan@Sun.com 		    physical, sizeof (physical)) != Z_OK ||
214011435SJordan.Vaughan@Sun.com 		    strcmp(tabptr->zone_nwif_physical, physical) != 0))
214111435SJordan.Vaughan@Sun.com 			continue;
214212748SSowmini.Varadhan@oracle.COM 		if (iptype == ZS_SHARED && addrspec != 0 &&
214312748SSowmini.Varadhan@oracle.COM 		    (fetchprop(cur, DTD_ATTR_ADDRESS, address,
214411435SJordan.Vaughan@Sun.com 		    sizeof (address)) != Z_OK ||
214511435SJordan.Vaughan@Sun.com 		    !zonecfg_same_net_address(tabptr->zone_nwif_address,
214611435SJordan.Vaughan@Sun.com 		    address)))
214711435SJordan.Vaughan@Sun.com 			continue;
214812748SSowmini.Varadhan@oracle.COM 		if (iptype == ZS_EXCLUSIVE && allowed_addrspec != 0 &&
214912748SSowmini.Varadhan@oracle.COM 		    (fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS, address,
215012748SSowmini.Varadhan@oracle.COM 		    sizeof (address)) != Z_OK ||
215112748SSowmini.Varadhan@oracle.COM 		    !zonecfg_same_net_address(tabptr->zone_nwif_allowed_address,
215212748SSowmini.Varadhan@oracle.COM 		    address)))
215312748SSowmini.Varadhan@oracle.COM 			continue;
215411435SJordan.Vaughan@Sun.com 		if (defrouterspec != 0 && (fetchprop(cur, DTD_ATTR_DEFROUTER,
215511435SJordan.Vaughan@Sun.com 		    address, sizeof (address)) != Z_OK ||
215611435SJordan.Vaughan@Sun.com 		    !zonecfg_same_net_address(tabptr->zone_nwif_defrouter,
215711435SJordan.Vaughan@Sun.com 		    address)))
215811435SJordan.Vaughan@Sun.com 			continue;
215911435SJordan.Vaughan@Sun.com 
216011435SJordan.Vaughan@Sun.com 		/*
216111435SJordan.Vaughan@Sun.com 		 * The current net element matches the query.  Select it if
216211435SJordan.Vaughan@Sun.com 		 * it's the first match; otherwise, abort the search.
216311435SJordan.Vaughan@Sun.com 		 */
216411435SJordan.Vaughan@Sun.com 		if (firstmatch == NULL)
216511435SJordan.Vaughan@Sun.com 			firstmatch = cur;
216611435SJordan.Vaughan@Sun.com 		else
216711435SJordan.Vaughan@Sun.com 			return (Z_INSUFFICIENT_SPEC);
21680Sstevel@tonic-gate 	}
21690Sstevel@tonic-gate 	if (firstmatch == NULL)
21700Sstevel@tonic-gate 		return (Z_NO_RESOURCE_ID);
21710Sstevel@tonic-gate 
21720Sstevel@tonic-gate 	cur = firstmatch;
21730Sstevel@tonic-gate 
21740Sstevel@tonic-gate 	if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
21750Sstevel@tonic-gate 	    sizeof (tabptr->zone_nwif_physical))) != Z_OK)
21760Sstevel@tonic-gate 		return (err);
21770Sstevel@tonic-gate 
217812748SSowmini.Varadhan@oracle.COM 	if (iptype == ZS_SHARED &&
217912748SSowmini.Varadhan@oracle.COM 	    (err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
21800Sstevel@tonic-gate 	    sizeof (tabptr->zone_nwif_address))) != Z_OK)
21810Sstevel@tonic-gate 		return (err);
21820Sstevel@tonic-gate 
218312748SSowmini.Varadhan@oracle.COM 	if (iptype == ZS_EXCLUSIVE &&
218412748SSowmini.Varadhan@oracle.COM 	    (err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
218512748SSowmini.Varadhan@oracle.COM 	    tabptr->zone_nwif_allowed_address,
218612748SSowmini.Varadhan@oracle.COM 	    sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK)
218712748SSowmini.Varadhan@oracle.COM 		return (err);
218812748SSowmini.Varadhan@oracle.COM 
21896076Sgfaden 	if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
21906076Sgfaden 	    tabptr->zone_nwif_defrouter,
21916076Sgfaden 	    sizeof (tabptr->zone_nwif_defrouter))) != Z_OK)
21926076Sgfaden 		return (err);
21936076Sgfaden 
21940Sstevel@tonic-gate 	return (Z_OK);
21950Sstevel@tonic-gate }
21960Sstevel@tonic-gate 
21970Sstevel@tonic-gate static int
zonecfg_add_nwif_core(zone_dochandle_t handle,struct zone_nwiftab * tabptr)21980Sstevel@tonic-gate zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
21990Sstevel@tonic-gate {
22000Sstevel@tonic-gate 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
22010Sstevel@tonic-gate 	int err;
22020Sstevel@tonic-gate 
22030Sstevel@tonic-gate 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL);
220412748SSowmini.Varadhan@oracle.COM 	if (strlen(tabptr->zone_nwif_address) > 0 &&
220512748SSowmini.Varadhan@oracle.COM 	    (err = newprop(newnode, DTD_ATTR_ADDRESS,
22060Sstevel@tonic-gate 	    tabptr->zone_nwif_address)) != Z_OK)
22070Sstevel@tonic-gate 		return (err);
220812748SSowmini.Varadhan@oracle.COM 	if (strlen(tabptr->zone_nwif_allowed_address) > 0 &&
220912748SSowmini.Varadhan@oracle.COM 	    (err = newprop(newnode, DTD_ATTR_ALLOWED_ADDRESS,
221012748SSowmini.Varadhan@oracle.COM 	    tabptr->zone_nwif_allowed_address)) != Z_OK)
221112748SSowmini.Varadhan@oracle.COM 		return (err);
2212228Sdp 	if ((err = newprop(newnode, DTD_ATTR_PHYSICAL,
22130Sstevel@tonic-gate 	    tabptr->zone_nwif_physical)) != Z_OK)
22140Sstevel@tonic-gate 		return (err);
22156738Sjparcel 	/*
22166738Sjparcel 	 * Do not add this property when it is not set, for backwards
22176738Sjparcel 	 * compatibility and because it is optional.
22186738Sjparcel 	 */
22196738Sjparcel 	if ((strlen(tabptr->zone_nwif_defrouter) > 0) &&
22206738Sjparcel 	    ((err = newprop(newnode, DTD_ATTR_DEFROUTER,
22216738Sjparcel 	    tabptr->zone_nwif_defrouter)) != Z_OK))
22226076Sgfaden 		return (err);
22230Sstevel@tonic-gate 	return (Z_OK);
22240Sstevel@tonic-gate }
22250Sstevel@tonic-gate 
22260Sstevel@tonic-gate int
zonecfg_add_nwif(zone_dochandle_t handle,struct zone_nwiftab * tabptr)22270Sstevel@tonic-gate zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
22280Sstevel@tonic-gate {
22290Sstevel@tonic-gate 	int err;
22300Sstevel@tonic-gate 
22310Sstevel@tonic-gate 	if (tabptr == NULL)
22320Sstevel@tonic-gate 		return (Z_INVAL);
22330Sstevel@tonic-gate 
22340Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK)
22350Sstevel@tonic-gate 		return (err);
22360Sstevel@tonic-gate 
22370Sstevel@tonic-gate 	if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK)
22380Sstevel@tonic-gate 		return (err);
22390Sstevel@tonic-gate 
22400Sstevel@tonic-gate 	return (Z_OK);
22410Sstevel@tonic-gate }
22420Sstevel@tonic-gate 
22430Sstevel@tonic-gate static int
zonecfg_delete_nwif_core(zone_dochandle_t handle,struct zone_nwiftab * tabptr)22440Sstevel@tonic-gate zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
22450Sstevel@tonic-gate {
22460Sstevel@tonic-gate 	xmlNodePtr cur = handle->zone_dh_cur;
224712748SSowmini.Varadhan@oracle.COM 	boolean_t addr_match, phys_match, allowed_addr_match;
22480Sstevel@tonic-gate 
22490Sstevel@tonic-gate 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
22500Sstevel@tonic-gate 		if (xmlStrcmp(cur->name, DTD_ELEM_NET))
22510Sstevel@tonic-gate 			continue;
22520Sstevel@tonic-gate 
22530Sstevel@tonic-gate 		addr_match = match_prop(cur, DTD_ATTR_ADDRESS,
22540Sstevel@tonic-gate 		    tabptr->zone_nwif_address);
225512748SSowmini.Varadhan@oracle.COM 		allowed_addr_match = match_prop(cur, DTD_ATTR_ALLOWED_ADDRESS,
225612748SSowmini.Varadhan@oracle.COM 		    tabptr->zone_nwif_allowed_address);
22570Sstevel@tonic-gate 		phys_match = match_prop(cur, DTD_ATTR_PHYSICAL,
22580Sstevel@tonic-gate 		    tabptr->zone_nwif_physical);
22590Sstevel@tonic-gate 
226012748SSowmini.Varadhan@oracle.COM 		if ((addr_match || allowed_addr_match) && phys_match) {
22610Sstevel@tonic-gate 			xmlUnlinkNode(cur);
22620Sstevel@tonic-gate 			xmlFreeNode(cur);
22630Sstevel@tonic-gate 			return (Z_OK);
22640Sstevel@tonic-gate 		}
22650Sstevel@tonic-gate 	}
22660Sstevel@tonic-gate 	return (Z_NO_RESOURCE_ID);
22670Sstevel@tonic-gate }
22680Sstevel@tonic-gate 
22690Sstevel@tonic-gate int
zonecfg_delete_nwif(zone_dochandle_t handle,struct zone_nwiftab * tabptr)22700Sstevel@tonic-gate zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
22710Sstevel@tonic-gate {
22720Sstevel@tonic-gate 	int err;
22730Sstevel@tonic-gate 
22740Sstevel@tonic-gate 	if (tabptr == NULL)
22750Sstevel@tonic-gate 		return (Z_INVAL);
22760Sstevel@tonic-gate 
22770Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK)
22780Sstevel@tonic-gate 		return (err);
22790Sstevel@tonic-gate 
22800Sstevel@tonic-gate 	if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK)
22810Sstevel@tonic-gate 		return (err);
22820Sstevel@tonic-gate 
22830Sstevel@tonic-gate 	return (Z_OK);
22840Sstevel@tonic-gate }
22850Sstevel@tonic-gate 
22860Sstevel@tonic-gate int
zonecfg_modify_nwif(zone_dochandle_t handle,struct zone_nwiftab * oldtabptr,struct zone_nwiftab * newtabptr)22870Sstevel@tonic-gate zonecfg_modify_nwif(
22880Sstevel@tonic-gate 	zone_dochandle_t handle,
22890Sstevel@tonic-gate 	struct zone_nwiftab *oldtabptr,
22900Sstevel@tonic-gate 	struct zone_nwiftab *newtabptr)
22910Sstevel@tonic-gate {
22920Sstevel@tonic-gate 	int err;
22930Sstevel@tonic-gate 
22940Sstevel@tonic-gate 	if (oldtabptr == NULL || newtabptr == NULL)
22950Sstevel@tonic-gate 		return (Z_INVAL);
22960Sstevel@tonic-gate 
22970Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK)
22980Sstevel@tonic-gate 		return (err);
22990Sstevel@tonic-gate 
23000Sstevel@tonic-gate 	if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK)
23010Sstevel@tonic-gate 		return (err);
23020Sstevel@tonic-gate 
23030Sstevel@tonic-gate 	if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK)
23040Sstevel@tonic-gate 		return (err);
23050Sstevel@tonic-gate 
23060Sstevel@tonic-gate 	return (Z_OK);
23070Sstevel@tonic-gate }
23080Sstevel@tonic-gate 
23098662SJordan.Vaughan@Sun.com /*
231012633Sjohn.levon@sun.com  * Must be a comma-separated list of alpha-numeric file system names.
231112633Sjohn.levon@sun.com  */
231212633Sjohn.levon@sun.com static int
zonecfg_valid_fs_allowed(const char * fsallowedp)231312633Sjohn.levon@sun.com zonecfg_valid_fs_allowed(const char *fsallowedp)
231412633Sjohn.levon@sun.com {
231512633Sjohn.levon@sun.com 	char tmp[ZONE_FS_ALLOWED_MAX];
231612633Sjohn.levon@sun.com 	char *cp = tmp;
231712633Sjohn.levon@sun.com 	char *p;
231812633Sjohn.levon@sun.com 
231912633Sjohn.levon@sun.com 	if (strlen(fsallowedp) > ZONE_FS_ALLOWED_MAX)
232012633Sjohn.levon@sun.com 		return (Z_TOO_BIG);
232112633Sjohn.levon@sun.com 
232212633Sjohn.levon@sun.com 	(void) strlcpy(tmp, fsallowedp, sizeof (tmp));
232312633Sjohn.levon@sun.com 
232412633Sjohn.levon@sun.com 	while (*cp != '\0') {
232512633Sjohn.levon@sun.com 		p = cp;
232612633Sjohn.levon@sun.com 		while (*p != '\0' && *p != ',') {
232712633Sjohn.levon@sun.com 			if (!isalnum(*p))
232812633Sjohn.levon@sun.com 				return (Z_INVALID_PROPERTY);
232912633Sjohn.levon@sun.com 			p++;
233012633Sjohn.levon@sun.com 		}
233112633Sjohn.levon@sun.com 
233212633Sjohn.levon@sun.com 		if (*p == ',') {
233312633Sjohn.levon@sun.com 			if (p == cp)
233412633Sjohn.levon@sun.com 				return (Z_INVALID_PROPERTY);
233512633Sjohn.levon@sun.com 
233612633Sjohn.levon@sun.com 			p++;
233712633Sjohn.levon@sun.com 
233812633Sjohn.levon@sun.com 			if (*p == '\0')
233912633Sjohn.levon@sun.com 				return (Z_INVALID_PROPERTY);
234012633Sjohn.levon@sun.com 		}
234112633Sjohn.levon@sun.com 
234212633Sjohn.levon@sun.com 		cp = p;
234312633Sjohn.levon@sun.com 	}
234412633Sjohn.levon@sun.com 
234512633Sjohn.levon@sun.com 	return (Z_OK);
234612633Sjohn.levon@sun.com }
234712633Sjohn.levon@sun.com 
234812633Sjohn.levon@sun.com int
zonecfg_get_fs_allowed(zone_dochandle_t handle,char * bufp,size_t buflen)234912633Sjohn.levon@sun.com zonecfg_get_fs_allowed(zone_dochandle_t handle, char *bufp, size_t buflen)
235012633Sjohn.levon@sun.com {
235112633Sjohn.levon@sun.com 	int err;
235212633Sjohn.levon@sun.com 
235312633Sjohn.levon@sun.com 	if ((err = getrootattr(handle, DTD_ATTR_FS_ALLOWED,
235412633Sjohn.levon@sun.com 	    bufp, buflen)) != Z_OK)
235512633Sjohn.levon@sun.com 		return (err);
235612633Sjohn.levon@sun.com 	if (bufp[0] == '\0')
235712633Sjohn.levon@sun.com 		return (Z_BAD_PROPERTY);
235812633Sjohn.levon@sun.com 	return (zonecfg_valid_fs_allowed(bufp));
235912633Sjohn.levon@sun.com }
236012633Sjohn.levon@sun.com 
236112633Sjohn.levon@sun.com int
zonecfg_set_fs_allowed(zone_dochandle_t handle,const char * bufp)236212633Sjohn.levon@sun.com zonecfg_set_fs_allowed(zone_dochandle_t handle, const char *bufp)
236312633Sjohn.levon@sun.com {
236412633Sjohn.levon@sun.com 	int err;
236512633Sjohn.levon@sun.com 
236612633Sjohn.levon@sun.com 	if (bufp == NULL || (err = zonecfg_valid_fs_allowed(bufp)) == Z_OK)
236712633Sjohn.levon@sun.com 		return (setrootattr(handle, DTD_ATTR_FS_ALLOWED, bufp));
236812633Sjohn.levon@sun.com 	return (err);
236912633Sjohn.levon@sun.com }
237012633Sjohn.levon@sun.com 
237112633Sjohn.levon@sun.com /*
237212633Sjohn.levon@sun.com  * Determines if the specified string is a valid hostid string.  This function
237312633Sjohn.levon@sun.com  * returns Z_OK if the string is a valid hostid string.  It returns Z_INVAL if
237412633Sjohn.levon@sun.com  * 'hostidp' is NULL, Z_TOO_BIG if 'hostidp' refers to a string buffer
237512633Sjohn.levon@sun.com  * containing a hex string with more than 8 digits, and Z_INVALID_PROPERTY if
237612633Sjohn.levon@sun.com  * the string has an invalid format.
237712633Sjohn.levon@sun.com  */
237812633Sjohn.levon@sun.com static int
zonecfg_valid_hostid(const char * hostidp)237912633Sjohn.levon@sun.com zonecfg_valid_hostid(const char *hostidp)
238012633Sjohn.levon@sun.com {
238112633Sjohn.levon@sun.com 	char *currentp;
238212633Sjohn.levon@sun.com 	u_longlong_t hostidval;
238312633Sjohn.levon@sun.com 	size_t len;
238412633Sjohn.levon@sun.com 
238512633Sjohn.levon@sun.com 	if (hostidp == NULL)
238612633Sjohn.levon@sun.com 		return (Z_INVAL);
238712633Sjohn.levon@sun.com 
238812633Sjohn.levon@sun.com 	/* Empty strings and strings with whitespace are invalid. */
238912633Sjohn.levon@sun.com 	if (*hostidp == '\0')
239012633Sjohn.levon@sun.com 		return (Z_INVALID_PROPERTY);
239112633Sjohn.levon@sun.com 	for (currentp = (char *)hostidp; *currentp != '\0'; ++currentp) {
239212633Sjohn.levon@sun.com 		if (isspace(*currentp))
239312633Sjohn.levon@sun.com 			return (Z_INVALID_PROPERTY);
239412633Sjohn.levon@sun.com 	}
239512633Sjohn.levon@sun.com 	len = (size_t)(currentp - hostidp);
239612633Sjohn.levon@sun.com 
239712633Sjohn.levon@sun.com 	/*
239812633Sjohn.levon@sun.com 	 * The caller might pass a hostid that is larger than the maximum
239912633Sjohn.levon@sun.com 	 * unsigned 32-bit integral value.  Check for this!  Also, make sure
240012633Sjohn.levon@sun.com 	 * that the whole string is converted (this helps us find illegal
240112633Sjohn.levon@sun.com 	 * characters) and that the whole string fits within a buffer of size
240212633Sjohn.levon@sun.com 	 * HW_HOSTID_LEN.
240312633Sjohn.levon@sun.com 	 */
240412633Sjohn.levon@sun.com 	currentp = (char *)hostidp;
240512633Sjohn.levon@sun.com 	if (strncmp(hostidp, "0x", 2) == 0 || strncmp(hostidp, "0X", 2) == 0)
240612633Sjohn.levon@sun.com 		currentp += 2;
240712633Sjohn.levon@sun.com 	hostidval = strtoull(currentp, &currentp, 16);
240812633Sjohn.levon@sun.com 	if ((size_t)(currentp - hostidp) >= HW_HOSTID_LEN)
240912633Sjohn.levon@sun.com 		return (Z_TOO_BIG);
241012633Sjohn.levon@sun.com 	if (hostidval > UINT_MAX || hostidval == HW_INVALID_HOSTID ||
241112633Sjohn.levon@sun.com 	    currentp != hostidp + len)
241212633Sjohn.levon@sun.com 		return (Z_INVALID_PROPERTY);
241312633Sjohn.levon@sun.com 	return (Z_OK);
241412633Sjohn.levon@sun.com }
241512633Sjohn.levon@sun.com 
241612633Sjohn.levon@sun.com /*
24178662SJordan.Vaughan@Sun.com  * Gets the zone hostid string stored in the specified zone configuration
24188662SJordan.Vaughan@Sun.com  * document.  This function returns Z_OK on success.  Z_BAD_PROPERTY is returned
24198662SJordan.Vaughan@Sun.com  * if the config file doesn't specify a hostid or if the hostid is blank.
24208662SJordan.Vaughan@Sun.com  *
24218662SJordan.Vaughan@Sun.com  * Note that buflen should be at least HW_HOSTID_LEN.
24228662SJordan.Vaughan@Sun.com  */
24238662SJordan.Vaughan@Sun.com int
zonecfg_get_hostid(zone_dochandle_t handle,char * bufp,size_t buflen)24248662SJordan.Vaughan@Sun.com zonecfg_get_hostid(zone_dochandle_t handle, char *bufp, size_t buflen)
24258662SJordan.Vaughan@Sun.com {
24268662SJordan.Vaughan@Sun.com 	int err;
24278662SJordan.Vaughan@Sun.com 
24288662SJordan.Vaughan@Sun.com 	if ((err = getrootattr(handle, DTD_ATTR_HOSTID, bufp, buflen)) != Z_OK)
24298662SJordan.Vaughan@Sun.com 		return (err);
24308662SJordan.Vaughan@Sun.com 	if (bufp[0] == '\0')
24318662SJordan.Vaughan@Sun.com 		return (Z_BAD_PROPERTY);
243212633Sjohn.levon@sun.com 	return (zonecfg_valid_hostid(bufp));
24338662SJordan.Vaughan@Sun.com }
24348662SJordan.Vaughan@Sun.com 
24358662SJordan.Vaughan@Sun.com /*
24368662SJordan.Vaughan@Sun.com  * Sets the hostid string in the specified zone config document to the given
24378662SJordan.Vaughan@Sun.com  * string value.  If 'hostidp' is NULL, then the config document's hostid
24388662SJordan.Vaughan@Sun.com  * attribute is cleared.  Non-NULL hostids are validated.  This function returns
24398662SJordan.Vaughan@Sun.com  * Z_OK on success.  Any other return value indicates failure.
24408662SJordan.Vaughan@Sun.com  */
24418662SJordan.Vaughan@Sun.com int
zonecfg_set_hostid(zone_dochandle_t handle,const char * hostidp)24428662SJordan.Vaughan@Sun.com zonecfg_set_hostid(zone_dochandle_t handle, const char *hostidp)
24438662SJordan.Vaughan@Sun.com {
24448662SJordan.Vaughan@Sun.com 	int err;
24458662SJordan.Vaughan@Sun.com 
24468662SJordan.Vaughan@Sun.com 	/*
24478662SJordan.Vaughan@Sun.com 	 * A NULL hostid string is interpreted as a request to clear the
24488662SJordan.Vaughan@Sun.com 	 * hostid.
24498662SJordan.Vaughan@Sun.com 	 */
24508662SJordan.Vaughan@Sun.com 	if (hostidp == NULL || (err = zonecfg_valid_hostid(hostidp)) == Z_OK)
24518662SJordan.Vaughan@Sun.com 		return (setrootattr(handle, DTD_ATTR_HOSTID, hostidp));
24528662SJordan.Vaughan@Sun.com 	return (err);
24538662SJordan.Vaughan@Sun.com }
24548662SJordan.Vaughan@Sun.com 
24550Sstevel@tonic-gate int
zonecfg_lookup_dev(zone_dochandle_t handle,struct zone_devtab * tabptr)24560Sstevel@tonic-gate zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
24570Sstevel@tonic-gate {
24580Sstevel@tonic-gate 	xmlNodePtr cur, firstmatch;
24590Sstevel@tonic-gate 	int err;
24600Sstevel@tonic-gate 	char match[MAXPATHLEN];
24610Sstevel@tonic-gate 
24620Sstevel@tonic-gate 	if (tabptr == NULL)
24630Sstevel@tonic-gate 		return (Z_INVAL);
24640Sstevel@tonic-gate 
24650Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK)
24660Sstevel@tonic-gate 		return (err);
24670Sstevel@tonic-gate 
24680Sstevel@tonic-gate 	cur = handle->zone_dh_cur;
24690Sstevel@tonic-gate 	firstmatch = NULL;
24700Sstevel@tonic-gate 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
24710Sstevel@tonic-gate 		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
24720Sstevel@tonic-gate 			continue;
24730Sstevel@tonic-gate 		if (strlen(tabptr->zone_dev_match) == 0)
24740Sstevel@tonic-gate 			continue;
24750Sstevel@tonic-gate 
24760Sstevel@tonic-gate 		if ((fetchprop(cur, DTD_ATTR_MATCH, match,
24770Sstevel@tonic-gate 		    sizeof (match)) == Z_OK)) {
24780Sstevel@tonic-gate 			if (strcmp(tabptr->zone_dev_match,
24790Sstevel@tonic-gate 			    match) == 0) {
24800Sstevel@tonic-gate 				if (firstmatch == NULL)
24810Sstevel@tonic-gate 					firstmatch = cur;
24820Sstevel@tonic-gate 				else if (firstmatch != cur)
24830Sstevel@tonic-gate 					return (Z_INSUFFICIENT_SPEC);
24840Sstevel@tonic-gate 			} else {
24850Sstevel@tonic-gate 				/*
24860Sstevel@tonic-gate 				 * If another property matched but this
24870Sstevel@tonic-gate 				 * one doesn't then reset firstmatch.
24880Sstevel@tonic-gate 				 */
24890Sstevel@tonic-gate 				if (firstmatch == cur)
24900Sstevel@tonic-gate 					firstmatch = NULL;
24910Sstevel@tonic-gate 			}
24920Sstevel@tonic-gate 		}
24930Sstevel@tonic-gate 	}
24940Sstevel@tonic-gate 	if (firstmatch == NULL)
24950Sstevel@tonic-gate 		return (Z_NO_RESOURCE_ID);
24960Sstevel@tonic-gate 
24970Sstevel@tonic-gate 	cur = firstmatch;
24980Sstevel@tonic-gate 
24990Sstevel@tonic-gate 	if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
25000Sstevel@tonic-gate 	    sizeof (tabptr->zone_dev_match))) != Z_OK)
25010Sstevel@tonic-gate 		return (err);
25020Sstevel@tonic-gate 
25030Sstevel@tonic-gate 	return (Z_OK);
25040Sstevel@tonic-gate }
25050Sstevel@tonic-gate 
25060Sstevel@tonic-gate static int
zonecfg_add_dev_core(zone_dochandle_t handle,struct zone_devtab * tabptr)25070Sstevel@tonic-gate zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
25080Sstevel@tonic-gate {
25090Sstevel@tonic-gate 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
25100Sstevel@tonic-gate 	int err;
25110Sstevel@tonic-gate 
25120Sstevel@tonic-gate 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL);
25130Sstevel@tonic-gate 
2514228Sdp 	if ((err = newprop(newnode, DTD_ATTR_MATCH,
25150Sstevel@tonic-gate 	    tabptr->zone_dev_match)) != Z_OK)
25160Sstevel@tonic-gate 		return (err);
25170Sstevel@tonic-gate 
25180Sstevel@tonic-gate 	return (Z_OK);
25190Sstevel@tonic-gate }
25200Sstevel@tonic-gate 
25210Sstevel@tonic-gate int
zonecfg_add_dev(zone_dochandle_t handle,struct zone_devtab * tabptr)25220Sstevel@tonic-gate zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
25230Sstevel@tonic-gate {
25240Sstevel@tonic-gate 	int err;
25250Sstevel@tonic-gate 
25260Sstevel@tonic-gate 	if (tabptr == NULL)
25270Sstevel@tonic-gate 		return (Z_INVAL);
25280Sstevel@tonic-gate 
25290Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK)
25300Sstevel@tonic-gate 		return (err);
25310Sstevel@tonic-gate 
25320Sstevel@tonic-gate 	if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK)
25330Sstevel@tonic-gate 		return (err);
25340Sstevel@tonic-gate 
25350Sstevel@tonic-gate 	return (Z_OK);
25360Sstevel@tonic-gate }
25370Sstevel@tonic-gate 
25380Sstevel@tonic-gate static int
zonecfg_delete_dev_core(zone_dochandle_t handle,struct zone_devtab * tabptr)25390Sstevel@tonic-gate zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
25400Sstevel@tonic-gate {
25412621Sllai1 	xmlNodePtr cur = handle->zone_dh_cur;
25420Sstevel@tonic-gate 	int match_match;
25430Sstevel@tonic-gate 
25440Sstevel@tonic-gate 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
25450Sstevel@tonic-gate 		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
25460Sstevel@tonic-gate 			continue;
25470Sstevel@tonic-gate 
25480Sstevel@tonic-gate 		match_match = match_prop(cur, DTD_ATTR_MATCH,
25490Sstevel@tonic-gate 		    tabptr->zone_dev_match);
25500Sstevel@tonic-gate 
25510Sstevel@tonic-gate 		if (match_match) {
25520Sstevel@tonic-gate 			xmlUnlinkNode(cur);
25530Sstevel@tonic-gate 			xmlFreeNode(cur);
25540Sstevel@tonic-gate 			return (Z_OK);
25550Sstevel@tonic-gate 		}
25560Sstevel@tonic-gate 	}
25570Sstevel@tonic-gate 	return (Z_NO_RESOURCE_ID);
25580Sstevel@tonic-gate }
25590Sstevel@tonic-gate 
25600Sstevel@tonic-gate int
zonecfg_delete_dev(zone_dochandle_t handle,struct zone_devtab * tabptr)25610Sstevel@tonic-gate zonecfg_delete_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
25620Sstevel@tonic-gate {
25630Sstevel@tonic-gate 	int err;
25640Sstevel@tonic-gate 
25650Sstevel@tonic-gate 	if (tabptr == NULL)
25660Sstevel@tonic-gate 		return (Z_INVAL);
25670Sstevel@tonic-gate 
25680Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK)
25690Sstevel@tonic-gate 		return (err);
25700Sstevel@tonic-gate 
25710Sstevel@tonic-gate 	if ((err = zonecfg_delete_dev_core(handle, tabptr)) != Z_OK)
25720Sstevel@tonic-gate 		return (err);
25730Sstevel@tonic-gate 
25740Sstevel@tonic-gate 	return (Z_OK);
25750Sstevel@tonic-gate }
25760Sstevel@tonic-gate 
25770Sstevel@tonic-gate int
zonecfg_modify_dev(zone_dochandle_t handle,struct zone_devtab * oldtabptr,struct zone_devtab * newtabptr)25780Sstevel@tonic-gate zonecfg_modify_dev(
25790Sstevel@tonic-gate 	zone_dochandle_t handle,
25800Sstevel@tonic-gate 	struct zone_devtab *oldtabptr,
25810Sstevel@tonic-gate 	struct zone_devtab *newtabptr)
25820Sstevel@tonic-gate {
25830Sstevel@tonic-gate 	int err;
25840Sstevel@tonic-gate 
25850Sstevel@tonic-gate 	if (oldtabptr == NULL || newtabptr == NULL)
25860Sstevel@tonic-gate 		return (Z_INVAL);
25870Sstevel@tonic-gate 
25880Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK)
25890Sstevel@tonic-gate 		return (err);
25900Sstevel@tonic-gate 
25910Sstevel@tonic-gate 	if ((err = zonecfg_delete_dev_core(handle, oldtabptr)) != Z_OK)
25920Sstevel@tonic-gate 		return (err);
25930Sstevel@tonic-gate 
25940Sstevel@tonic-gate 	if ((err = zonecfg_add_dev_core(handle, newtabptr)) != Z_OK)
25950Sstevel@tonic-gate 		return (err);
25960Sstevel@tonic-gate 
25970Sstevel@tonic-gate 	return (Z_OK);
25980Sstevel@tonic-gate }
25990Sstevel@tonic-gate 
260012578SGlenn.Faden@Sun.COM static int
zonecfg_add_auth_core(zone_dochandle_t handle,struct zone_admintab * tabptr,char * zonename)260112578SGlenn.Faden@Sun.COM zonecfg_add_auth_core(zone_dochandle_t handle, struct zone_admintab *tabptr,
260212578SGlenn.Faden@Sun.COM     char *zonename)
260312578SGlenn.Faden@Sun.COM {
260412578SGlenn.Faden@Sun.COM 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
260512578SGlenn.Faden@Sun.COM 	int err;
260612578SGlenn.Faden@Sun.COM 
260712578SGlenn.Faden@Sun.COM 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ADMIN, NULL);
260812578SGlenn.Faden@Sun.COM 	err = newprop(newnode, DTD_ATTR_USER, tabptr->zone_admin_user);
260912578SGlenn.Faden@Sun.COM 	if (err != Z_OK)
261012578SGlenn.Faden@Sun.COM 		return (err);
261112578SGlenn.Faden@Sun.COM 	err = newprop(newnode, DTD_ATTR_AUTHS, tabptr->zone_admin_auths);
261212578SGlenn.Faden@Sun.COM 	if (err != Z_OK)
261312578SGlenn.Faden@Sun.COM 		return (err);
261412578SGlenn.Faden@Sun.COM 	if ((err = zonecfg_remove_userauths(
261512578SGlenn.Faden@Sun.COM 	    handle, tabptr->zone_admin_user, zonename, B_FALSE)) != Z_OK)
261612578SGlenn.Faden@Sun.COM 		return (err);
261712578SGlenn.Faden@Sun.COM 	return (Z_OK);
261812578SGlenn.Faden@Sun.COM }
261912578SGlenn.Faden@Sun.COM 
262012578SGlenn.Faden@Sun.COM int
zonecfg_add_admin(zone_dochandle_t handle,struct zone_admintab * tabptr,char * zonename)262112578SGlenn.Faden@Sun.COM zonecfg_add_admin(zone_dochandle_t handle, struct zone_admintab *tabptr,
262212578SGlenn.Faden@Sun.COM     char *zonename)
262312578SGlenn.Faden@Sun.COM {
262412578SGlenn.Faden@Sun.COM 	int err;
262512578SGlenn.Faden@Sun.COM 
262612578SGlenn.Faden@Sun.COM 	if (tabptr == NULL)
262712578SGlenn.Faden@Sun.COM 		return (Z_INVAL);
262812578SGlenn.Faden@Sun.COM 
262912578SGlenn.Faden@Sun.COM 	if ((err = operation_prep(handle)) != Z_OK)
263012578SGlenn.Faden@Sun.COM 		return (err);
263112578SGlenn.Faden@Sun.COM 
263212578SGlenn.Faden@Sun.COM 	if ((err = zonecfg_add_auth_core(handle, tabptr,
263312578SGlenn.Faden@Sun.COM 	    zonename)) != Z_OK)
263412578SGlenn.Faden@Sun.COM 		return (err);
263512578SGlenn.Faden@Sun.COM 
263612578SGlenn.Faden@Sun.COM 	return (Z_OK);
263712578SGlenn.Faden@Sun.COM }
263812578SGlenn.Faden@Sun.COM static int
zonecfg_delete_auth_core(zone_dochandle_t handle,struct zone_admintab * tabptr,char * zonename)263912578SGlenn.Faden@Sun.COM zonecfg_delete_auth_core(zone_dochandle_t handle, struct zone_admintab *tabptr,
264012578SGlenn.Faden@Sun.COM     char *zonename)
264112578SGlenn.Faden@Sun.COM {
264212578SGlenn.Faden@Sun.COM 	xmlNodePtr cur = handle->zone_dh_cur;
264312578SGlenn.Faden@Sun.COM 	boolean_t auth_match;
264412578SGlenn.Faden@Sun.COM 	int err;
264512578SGlenn.Faden@Sun.COM 
264612578SGlenn.Faden@Sun.COM 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
264712578SGlenn.Faden@Sun.COM 		if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
264812578SGlenn.Faden@Sun.COM 			continue;
264912578SGlenn.Faden@Sun.COM 		auth_match = match_prop(cur, DTD_ATTR_USER,
265012578SGlenn.Faden@Sun.COM 		    tabptr->zone_admin_user);
265112578SGlenn.Faden@Sun.COM 		if (auth_match) {
265212578SGlenn.Faden@Sun.COM 			if ((err = zonecfg_insert_userauths(
265312578SGlenn.Faden@Sun.COM 			    handle, tabptr->zone_admin_user,
265412578SGlenn.Faden@Sun.COM 			    zonename)) != Z_OK)
265512578SGlenn.Faden@Sun.COM 				return (err);
265612578SGlenn.Faden@Sun.COM 			xmlUnlinkNode(cur);
265712578SGlenn.Faden@Sun.COM 			xmlFreeNode(cur);
265812578SGlenn.Faden@Sun.COM 			return (Z_OK);
265912578SGlenn.Faden@Sun.COM 		}
266012578SGlenn.Faden@Sun.COM 	}
266112578SGlenn.Faden@Sun.COM 	return (Z_NO_RESOURCE_ID);
266212578SGlenn.Faden@Sun.COM }
266312578SGlenn.Faden@Sun.COM 
266412578SGlenn.Faden@Sun.COM int
zonecfg_delete_admin(zone_dochandle_t handle,struct zone_admintab * tabptr,char * zonename)266512578SGlenn.Faden@Sun.COM zonecfg_delete_admin(zone_dochandle_t handle, struct zone_admintab *tabptr,
266612578SGlenn.Faden@Sun.COM     char *zonename)
266712578SGlenn.Faden@Sun.COM {
266812578SGlenn.Faden@Sun.COM 	int err;
266912578SGlenn.Faden@Sun.COM 
267012578SGlenn.Faden@Sun.COM 	if (tabptr == NULL)
267112578SGlenn.Faden@Sun.COM 		return (Z_INVAL);
267212578SGlenn.Faden@Sun.COM 
267312578SGlenn.Faden@Sun.COM 	if ((err = operation_prep(handle)) != Z_OK)
267412578SGlenn.Faden@Sun.COM 		return (err);
267512578SGlenn.Faden@Sun.COM 
267612578SGlenn.Faden@Sun.COM 	if ((err = zonecfg_delete_auth_core(handle, tabptr, zonename)) != Z_OK)
267712578SGlenn.Faden@Sun.COM 		return (err);
267812578SGlenn.Faden@Sun.COM 
267912578SGlenn.Faden@Sun.COM 	return (Z_OK);
268012578SGlenn.Faden@Sun.COM }
268112578SGlenn.Faden@Sun.COM 
268212578SGlenn.Faden@Sun.COM int
zonecfg_modify_admin(zone_dochandle_t handle,struct zone_admintab * oldtabptr,struct zone_admintab * newtabptr,char * zonename)268312578SGlenn.Faden@Sun.COM zonecfg_modify_admin(zone_dochandle_t handle, struct zone_admintab *oldtabptr,
268412578SGlenn.Faden@Sun.COM     struct zone_admintab *newtabptr, char *zonename)
268512578SGlenn.Faden@Sun.COM {
268612578SGlenn.Faden@Sun.COM 	int err;
268712578SGlenn.Faden@Sun.COM 
268812578SGlenn.Faden@Sun.COM 	if (oldtabptr == NULL || newtabptr == NULL)
268912578SGlenn.Faden@Sun.COM 		return (Z_INVAL);
269012578SGlenn.Faden@Sun.COM 
269112578SGlenn.Faden@Sun.COM 	if ((err = operation_prep(handle)) != Z_OK)
269212578SGlenn.Faden@Sun.COM 		return (err);
269312578SGlenn.Faden@Sun.COM 
269412578SGlenn.Faden@Sun.COM 	if ((err = zonecfg_delete_auth_core(handle, oldtabptr, zonename))
269512578SGlenn.Faden@Sun.COM 	    != Z_OK)
269612578SGlenn.Faden@Sun.COM 		return (err);
269712578SGlenn.Faden@Sun.COM 
269812578SGlenn.Faden@Sun.COM 	if ((err = zonecfg_add_auth_core(handle, newtabptr,
269912578SGlenn.Faden@Sun.COM 	    zonename)) != Z_OK)
270012578SGlenn.Faden@Sun.COM 		return (err);
270112578SGlenn.Faden@Sun.COM 
270212578SGlenn.Faden@Sun.COM 	return (Z_OK);
270312578SGlenn.Faden@Sun.COM }
270412578SGlenn.Faden@Sun.COM 
270512578SGlenn.Faden@Sun.COM int
zonecfg_lookup_admin(zone_dochandle_t handle,struct zone_admintab * tabptr)270612578SGlenn.Faden@Sun.COM zonecfg_lookup_admin(zone_dochandle_t handle, struct zone_admintab *tabptr)
270712578SGlenn.Faden@Sun.COM {
270812578SGlenn.Faden@Sun.COM 	xmlNodePtr cur, firstmatch;
270912578SGlenn.Faden@Sun.COM 	int err;
271012578SGlenn.Faden@Sun.COM 	char user[MAXUSERNAME];
271112578SGlenn.Faden@Sun.COM 
271212578SGlenn.Faden@Sun.COM 	if (tabptr == NULL)
271312578SGlenn.Faden@Sun.COM 		return (Z_INVAL);
271412578SGlenn.Faden@Sun.COM 
271512578SGlenn.Faden@Sun.COM 	if ((err = operation_prep(handle)) != Z_OK)
271612578SGlenn.Faden@Sun.COM 		return (err);
271712578SGlenn.Faden@Sun.COM 
271812578SGlenn.Faden@Sun.COM 	cur = handle->zone_dh_cur;
271912578SGlenn.Faden@Sun.COM 	firstmatch = NULL;
272012578SGlenn.Faden@Sun.COM 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
272112578SGlenn.Faden@Sun.COM 		if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
272212578SGlenn.Faden@Sun.COM 			continue;
272312578SGlenn.Faden@Sun.COM 		if (strlen(tabptr->zone_admin_user) > 0) {
272412578SGlenn.Faden@Sun.COM 			if ((fetchprop(cur, DTD_ATTR_USER, user,
272512578SGlenn.Faden@Sun.COM 			    sizeof (user)) == Z_OK) &&
272612578SGlenn.Faden@Sun.COM 			    (strcmp(tabptr->zone_admin_user, user) == 0)) {
272712578SGlenn.Faden@Sun.COM 				if (firstmatch == NULL)
272812578SGlenn.Faden@Sun.COM 					firstmatch = cur;
272912578SGlenn.Faden@Sun.COM 				else
273012578SGlenn.Faden@Sun.COM 					return (Z_INSUFFICIENT_SPEC);
273112578SGlenn.Faden@Sun.COM 			}
273212578SGlenn.Faden@Sun.COM 		}
273312578SGlenn.Faden@Sun.COM 	}
273412578SGlenn.Faden@Sun.COM 	if (firstmatch == NULL)
273512578SGlenn.Faden@Sun.COM 		return (Z_NO_RESOURCE_ID);
273612578SGlenn.Faden@Sun.COM 
273712578SGlenn.Faden@Sun.COM 	cur = firstmatch;
273812578SGlenn.Faden@Sun.COM 
273912578SGlenn.Faden@Sun.COM 	if ((err = fetchprop(cur, DTD_ATTR_USER, tabptr->zone_admin_user,
274012578SGlenn.Faden@Sun.COM 	    sizeof (tabptr->zone_admin_user))) != Z_OK)
274112578SGlenn.Faden@Sun.COM 		return (err);
274212578SGlenn.Faden@Sun.COM 
274312578SGlenn.Faden@Sun.COM 	if ((err = fetchprop(cur, DTD_ATTR_AUTHS, tabptr->zone_admin_auths,
274412578SGlenn.Faden@Sun.COM 	    sizeof (tabptr->zone_admin_auths))) != Z_OK)
274512578SGlenn.Faden@Sun.COM 		return (err);
274612578SGlenn.Faden@Sun.COM 
274712578SGlenn.Faden@Sun.COM 	return (Z_OK);
274812578SGlenn.Faden@Sun.COM }
274912578SGlenn.Faden@Sun.COM 
275012578SGlenn.Faden@Sun.COM 
27517089Sgjelinek /* Lock to serialize all devwalks */
27521507Sgjelinek static pthread_mutex_t zonecfg_devwalk_lock = PTHREAD_MUTEX_INITIALIZER;
27531507Sgjelinek /*
27547089Sgjelinek  * Global variables used to pass data from zonecfg_dev_manifest to the nftw
27551507Sgjelinek  * call-back (zonecfg_devwalk_cb).  g_devwalk_data is really the void*
27567089Sgjelinek  * parameter and g_devwalk_cb is really the *cb parameter from
27577089Sgjelinek  * zonecfg_dev_manifest.
27581507Sgjelinek  */
27597089Sgjelinek typedef struct __g_devwalk_data *g_devwalk_data_t;
27607089Sgjelinek static g_devwalk_data_t g_devwalk_data;
27611507Sgjelinek static int (*g_devwalk_cb)(const char *, uid_t, gid_t, mode_t, const char *,
27621507Sgjelinek     void *);
27631507Sgjelinek static size_t g_devwalk_skip_prefix;
27641507Sgjelinek 
27651507Sgjelinek /*
27667089Sgjelinek  * zonecfg_dev_manifest call-back function used during detach to generate the
27677089Sgjelinek  * dev info in the manifest.
27687089Sgjelinek  */
27697089Sgjelinek static int
get_detach_dev_entry(const char * name,uid_t uid,gid_t gid,mode_t mode,const char * acl,void * hdl)27707089Sgjelinek get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode,
27717089Sgjelinek     const char *acl, void *hdl)
27727089Sgjelinek {
27737089Sgjelinek 	zone_dochandle_t handle = (zone_dochandle_t)hdl;
27747089Sgjelinek 	xmlNodePtr newnode;
27757089Sgjelinek 	xmlNodePtr cur;
27767089Sgjelinek 	int err;
27777089Sgjelinek 	char buf[128];
27787089Sgjelinek 
27797089Sgjelinek 	if ((err = operation_prep(handle)) != Z_OK)
27807089Sgjelinek 		return (err);
27817089Sgjelinek 
27827089Sgjelinek 	cur = handle->zone_dh_cur;
27837089Sgjelinek 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL);
27847089Sgjelinek 	if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK)
27857089Sgjelinek 		return (err);
27867089Sgjelinek 	(void) snprintf(buf, sizeof (buf), "%lu", uid);
27877089Sgjelinek 	if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK)
27887089Sgjelinek 		return (err);
27897089Sgjelinek 	(void) snprintf(buf, sizeof (buf), "%lu", gid);
27907089Sgjelinek 	if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK)
27917089Sgjelinek 		return (err);
27927089Sgjelinek 	(void) snprintf(buf, sizeof (buf), "%o", mode);
27937089Sgjelinek 	if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK)
27947089Sgjelinek 		return (err);
27957089Sgjelinek 	if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK)
27967089Sgjelinek 		return (err);
27977089Sgjelinek 	return (Z_OK);
27987089Sgjelinek }
27997089Sgjelinek 
28007089Sgjelinek /*
28017089Sgjelinek  * This is the nftw call-back function used by zonecfg_dev_manifest.  It is
28027089Sgjelinek  * responsible for calling the actual call-back.
28031507Sgjelinek  */
28041507Sgjelinek /* ARGSUSED2 */
28051507Sgjelinek static int
zonecfg_devwalk_cb(const char * path,const struct stat * st,int f,struct FTW * ftw)28061507Sgjelinek zonecfg_devwalk_cb(const char *path, const struct stat *st, int f,
28071507Sgjelinek     struct FTW *ftw)
28081507Sgjelinek {
28091507Sgjelinek 	acl_t *acl;
28101507Sgjelinek 	char *acl_txt = NULL;
28111507Sgjelinek 
28121507Sgjelinek 	/* skip all but character and block devices */
28131507Sgjelinek 	if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode))
28141507Sgjelinek 		return (0);
28151507Sgjelinek 
28161507Sgjelinek 	if ((acl_get(path, ACL_NO_TRIVIAL, &acl) == 0) &&
28171507Sgjelinek 	    acl != NULL) {
28181507Sgjelinek 		acl_txt = acl_totext(acl, ACL_NORESOLVE);
28191507Sgjelinek 		acl_free(acl);
28201507Sgjelinek 	}
28211507Sgjelinek 
28221507Sgjelinek 	if (strlen(path) <= g_devwalk_skip_prefix)
28231507Sgjelinek 		return (0);
28241507Sgjelinek 
28251507Sgjelinek 	g_devwalk_cb(path + g_devwalk_skip_prefix, st->st_uid, st->st_gid,
28261507Sgjelinek 	    st->st_mode & S_IAMB, acl_txt != NULL ? acl_txt : "",
28271507Sgjelinek 	    g_devwalk_data);
28281507Sgjelinek 	free(acl_txt);
28291507Sgjelinek 	return (0);
28301507Sgjelinek }
28311507Sgjelinek 
28321507Sgjelinek /*
28337089Sgjelinek  * Walk the dev tree for the zone specified by hdl and call the
28347089Sgjelinek  * get_detach_dev_entry call-back function for each entry in the tree.  The
28357089Sgjelinek  * call-back will be passed the name, uid, gid, mode, acl string and the
28367089Sgjelinek  * handle input parameter for each dev entry.
28371507Sgjelinek  *
28387089Sgjelinek  * Data is passed to get_detach_dev_entry through the global variables
28391507Sgjelinek  * g_devwalk_data, *g_devwalk_cb, and g_devwalk_skip_prefix.  The
28407089Sgjelinek  * zonecfg_devwalk_cb function will actually call get_detach_dev_entry.
28411507Sgjelinek  */
28421507Sgjelinek int
zonecfg_dev_manifest(zone_dochandle_t hdl)28437089Sgjelinek zonecfg_dev_manifest(zone_dochandle_t hdl)
28441507Sgjelinek {
28451507Sgjelinek 	char path[MAXPATHLEN];
28461507Sgjelinek 	int ret;
28471507Sgjelinek 
28481507Sgjelinek 	if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK)
28491507Sgjelinek 		return (ret);
28501507Sgjelinek 
28511507Sgjelinek 	if (strlcat(path, "/dev", sizeof (path)) >= sizeof (path))
28521507Sgjelinek 		return (Z_TOO_BIG);
28531507Sgjelinek 
28541507Sgjelinek 	/*
28557089Sgjelinek 	 * We have to serialize all devwalks in the same process
28561507Sgjelinek 	 * (which should be fine), since nftw() is so badly designed.
28571507Sgjelinek 	 */
28581507Sgjelinek 	(void) pthread_mutex_lock(&zonecfg_devwalk_lock);
28591507Sgjelinek 
28607089Sgjelinek 	g_devwalk_skip_prefix = strlen(path) + 1;
28617089Sgjelinek 	g_devwalk_data = (g_devwalk_data_t)hdl;
28627089Sgjelinek 	g_devwalk_cb = get_detach_dev_entry;
28631507Sgjelinek 	(void) nftw(path, zonecfg_devwalk_cb, 0, FTW_PHYS);
28641507Sgjelinek 
28651507Sgjelinek 	(void) pthread_mutex_unlock(&zonecfg_devwalk_lock);
28661507Sgjelinek 	return (Z_OK);
28671507Sgjelinek }
28681507Sgjelinek 
28691507Sgjelinek /*
28701507Sgjelinek  * Update the owner, group, mode and acl on the specified dev (inpath) for
28711507Sgjelinek  * the zone (hdl).  This function can be used to fix up the dev tree after
28721507Sgjelinek  * attaching a migrated zone.
28731507Sgjelinek  */
28741507Sgjelinek int
zonecfg_devperms_apply(zone_dochandle_t hdl,const char * inpath,uid_t owner,gid_t group,mode_t mode,const char * acltxt)28751507Sgjelinek zonecfg_devperms_apply(zone_dochandle_t hdl, const char *inpath, uid_t owner,
28761507Sgjelinek     gid_t group, mode_t mode, const char *acltxt)
28771507Sgjelinek {
28781507Sgjelinek 	int ret;
28791507Sgjelinek 	char path[MAXPATHLEN];
28801507Sgjelinek 	struct stat st;
28811507Sgjelinek 	acl_t *aclp;
28821507Sgjelinek 
28831507Sgjelinek 	if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK)
28841507Sgjelinek 		return (ret);
28851507Sgjelinek 
28861507Sgjelinek 	if (strlcat(path, "/dev/", sizeof (path)) >= sizeof (path))
28871507Sgjelinek 		return (Z_TOO_BIG);
28881507Sgjelinek 	if (strlcat(path, inpath, sizeof (path)) >= sizeof (path))
28891507Sgjelinek 		return (Z_TOO_BIG);
28901507Sgjelinek 
28911507Sgjelinek 	if (stat(path, &st) == -1)
28921507Sgjelinek 		return (Z_INVAL);
28931507Sgjelinek 
28941507Sgjelinek 	/* make sure we're only touching device nodes */
28951507Sgjelinek 	if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode))
28961507Sgjelinek 		return (Z_INVAL);
28971507Sgjelinek 
28981507Sgjelinek 	if (chown(path, owner, group) == -1)
28991507Sgjelinek 		return (Z_SYSTEM);
29001507Sgjelinek 
29011507Sgjelinek 	if (chmod(path, mode) == -1)
29021507Sgjelinek 		return (Z_SYSTEM);
29031507Sgjelinek 
29041507Sgjelinek 	if ((acltxt == NULL) || (strcmp(acltxt, "") == 0))
29051507Sgjelinek 		return (Z_OK);
29061507Sgjelinek 
29078057SJordan.Vaughan@Sun.com 	if (acl_fromtext(acltxt, &aclp) != 0) {
29088057SJordan.Vaughan@Sun.com 		errno = EINVAL;
29091507Sgjelinek 		return (Z_SYSTEM);
29108057SJordan.Vaughan@Sun.com 	}
29111507Sgjelinek 
29121507Sgjelinek 	errno = 0;
29131507Sgjelinek 	if (acl_set(path, aclp) == -1) {
29141507Sgjelinek 		free(aclp);
29151507Sgjelinek 		return (Z_SYSTEM);
29161507Sgjelinek 	}
29171507Sgjelinek 
29181507Sgjelinek 	free(aclp);
29191507Sgjelinek 	return (Z_OK);
29201507Sgjelinek }
29211507Sgjelinek 
29220Sstevel@tonic-gate /*
29230Sstevel@tonic-gate  * This function finds everything mounted under a zone's rootpath.
29240Sstevel@tonic-gate  * This returns the number of mounts under rootpath, or -1 on error.
29250Sstevel@tonic-gate  * callback is called once per mount found with the first argument
292611276SJordan.Vaughan@Sun.com  * pointing to a mnttab structure containing the mount's information.
29270Sstevel@tonic-gate  *
29280Sstevel@tonic-gate  * If the callback function returns non-zero zonecfg_find_mounts
29290Sstevel@tonic-gate  * aborts with an error.
29300Sstevel@tonic-gate  */
29310Sstevel@tonic-gate int
zonecfg_find_mounts(char * rootpath,int (* callback)(const struct mnttab *,void *),void * priv)293211276SJordan.Vaughan@Sun.com zonecfg_find_mounts(char *rootpath, int (*callback)(const struct mnttab *,
293311276SJordan.Vaughan@Sun.com     void *), void *priv) {
29340Sstevel@tonic-gate 	FILE *mnttab;
29350Sstevel@tonic-gate 	struct mnttab m;
29360Sstevel@tonic-gate 	size_t l;
29371607Sgjelinek 	int zfsl;
29380Sstevel@tonic-gate 	int rv = 0;
29391607Sgjelinek 	char zfs_path[MAXPATHLEN];
29400Sstevel@tonic-gate 
29410Sstevel@tonic-gate 	assert(rootpath != NULL);
29420Sstevel@tonic-gate 
29431607Sgjelinek 	if ((zfsl = snprintf(zfs_path, sizeof (zfs_path), "%s/.zfs/", rootpath))
29441607Sgjelinek 	    >= sizeof (zfs_path))
29451607Sgjelinek 		return (-1);
29461607Sgjelinek 
29470Sstevel@tonic-gate 	l = strlen(rootpath);
29480Sstevel@tonic-gate 
29490Sstevel@tonic-gate 	mnttab = fopen("/etc/mnttab", "r");
29500Sstevel@tonic-gate 
29510Sstevel@tonic-gate 	if (mnttab == NULL)
29520Sstevel@tonic-gate 		return (-1);
29530Sstevel@tonic-gate 
29540Sstevel@tonic-gate 	if (ioctl(fileno(mnttab), MNTIOC_SHOWHIDDEN, NULL) < 0)  {
29550Sstevel@tonic-gate 		rv = -1;
29560Sstevel@tonic-gate 		goto out;
29570Sstevel@tonic-gate 	}
29580Sstevel@tonic-gate 
29590Sstevel@tonic-gate 	while (!getmntent(mnttab, &m)) {
29600Sstevel@tonic-gate 		if ((strncmp(rootpath, m.mnt_mountp, l) == 0) &&
29611607Sgjelinek 		    (m.mnt_mountp[l] == '/') &&
29621607Sgjelinek 		    (strncmp(zfs_path, m.mnt_mountp, zfsl) != 0)) {
29630Sstevel@tonic-gate 			rv++;
29640Sstevel@tonic-gate 			if (callback == NULL)
29650Sstevel@tonic-gate 				continue;
296611276SJordan.Vaughan@Sun.com 			if (callback(&m, priv)) {
29670Sstevel@tonic-gate 				rv = -1;
29680Sstevel@tonic-gate 				goto out;
29690Sstevel@tonic-gate 
29700Sstevel@tonic-gate 			}
29710Sstevel@tonic-gate 		}
29720Sstevel@tonic-gate 	}
29730Sstevel@tonic-gate 
29740Sstevel@tonic-gate out:
29750Sstevel@tonic-gate 	(void) fclose(mnttab);
29760Sstevel@tonic-gate 	return (rv);
29770Sstevel@tonic-gate }
29780Sstevel@tonic-gate 
29790Sstevel@tonic-gate int
zonecfg_lookup_attr(zone_dochandle_t handle,struct zone_attrtab * tabptr)29800Sstevel@tonic-gate zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
29810Sstevel@tonic-gate {
29820Sstevel@tonic-gate 	xmlNodePtr cur, firstmatch;
29830Sstevel@tonic-gate 	int err;
29840Sstevel@tonic-gate 	char name[MAXNAMELEN], type[MAXNAMELEN], value[MAXNAMELEN];
29850Sstevel@tonic-gate 
29860Sstevel@tonic-gate 	if (tabptr == NULL)
29870Sstevel@tonic-gate 		return (Z_INVAL);
29880Sstevel@tonic-gate 
29890Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK)
29900Sstevel@tonic-gate 		return (err);
29910Sstevel@tonic-gate 
29920Sstevel@tonic-gate 	cur = handle->zone_dh_cur;
29930Sstevel@tonic-gate 	firstmatch = NULL;
29940Sstevel@tonic-gate 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
29950Sstevel@tonic-gate 		if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
29960Sstevel@tonic-gate 			continue;
29970Sstevel@tonic-gate 		if (strlen(tabptr->zone_attr_name) > 0) {
29980Sstevel@tonic-gate 			if ((fetchprop(cur, DTD_ATTR_NAME, name,
29990Sstevel@tonic-gate 			    sizeof (name)) == Z_OK) &&
30000Sstevel@tonic-gate 			    (strcmp(tabptr->zone_attr_name, name) == 0)) {
30010Sstevel@tonic-gate 				if (firstmatch == NULL)
30020Sstevel@tonic-gate 					firstmatch = cur;
30030Sstevel@tonic-gate 				else
30040Sstevel@tonic-gate 					return (Z_INSUFFICIENT_SPEC);
30050Sstevel@tonic-gate 			}
30060Sstevel@tonic-gate 		}
30070Sstevel@tonic-gate 		if (strlen(tabptr->zone_attr_type) > 0) {
30080Sstevel@tonic-gate 			if ((fetchprop(cur, DTD_ATTR_TYPE, type,
30090Sstevel@tonic-gate 			    sizeof (type)) == Z_OK)) {
30100Sstevel@tonic-gate 				if (strcmp(tabptr->zone_attr_type, type) == 0) {
30110Sstevel@tonic-gate 					if (firstmatch == NULL)
30120Sstevel@tonic-gate 						firstmatch = cur;
30130Sstevel@tonic-gate 					else if (firstmatch != cur)
30140Sstevel@tonic-gate 						return (Z_INSUFFICIENT_SPEC);
30150Sstevel@tonic-gate 				} else {
30160Sstevel@tonic-gate 					/*
30170Sstevel@tonic-gate 					 * If another property matched but this
30180Sstevel@tonic-gate 					 * one doesn't then reset firstmatch.
30190Sstevel@tonic-gate 					 */
30200Sstevel@tonic-gate 					if (firstmatch == cur)
30210Sstevel@tonic-gate 						firstmatch = NULL;
30220Sstevel@tonic-gate 				}
30230Sstevel@tonic-gate 			}
30240Sstevel@tonic-gate 		}
30250Sstevel@tonic-gate 		if (strlen(tabptr->zone_attr_value) > 0) {
30260Sstevel@tonic-gate 			if ((fetchprop(cur, DTD_ATTR_VALUE, value,
30270Sstevel@tonic-gate 			    sizeof (value)) == Z_OK)) {
30280Sstevel@tonic-gate 				if (strcmp(tabptr->zone_attr_value, value) ==
30290Sstevel@tonic-gate 				    0) {
30300Sstevel@tonic-gate 					if (firstmatch == NULL)
30310Sstevel@tonic-gate 						firstmatch = cur;
30320Sstevel@tonic-gate 					else if (firstmatch != cur)
30330Sstevel@tonic-gate 						return (Z_INSUFFICIENT_SPEC);
30340Sstevel@tonic-gate 				} else {
30350Sstevel@tonic-gate 					/*
30360Sstevel@tonic-gate 					 * If another property matched but this
30370Sstevel@tonic-gate 					 * one doesn't then reset firstmatch.
30380Sstevel@tonic-gate 					 */
30390Sstevel@tonic-gate 					if (firstmatch == cur)
30400Sstevel@tonic-gate 						firstmatch = NULL;
30410Sstevel@tonic-gate 				}
30420Sstevel@tonic-gate 			}
30430Sstevel@tonic-gate 		}
30440Sstevel@tonic-gate 	}
30450Sstevel@tonic-gate 	if (firstmatch == NULL)
30460Sstevel@tonic-gate 		return (Z_NO_RESOURCE_ID);
30470Sstevel@tonic-gate 
30480Sstevel@tonic-gate 	cur = firstmatch;
30490Sstevel@tonic-gate 
30500Sstevel@tonic-gate 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
30510Sstevel@tonic-gate 	    sizeof (tabptr->zone_attr_name))) != Z_OK)
30520Sstevel@tonic-gate 		return (err);
30530Sstevel@tonic-gate 
30540Sstevel@tonic-gate 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
30550Sstevel@tonic-gate 	    sizeof (tabptr->zone_attr_type))) != Z_OK)
30560Sstevel@tonic-gate 		return (err);
30570Sstevel@tonic-gate 
30580Sstevel@tonic-gate 	if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
30590Sstevel@tonic-gate 	    sizeof (tabptr->zone_attr_value))) != Z_OK)
30600Sstevel@tonic-gate 		return (err);
30610Sstevel@tonic-gate 
30620Sstevel@tonic-gate 	return (Z_OK);
30630Sstevel@tonic-gate }
30640Sstevel@tonic-gate 
30650Sstevel@tonic-gate static int
zonecfg_add_attr_core(zone_dochandle_t handle,struct zone_attrtab * tabptr)30660Sstevel@tonic-gate zonecfg_add_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
30670Sstevel@tonic-gate {
30680Sstevel@tonic-gate 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
30690Sstevel@tonic-gate 	int err;
30700Sstevel@tonic-gate 
30710Sstevel@tonic-gate 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ATTR, NULL);
3072228Sdp 	err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_attr_name);
30730Sstevel@tonic-gate 	if (err != Z_OK)
30740Sstevel@tonic-gate 		return (err);
3075228Sdp 	err = newprop(newnode, DTD_ATTR_TYPE, tabptr->zone_attr_type);
30760Sstevel@tonic-gate 	if (err != Z_OK)
30770Sstevel@tonic-gate 		return (err);
3078228Sdp 	err = newprop(newnode, DTD_ATTR_VALUE, tabptr->zone_attr_value);
30790Sstevel@tonic-gate 	if (err != Z_OK)
30800Sstevel@tonic-gate 		return (err);
30810Sstevel@tonic-gate 	return (Z_OK);
30820Sstevel@tonic-gate }
30830Sstevel@tonic-gate 
30840Sstevel@tonic-gate int
zonecfg_add_attr(zone_dochandle_t handle,struct zone_attrtab * tabptr)30850Sstevel@tonic-gate zonecfg_add_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
30860Sstevel@tonic-gate {
30870Sstevel@tonic-gate 	int err;
30880Sstevel@tonic-gate 
30890Sstevel@tonic-gate 	if (tabptr == NULL)
30900Sstevel@tonic-gate 		return (Z_INVAL);
30910Sstevel@tonic-gate 
30920Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK)
30930Sstevel@tonic-gate 		return (err);
30940Sstevel@tonic-gate 
30950Sstevel@tonic-gate 	if ((err = zonecfg_add_attr_core(handle, tabptr)) != Z_OK)
30960Sstevel@tonic-gate 		return (err);
30970Sstevel@tonic-gate 
30980Sstevel@tonic-gate 	return (Z_OK);
30990Sstevel@tonic-gate }
31000Sstevel@tonic-gate 
31010Sstevel@tonic-gate static int
zonecfg_delete_attr_core(zone_dochandle_t handle,struct zone_attrtab * tabptr)31020Sstevel@tonic-gate zonecfg_delete_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
31030Sstevel@tonic-gate {
31040Sstevel@tonic-gate 	xmlNodePtr cur = handle->zone_dh_cur;
31050Sstevel@tonic-gate 	int name_match, type_match, value_match;
31060Sstevel@tonic-gate 
31070Sstevel@tonic-gate 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
31080Sstevel@tonic-gate 		if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
31090Sstevel@tonic-gate 			continue;
31100Sstevel@tonic-gate 
31110Sstevel@tonic-gate 		name_match = match_prop(cur, DTD_ATTR_NAME,
31120Sstevel@tonic-gate 		    tabptr->zone_attr_name);
31130Sstevel@tonic-gate 		type_match = match_prop(cur, DTD_ATTR_TYPE,
31140Sstevel@tonic-gate 		    tabptr->zone_attr_type);
31150Sstevel@tonic-gate 		value_match = match_prop(cur, DTD_ATTR_VALUE,
31160Sstevel@tonic-gate 		    tabptr->zone_attr_value);
31170Sstevel@tonic-gate 
31180Sstevel@tonic-gate 		if (name_match && type_match && value_match) {
31190Sstevel@tonic-gate 			xmlUnlinkNode(cur);
31200Sstevel@tonic-gate 			xmlFreeNode(cur);
31210Sstevel@tonic-gate 			return (Z_OK);
31220Sstevel@tonic-gate 		}
31230Sstevel@tonic-gate 	}
31240Sstevel@tonic-gate 	return (Z_NO_RESOURCE_ID);
31250Sstevel@tonic-gate }
31260Sstevel@tonic-gate 
31270Sstevel@tonic-gate int
zonecfg_delete_attr(zone_dochandle_t handle,struct zone_attrtab * tabptr)31280Sstevel@tonic-gate zonecfg_delete_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
31290Sstevel@tonic-gate {
31300Sstevel@tonic-gate 	int err;
31310Sstevel@tonic-gate 
31320Sstevel@tonic-gate 	if (tabptr == NULL)
31330Sstevel@tonic-gate 		return (Z_INVAL);
31340Sstevel@tonic-gate 
31350Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK)
31360Sstevel@tonic-gate 		return (err);
31370Sstevel@tonic-gate 
31380Sstevel@tonic-gate 	if ((err = zonecfg_delete_attr_core(handle, tabptr)) != Z_OK)
31390Sstevel@tonic-gate 		return (err);
31400Sstevel@tonic-gate 
31410Sstevel@tonic-gate 	return (Z_OK);
31420Sstevel@tonic-gate }
31430Sstevel@tonic-gate 
31440Sstevel@tonic-gate int
zonecfg_modify_attr(zone_dochandle_t handle,struct zone_attrtab * oldtabptr,struct zone_attrtab * newtabptr)31450Sstevel@tonic-gate zonecfg_modify_attr(
31460Sstevel@tonic-gate 	zone_dochandle_t handle,
31470Sstevel@tonic-gate 	struct zone_attrtab *oldtabptr,
31480Sstevel@tonic-gate 	struct zone_attrtab *newtabptr)
31490Sstevel@tonic-gate {
31500Sstevel@tonic-gate 	int err;
31510Sstevel@tonic-gate 
31520Sstevel@tonic-gate 	if (oldtabptr == NULL || newtabptr == NULL)
31530Sstevel@tonic-gate 		return (Z_INVAL);
31540Sstevel@tonic-gate 
31550Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK)
31560Sstevel@tonic-gate 		return (err);
31570Sstevel@tonic-gate 
31580Sstevel@tonic-gate 	if ((err = zonecfg_delete_attr_core(handle, oldtabptr)) != Z_OK)
31590Sstevel@tonic-gate 		return (err);
31600Sstevel@tonic-gate 
31610Sstevel@tonic-gate 	if ((err = zonecfg_add_attr_core(handle, newtabptr)) != Z_OK)
31620Sstevel@tonic-gate 		return (err);
31630Sstevel@tonic-gate 
31640Sstevel@tonic-gate 	return (Z_OK);
31650Sstevel@tonic-gate }
31660Sstevel@tonic-gate 
31670Sstevel@tonic-gate int
zonecfg_get_attr_boolean(const struct zone_attrtab * attr,boolean_t * value)31680Sstevel@tonic-gate zonecfg_get_attr_boolean(const struct zone_attrtab *attr, boolean_t *value)
31690Sstevel@tonic-gate {
31700Sstevel@tonic-gate 	if (attr == NULL)
31710Sstevel@tonic-gate 		return (Z_INVAL);
31720Sstevel@tonic-gate 
31730Sstevel@tonic-gate 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_BOOLEAN) != 0)
31740Sstevel@tonic-gate 		return (Z_INVAL);
31750Sstevel@tonic-gate 
31760Sstevel@tonic-gate 	if (strcmp(attr->zone_attr_value, DTD_ENTITY_TRUE) == 0) {
31770Sstevel@tonic-gate 		*value = B_TRUE;
31780Sstevel@tonic-gate 		return (Z_OK);
31790Sstevel@tonic-gate 	}
31800Sstevel@tonic-gate 	if (strcmp(attr->zone_attr_value, DTD_ENTITY_FALSE) == 0) {
31810Sstevel@tonic-gate 		*value = B_FALSE;
31820Sstevel@tonic-gate 		return (Z_OK);
31830Sstevel@tonic-gate 	}
31840Sstevel@tonic-gate 	return (Z_INVAL);
31850Sstevel@tonic-gate }
31860Sstevel@tonic-gate 
31870Sstevel@tonic-gate int
zonecfg_get_attr_int(const struct zone_attrtab * attr,int64_t * value)31880Sstevel@tonic-gate zonecfg_get_attr_int(const struct zone_attrtab *attr, int64_t *value)
31890Sstevel@tonic-gate {
31900Sstevel@tonic-gate 	long long result;
31910Sstevel@tonic-gate 	char *endptr;
31920Sstevel@tonic-gate 
31930Sstevel@tonic-gate 	if (attr == NULL)
31940Sstevel@tonic-gate 		return (Z_INVAL);
31950Sstevel@tonic-gate 
31960Sstevel@tonic-gate 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_INT) != 0)
31970Sstevel@tonic-gate 		return (Z_INVAL);
31980Sstevel@tonic-gate 
31990Sstevel@tonic-gate 	errno = 0;
32000Sstevel@tonic-gate 	result = strtoll(attr->zone_attr_value, &endptr, 10);
32010Sstevel@tonic-gate 	if (errno != 0 || *endptr != '\0')
32020Sstevel@tonic-gate 		return (Z_INVAL);
32030Sstevel@tonic-gate 	*value = result;
32040Sstevel@tonic-gate 	return (Z_OK);
32050Sstevel@tonic-gate }
32060Sstevel@tonic-gate 
32070Sstevel@tonic-gate int
zonecfg_get_attr_string(const struct zone_attrtab * attr,char * value,size_t val_sz)32080Sstevel@tonic-gate zonecfg_get_attr_string(const struct zone_attrtab *attr, char *value,
32090Sstevel@tonic-gate     size_t val_sz)
32100Sstevel@tonic-gate {
32110Sstevel@tonic-gate 	if (attr == NULL)
32120Sstevel@tonic-gate 		return (Z_INVAL);
32130Sstevel@tonic-gate 
32140Sstevel@tonic-gate 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_STRING) != 0)
32150Sstevel@tonic-gate 		return (Z_INVAL);
32160Sstevel@tonic-gate 
32170Sstevel@tonic-gate 	if (strlcpy(value, attr->zone_attr_value, val_sz) >= val_sz)
32180Sstevel@tonic-gate 		return (Z_TOO_BIG);
32190Sstevel@tonic-gate 	return (Z_OK);
32200Sstevel@tonic-gate }
32210Sstevel@tonic-gate 
32220Sstevel@tonic-gate int
zonecfg_get_attr_uint(const struct zone_attrtab * attr,uint64_t * value)32230Sstevel@tonic-gate zonecfg_get_attr_uint(const struct zone_attrtab *attr, uint64_t *value)
32240Sstevel@tonic-gate {
32250Sstevel@tonic-gate 	unsigned long long result;
32260Sstevel@tonic-gate 	long long neg_result;
32270Sstevel@tonic-gate 	char *endptr;
32280Sstevel@tonic-gate 
32290Sstevel@tonic-gate 	if (attr == NULL)
32300Sstevel@tonic-gate 		return (Z_INVAL);
32310Sstevel@tonic-gate 
32320Sstevel@tonic-gate 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_UINT) != 0)
32330Sstevel@tonic-gate 		return (Z_INVAL);
32340Sstevel@tonic-gate 
32350Sstevel@tonic-gate 	errno = 0;
32360Sstevel@tonic-gate 	result = strtoull(attr->zone_attr_value, &endptr, 10);
32370Sstevel@tonic-gate 	if (errno != 0 || *endptr != '\0')
32380Sstevel@tonic-gate 		return (Z_INVAL);
32390Sstevel@tonic-gate 	errno = 0;
32400Sstevel@tonic-gate 	neg_result = strtoll(attr->zone_attr_value, &endptr, 10);
32410Sstevel@tonic-gate 	/*
32420Sstevel@tonic-gate 	 * Incredibly, strtoull("<negative number>", ...) will not fail but
32430Sstevel@tonic-gate 	 * return whatever (negative) number cast as a u_longlong_t, so we
32440Sstevel@tonic-gate 	 * need to look for this here.
32450Sstevel@tonic-gate 	 */
32460Sstevel@tonic-gate 	if (errno == 0 && neg_result < 0)
32470Sstevel@tonic-gate 		return (Z_INVAL);
32480Sstevel@tonic-gate 	*value = result;
32490Sstevel@tonic-gate 	return (Z_OK);
32500Sstevel@tonic-gate }
32510Sstevel@tonic-gate 
32520Sstevel@tonic-gate int
zonecfg_lookup_rctl(zone_dochandle_t handle,struct zone_rctltab * tabptr)32530Sstevel@tonic-gate zonecfg_lookup_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
32540Sstevel@tonic-gate {
32550Sstevel@tonic-gate 	xmlNodePtr cur, val;
32560Sstevel@tonic-gate 	char savedname[MAXNAMELEN];
32570Sstevel@tonic-gate 	struct zone_rctlvaltab *valptr;
32580Sstevel@tonic-gate 	int err;
32590Sstevel@tonic-gate 
32608057SJordan.Vaughan@Sun.com 	if (strlen(tabptr->zone_rctl_name) == 0)
32610Sstevel@tonic-gate 		return (Z_INVAL);
32620Sstevel@tonic-gate 
32630Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK)
32640Sstevel@tonic-gate 		return (err);
32650Sstevel@tonic-gate 
32660Sstevel@tonic-gate 	cur = handle->zone_dh_cur;
32670Sstevel@tonic-gate 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
32680Sstevel@tonic-gate 		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL))
32690Sstevel@tonic-gate 			continue;
32700Sstevel@tonic-gate 		if ((fetchprop(cur, DTD_ATTR_NAME, savedname,
32710Sstevel@tonic-gate 		    sizeof (savedname)) == Z_OK) &&
32720Sstevel@tonic-gate 		    (strcmp(savedname, tabptr->zone_rctl_name) == 0)) {
32730Sstevel@tonic-gate 			tabptr->zone_rctl_valptr = NULL;
32740Sstevel@tonic-gate 			for (val = cur->xmlChildrenNode; val != NULL;
32750Sstevel@tonic-gate 			    val = val->next) {
32760Sstevel@tonic-gate 				valptr = (struct zone_rctlvaltab *)malloc(
32770Sstevel@tonic-gate 				    sizeof (struct zone_rctlvaltab));
32780Sstevel@tonic-gate 				if (valptr == NULL)
32790Sstevel@tonic-gate 					return (Z_NOMEM);
32800Sstevel@tonic-gate 				if ((fetchprop(val, DTD_ATTR_PRIV,
32810Sstevel@tonic-gate 				    valptr->zone_rctlval_priv,
32820Sstevel@tonic-gate 				    sizeof (valptr->zone_rctlval_priv)) !=
32830Sstevel@tonic-gate 				    Z_OK))
32840Sstevel@tonic-gate 					break;
32850Sstevel@tonic-gate 				if ((fetchprop(val, DTD_ATTR_LIMIT,
32860Sstevel@tonic-gate 				    valptr->zone_rctlval_limit,
32870Sstevel@tonic-gate 				    sizeof (valptr->zone_rctlval_limit)) !=
32880Sstevel@tonic-gate 				    Z_OK))
32890Sstevel@tonic-gate 					break;
32900Sstevel@tonic-gate 				if ((fetchprop(val, DTD_ATTR_ACTION,
32910Sstevel@tonic-gate 				    valptr->zone_rctlval_action,
32920Sstevel@tonic-gate 				    sizeof (valptr->zone_rctlval_action)) !=
32930Sstevel@tonic-gate 				    Z_OK))
32940Sstevel@tonic-gate 					break;
32950Sstevel@tonic-gate 				if (zonecfg_add_rctl_value(tabptr, valptr) !=
32960Sstevel@tonic-gate 				    Z_OK)
32970Sstevel@tonic-gate 					break;
32980Sstevel@tonic-gate 			}
32990Sstevel@tonic-gate 			return (Z_OK);
33000Sstevel@tonic-gate 		}
33010Sstevel@tonic-gate 	}
33020Sstevel@tonic-gate 	return (Z_NO_RESOURCE_ID);
33030Sstevel@tonic-gate }
33040Sstevel@tonic-gate 
33050Sstevel@tonic-gate static int
zonecfg_add_rctl_core(zone_dochandle_t handle,struct zone_rctltab * tabptr)33060Sstevel@tonic-gate zonecfg_add_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr)
33070Sstevel@tonic-gate {
33080Sstevel@tonic-gate 	xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode;
33090Sstevel@tonic-gate 	struct zone_rctlvaltab *valptr;
33100Sstevel@tonic-gate 	int err;
33110Sstevel@tonic-gate 
33120Sstevel@tonic-gate 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_RCTL, NULL);
3313228Sdp 	err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_rctl_name);
33140Sstevel@tonic-gate 	if (err != Z_OK)
33150Sstevel@tonic-gate 		return (err);
33160Sstevel@tonic-gate 	for (valptr = tabptr->zone_rctl_valptr; valptr != NULL;
33170Sstevel@tonic-gate 	    valptr = valptr->zone_rctlval_next) {
33180Sstevel@tonic-gate 		valnode = xmlNewTextChild(newnode, NULL,
33190Sstevel@tonic-gate 		    DTD_ELEM_RCTLVALUE, NULL);
3320228Sdp 		err = newprop(valnode, DTD_ATTR_PRIV,
33210Sstevel@tonic-gate 		    valptr->zone_rctlval_priv);
33220Sstevel@tonic-gate 		if (err != Z_OK)
33230Sstevel@tonic-gate 			return (err);
3324228Sdp 		err = newprop(valnode, DTD_ATTR_LIMIT,
33250Sstevel@tonic-gate 		    valptr->zone_rctlval_limit);
33260Sstevel@tonic-gate 		if (err != Z_OK)
33270Sstevel@tonic-gate 			return (err);
3328228Sdp 		err = newprop(valnode, DTD_ATTR_ACTION,
33290Sstevel@tonic-gate 		    valptr->zone_rctlval_action);
33300Sstevel@tonic-gate 		if (err != Z_OK)
33310Sstevel@tonic-gate 			return (err);
33320Sstevel@tonic-gate 	}
33330Sstevel@tonic-gate 	return (Z_OK);
33340Sstevel@tonic-gate }
33350Sstevel@tonic-gate 
33360Sstevel@tonic-gate int
zonecfg_add_rctl(zone_dochandle_t handle,struct zone_rctltab * tabptr)33370Sstevel@tonic-gate zonecfg_add_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
33380Sstevel@tonic-gate {
33390Sstevel@tonic-gate 	int err;
33400Sstevel@tonic-gate 
33418057SJordan.Vaughan@Sun.com 	if (tabptr == NULL)
33420Sstevel@tonic-gate 		return (Z_INVAL);
33430Sstevel@tonic-gate 
33440Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK)
33450Sstevel@tonic-gate 		return (err);
33460Sstevel@tonic-gate 
33470Sstevel@tonic-gate 	if ((err = zonecfg_add_rctl_core(handle, tabptr)) != Z_OK)
33480Sstevel@tonic-gate 		return (err);
33490Sstevel@tonic-gate 
33500Sstevel@tonic-gate 	return (Z_OK);
33510Sstevel@tonic-gate }
33520Sstevel@tonic-gate 
33530Sstevel@tonic-gate static int
zonecfg_delete_rctl_core(zone_dochandle_t handle,struct zone_rctltab * tabptr)33540Sstevel@tonic-gate zonecfg_delete_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr)
33550Sstevel@tonic-gate {
33560Sstevel@tonic-gate 	xmlNodePtr cur = handle->zone_dh_cur;
33570Sstevel@tonic-gate 	xmlChar *savedname;
33580Sstevel@tonic-gate 	int name_result;
33590Sstevel@tonic-gate 
33600Sstevel@tonic-gate 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
33610Sstevel@tonic-gate 		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL))
33620Sstevel@tonic-gate 			continue;
33630Sstevel@tonic-gate 
33640Sstevel@tonic-gate 		savedname = xmlGetProp(cur, DTD_ATTR_NAME);
33650Sstevel@tonic-gate 		if (savedname == NULL)	/* shouldn't happen */
33660Sstevel@tonic-gate 			continue;
33670Sstevel@tonic-gate 		name_result = xmlStrcmp(savedname,
33680Sstevel@tonic-gate 		    (const xmlChar *) tabptr->zone_rctl_name);
33690Sstevel@tonic-gate 		xmlFree(savedname);
33700Sstevel@tonic-gate 
33710Sstevel@tonic-gate 		if (name_result == 0) {
33720Sstevel@tonic-gate 			xmlUnlinkNode(cur);
33730Sstevel@tonic-gate 			xmlFreeNode(cur);
33740Sstevel@tonic-gate 			return (Z_OK);
33750Sstevel@tonic-gate 		}
33760Sstevel@tonic-gate 	}
33770Sstevel@tonic-gate 	return (Z_NO_RESOURCE_ID);
33780Sstevel@tonic-gate }
33790Sstevel@tonic-gate 
33800Sstevel@tonic-gate int
zonecfg_delete_rctl(zone_dochandle_t handle,struct zone_rctltab * tabptr)33810Sstevel@tonic-gate zonecfg_delete_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
33820Sstevel@tonic-gate {
33830Sstevel@tonic-gate 	int err;
33840Sstevel@tonic-gate 
33858057SJordan.Vaughan@Sun.com 	if (tabptr == NULL)
33860Sstevel@tonic-gate 		return (Z_INVAL);
33870Sstevel@tonic-gate 
33880Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK)
33890Sstevel@tonic-gate 		return (err);
33900Sstevel@tonic-gate 
33910Sstevel@tonic-gate 	if ((err = zonecfg_delete_rctl_core(handle, tabptr)) != Z_OK)
33920Sstevel@tonic-gate 		return (err);
33930Sstevel@tonic-gate 
33940Sstevel@tonic-gate 	return (Z_OK);
33950Sstevel@tonic-gate }
33960Sstevel@tonic-gate 
33970Sstevel@tonic-gate int
zonecfg_modify_rctl(zone_dochandle_t handle,struct zone_rctltab * oldtabptr,struct zone_rctltab * newtabptr)33980Sstevel@tonic-gate zonecfg_modify_rctl(
33990Sstevel@tonic-gate 	zone_dochandle_t handle,
34000Sstevel@tonic-gate 	struct zone_rctltab *oldtabptr,
34010Sstevel@tonic-gate 	struct zone_rctltab *newtabptr)
34020Sstevel@tonic-gate {
34030Sstevel@tonic-gate 	int err;
34040Sstevel@tonic-gate 
34058057SJordan.Vaughan@Sun.com 	if (oldtabptr == NULL || newtabptr == NULL)
34060Sstevel@tonic-gate 		return (Z_INVAL);
34070Sstevel@tonic-gate 
34080Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK)
34090Sstevel@tonic-gate 		return (err);
34100Sstevel@tonic-gate 
34110Sstevel@tonic-gate 	if ((err = zonecfg_delete_rctl_core(handle, oldtabptr)) != Z_OK)
34120Sstevel@tonic-gate 		return (err);
34130Sstevel@tonic-gate 
34140Sstevel@tonic-gate 	if ((err = zonecfg_add_rctl_core(handle, newtabptr)) != Z_OK)
34150Sstevel@tonic-gate 		return (err);
34160Sstevel@tonic-gate 
34170Sstevel@tonic-gate 	return (Z_OK);
34180Sstevel@tonic-gate }
34190Sstevel@tonic-gate 
34200Sstevel@tonic-gate int
zonecfg_add_rctl_value(struct zone_rctltab * tabptr,struct zone_rctlvaltab * valtabptr)34210Sstevel@tonic-gate zonecfg_add_rctl_value(
34220Sstevel@tonic-gate 	struct zone_rctltab *tabptr,
34230Sstevel@tonic-gate 	struct zone_rctlvaltab *valtabptr)
34240Sstevel@tonic-gate {
34250Sstevel@tonic-gate 	struct zone_rctlvaltab *last, *old, *new;
34260Sstevel@tonic-gate 	rctlblk_t *rctlblk = alloca(rctlblk_size());
34270Sstevel@tonic-gate 
34280Sstevel@tonic-gate 	last = tabptr->zone_rctl_valptr;
34290Sstevel@tonic-gate 	for (old = last; old != NULL; old = old->zone_rctlval_next)
34300Sstevel@tonic-gate 		last = old;	/* walk to the end of the list */
34310Sstevel@tonic-gate 	new = valtabptr;	/* alloc'd by caller */
34320Sstevel@tonic-gate 	new->zone_rctlval_next = NULL;
34330Sstevel@tonic-gate 	if (zonecfg_construct_rctlblk(valtabptr, rctlblk) != Z_OK)
34340Sstevel@tonic-gate 		return (Z_INVAL);
34350Sstevel@tonic-gate 	if (!zonecfg_valid_rctlblk(rctlblk))
34360Sstevel@tonic-gate 		return (Z_INVAL);
34370Sstevel@tonic-gate 	if (last == NULL)
34380Sstevel@tonic-gate 		tabptr->zone_rctl_valptr = new;
34390Sstevel@tonic-gate 	else
34400Sstevel@tonic-gate 		last->zone_rctlval_next = new;
34410Sstevel@tonic-gate 	return (Z_OK);
34420Sstevel@tonic-gate }
34430Sstevel@tonic-gate 
34440Sstevel@tonic-gate int
zonecfg_remove_rctl_value(struct zone_rctltab * tabptr,struct zone_rctlvaltab * valtabptr)34450Sstevel@tonic-gate zonecfg_remove_rctl_value(
34460Sstevel@tonic-gate 	struct zone_rctltab *tabptr,
34470Sstevel@tonic-gate 	struct zone_rctlvaltab *valtabptr)
34480Sstevel@tonic-gate {
34490Sstevel@tonic-gate 	struct zone_rctlvaltab *last, *this, *next;
34500Sstevel@tonic-gate 
34510Sstevel@tonic-gate 	last = tabptr->zone_rctl_valptr;
34520Sstevel@tonic-gate 	for (this = last; this != NULL; this = this->zone_rctlval_next) {
34530Sstevel@tonic-gate 		if (strcmp(this->zone_rctlval_priv,
34540Sstevel@tonic-gate 		    valtabptr->zone_rctlval_priv) == 0 &&
34550Sstevel@tonic-gate 		    strcmp(this->zone_rctlval_limit,
34560Sstevel@tonic-gate 		    valtabptr->zone_rctlval_limit) == 0 &&
34570Sstevel@tonic-gate 		    strcmp(this->zone_rctlval_action,
34580Sstevel@tonic-gate 		    valtabptr->zone_rctlval_action) == 0) {
34590Sstevel@tonic-gate 			next = this->zone_rctlval_next;
34600Sstevel@tonic-gate 			if (this == tabptr->zone_rctl_valptr)
34610Sstevel@tonic-gate 				tabptr->zone_rctl_valptr = next;
34620Sstevel@tonic-gate 			else
34630Sstevel@tonic-gate 				last->zone_rctlval_next = next;
34640Sstevel@tonic-gate 			free(this);
34650Sstevel@tonic-gate 			return (Z_OK);
34660Sstevel@tonic-gate 		} else
34670Sstevel@tonic-gate 			last = this;
34680Sstevel@tonic-gate 	}
34690Sstevel@tonic-gate 	return (Z_NO_PROPERTY_ID);
34700Sstevel@tonic-gate }
34710Sstevel@tonic-gate 
34727089Sgjelinek void
zonecfg_set_swinv(zone_dochandle_t handle)34737089Sgjelinek zonecfg_set_swinv(zone_dochandle_t handle)
34747089Sgjelinek {
34757089Sgjelinek 	handle->zone_dh_sw_inv = B_TRUE;
34767089Sgjelinek }
34777089Sgjelinek 
34787089Sgjelinek /*
34797089Sgjelinek  * Add the pkg to the sw inventory on the handle.
34807089Sgjelinek  */
34817089Sgjelinek int
zonecfg_add_pkg(zone_dochandle_t handle,char * name,char * version)34827089Sgjelinek zonecfg_add_pkg(zone_dochandle_t handle, char *name, char *version)
34837089Sgjelinek {
34847089Sgjelinek 	xmlNodePtr newnode;
34857089Sgjelinek 	xmlNodePtr cur;
34867089Sgjelinek 	int err;
34877089Sgjelinek 
34887089Sgjelinek 	if ((err = operation_prep(handle)) != Z_OK)
34897089Sgjelinek 		return (err);
34907089Sgjelinek 
34917089Sgjelinek 	cur = handle->zone_dh_cur;
34927089Sgjelinek 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL);
34937089Sgjelinek 	if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK)
34947089Sgjelinek 		return (err);
34957089Sgjelinek 	if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK)
34967089Sgjelinek 		return (err);
34977089Sgjelinek 	return (Z_OK);
34987089Sgjelinek }
34997089Sgjelinek 
35007089Sgjelinek int
zonecfg_add_patch(zone_dochandle_t handle,char * id,void ** pnode)35017089Sgjelinek zonecfg_add_patch(zone_dochandle_t handle, char *id, void **pnode)
35027089Sgjelinek {
35037089Sgjelinek 	xmlNodePtr node = (xmlNodePtr)*pnode;
35047089Sgjelinek 	xmlNodePtr cur;
35057089Sgjelinek 	int err;
35067089Sgjelinek 
35077089Sgjelinek 	if ((err = operation_prep(handle)) != Z_OK)
35087089Sgjelinek 		return (err);
35097089Sgjelinek 
35107089Sgjelinek 	cur = handle->zone_dh_cur;
35117089Sgjelinek 	node = xmlNewTextChild(cur, NULL, DTD_ELEM_PATCH, NULL);
35127089Sgjelinek 	if ((err = newprop(node, DTD_ATTR_ID, id)) != Z_OK)
35137089Sgjelinek 		return (err);
35147089Sgjelinek 	*pnode = (void *)node;
35157089Sgjelinek 	return (Z_OK);
35167089Sgjelinek }
35177089Sgjelinek 
35187089Sgjelinek int
zonecfg_add_patch_obs(char * id,void * cur)35197089Sgjelinek zonecfg_add_patch_obs(char *id, void *cur)
35207089Sgjelinek {
35217089Sgjelinek 	xmlNodePtr	node;
35227089Sgjelinek 	int err;
35237089Sgjelinek 
35247089Sgjelinek 	node = xmlNewTextChild((xmlNodePtr)cur, NULL, DTD_ELEM_OBSOLETES, NULL);
35257089Sgjelinek 	if ((err = newprop(node, DTD_ATTR_ID, id)) != Z_OK)
35267089Sgjelinek 		return (err);
35277089Sgjelinek 	return (Z_OK);
35287089Sgjelinek }
35297089Sgjelinek 
35300Sstevel@tonic-gate char *
zonecfg_strerror(int errnum)35310Sstevel@tonic-gate zonecfg_strerror(int errnum)
35320Sstevel@tonic-gate {
35330Sstevel@tonic-gate 	switch (errnum) {
35340Sstevel@tonic-gate 	case Z_OK:
35350Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "OK"));
35360Sstevel@tonic-gate 	case Z_EMPTY_DOCUMENT:
35370Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Empty document"));
35380Sstevel@tonic-gate 	case Z_WRONG_DOC_TYPE:
35390Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Wrong document type"));
35400Sstevel@tonic-gate 	case Z_BAD_PROPERTY:
35410Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Bad document property"));
35420Sstevel@tonic-gate 	case Z_TEMP_FILE:
35430Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN,
35440Sstevel@tonic-gate 		    "Problem creating temporary file"));
35450Sstevel@tonic-gate 	case Z_SAVING_FILE:
35460Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Problem saving file"));
35470Sstevel@tonic-gate 	case Z_NO_ENTRY:
35480Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "No such entry"));
35490Sstevel@tonic-gate 	case Z_BOGUS_ZONE_NAME:
35500Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Bogus zone name"));
35510Sstevel@tonic-gate 	case Z_REQD_RESOURCE_MISSING:
35520Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Required resource missing"));
35530Sstevel@tonic-gate 	case Z_REQD_PROPERTY_MISSING:
35540Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Required property missing"));
35550Sstevel@tonic-gate 	case Z_BAD_HANDLE:
35560Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Bad handle"));
35570Sstevel@tonic-gate 	case Z_NOMEM:
35580Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Out of memory"));
35590Sstevel@tonic-gate 	case Z_INVAL:
35600Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Invalid argument"));
35610Sstevel@tonic-gate 	case Z_ACCES:
35620Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Permission denied"));
35630Sstevel@tonic-gate 	case Z_TOO_BIG:
35640Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Argument list too long"));
35650Sstevel@tonic-gate 	case Z_MISC_FS:
35660Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN,
35670Sstevel@tonic-gate 		    "Miscellaneous file system error"));
35680Sstevel@tonic-gate 	case Z_NO_ZONE:
35690Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "No such zone configured"));
35700Sstevel@tonic-gate 	case Z_NO_RESOURCE_TYPE:
35710Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "No such resource type"));
35720Sstevel@tonic-gate 	case Z_NO_RESOURCE_ID:
35730Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "No such resource with that id"));
35740Sstevel@tonic-gate 	case Z_NO_PROPERTY_TYPE:
35750Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "No such property type"));
35760Sstevel@tonic-gate 	case Z_NO_PROPERTY_ID:
35770Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "No such property with that id"));
3578565Sdp 	case Z_BAD_ZONE_STATE:
35790Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN,
3580565Sdp 		    "Zone state is invalid for the requested operation"));
35810Sstevel@tonic-gate 	case Z_INVALID_DOCUMENT:
35820Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Invalid document"));
3583565Sdp 	case Z_NAME_IN_USE:
3584565Sdp 		return (dgettext(TEXT_DOMAIN, "Zone name already in use"));
35850Sstevel@tonic-gate 	case Z_NO_SUCH_ID:
35860Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "No such zone ID"));
35870Sstevel@tonic-gate 	case Z_UPDATING_INDEX:
35880Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Problem updating index file"));
35890Sstevel@tonic-gate 	case Z_LOCKING_FILE:
35900Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Locking index file"));
35910Sstevel@tonic-gate 	case Z_UNLOCKING_FILE:
35920Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Unlocking index file"));
35930Sstevel@tonic-gate 	case Z_INSUFFICIENT_SPEC:
35940Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Insufficient specification"));
35950Sstevel@tonic-gate 	case Z_RESOLVED_PATH:
35960Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Resolved path mismatch"));
35970Sstevel@tonic-gate 	case Z_IPV6_ADDR_PREFIX_LEN:
35980Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN,
35990Sstevel@tonic-gate 		    "IPv6 address missing required prefix length"));
36000Sstevel@tonic-gate 	case Z_BOGUS_ADDRESS:
36010Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN,
36020Sstevel@tonic-gate 		    "Neither an IPv4 nor an IPv6 address nor a host name"));
36031645Scomay 	case Z_PRIV_PROHIBITED:
36041645Scomay 		return (dgettext(TEXT_DOMAIN,
36051645Scomay 		    "Specified privilege is prohibited"));
36061645Scomay 	case Z_PRIV_REQUIRED:
36071645Scomay 		return (dgettext(TEXT_DOMAIN,
36081645Scomay 		    "Required privilege is missing"));
36091645Scomay 	case Z_PRIV_UNKNOWN:
36101645Scomay 		return (dgettext(TEXT_DOMAIN,
36111645Scomay 		    "Specified privilege is unknown"));
36122712Snn35248 	case Z_BRAND_ERROR:
36132712Snn35248 		return (dgettext(TEXT_DOMAIN,
36142712Snn35248 		    "Brand-specific error"));
36153247Sgjelinek 	case Z_INCOMPATIBLE:
36163247Sgjelinek 		return (dgettext(TEXT_DOMAIN, "Incompatible settings"));
36173247Sgjelinek 	case Z_ALIAS_DISALLOW:
36183247Sgjelinek 		return (dgettext(TEXT_DOMAIN,
36193247Sgjelinek 		    "An incompatible rctl already exists for this property"));
36203247Sgjelinek 	case Z_CLEAR_DISALLOW:
36213247Sgjelinek 		return (dgettext(TEXT_DOMAIN,
36223247Sgjelinek 		    "Clearing this property is not allowed"));
36233247Sgjelinek 	case Z_POOL:
36243247Sgjelinek 		return (dgettext(TEXT_DOMAIN, "libpool(3LIB) error"));
36253247Sgjelinek 	case Z_POOLS_NOT_ACTIVE:
36263247Sgjelinek 		return (dgettext(TEXT_DOMAIN, "Pools facility not active; "
36273247Sgjelinek 		    "zone will not be bound to pool"));
36283247Sgjelinek 	case Z_POOL_ENABLE:
36293247Sgjelinek 		return (dgettext(TEXT_DOMAIN,
36303247Sgjelinek 		    "Could not enable pools facility"));
36313247Sgjelinek 	case Z_NO_POOL:
36323247Sgjelinek 		return (dgettext(TEXT_DOMAIN,
36333247Sgjelinek 		    "Pool not found; using default pool"));
36343247Sgjelinek 	case Z_POOL_CREATE:
36353247Sgjelinek 		return (dgettext(TEXT_DOMAIN,
36363247Sgjelinek 		    "Could not create a temporary pool"));
36373247Sgjelinek 	case Z_POOL_BIND:
36383247Sgjelinek 		return (dgettext(TEXT_DOMAIN, "Could not bind zone to pool"));
363912633Sjohn.levon@sun.com 	case Z_INVALID_PROPERTY:
364012633Sjohn.levon@sun.com 		return (dgettext(TEXT_DOMAIN, "Specified property is invalid"));
36418057SJordan.Vaughan@Sun.com 	case Z_SYSTEM:
36428057SJordan.Vaughan@Sun.com 		return (strerror(errno));
36430Sstevel@tonic-gate 	default:
36440Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Unknown error"));
36450Sstevel@tonic-gate 	}
36460Sstevel@tonic-gate }
36470Sstevel@tonic-gate 
36480Sstevel@tonic-gate /*
36490Sstevel@tonic-gate  * Note that the zonecfg_setXent() and zonecfg_endXent() calls are all the
36500Sstevel@tonic-gate  * same, as they just turn around and call zonecfg_setent() / zonecfg_endent().
36510Sstevel@tonic-gate  */
36520Sstevel@tonic-gate 
36530Sstevel@tonic-gate static int
zonecfg_setent(zone_dochandle_t handle)36540Sstevel@tonic-gate zonecfg_setent(zone_dochandle_t handle)
36550Sstevel@tonic-gate {
36560Sstevel@tonic-gate 	xmlNodePtr cur;
36570Sstevel@tonic-gate 	int err;
36580Sstevel@tonic-gate 
36590Sstevel@tonic-gate 	if (handle == NULL)
36600Sstevel@tonic-gate 		return (Z_INVAL);
36610Sstevel@tonic-gate 
36620Sstevel@tonic-gate 	if ((err = operation_prep(handle)) != Z_OK) {
36630Sstevel@tonic-gate 		handle->zone_dh_cur = NULL;
36640Sstevel@tonic-gate 		return (err);
36650Sstevel@tonic-gate 	}
36660Sstevel@tonic-gate 	cur = handle->zone_dh_cur;
36670Sstevel@tonic-gate 	cur = cur->xmlChildrenNode;
36680Sstevel@tonic-gate 	handle->zone_dh_cur = cur;
36690Sstevel@tonic-gate 	return (Z_OK);
36700Sstevel@tonic-gate }
36710Sstevel@tonic-gate 
36720Sstevel@tonic-gate static int
zonecfg_endent(zone_dochandle_t handle)36730Sstevel@tonic-gate zonecfg_endent(zone_dochandle_t handle)
36740Sstevel@tonic-gate {
36750Sstevel@tonic-gate 	if (handle == NULL)
36760Sstevel@tonic-gate 		return (Z_INVAL);
36770Sstevel@tonic-gate 
36780Sstevel@tonic-gate 	handle->zone_dh_cur = handle->zone_dh_top;
36790Sstevel@tonic-gate 	return (Z_OK);
36800Sstevel@tonic-gate }
36810Sstevel@tonic-gate 
36823247Sgjelinek /*
36833247Sgjelinek  * Do the work required to manipulate a process through libproc.
36843247Sgjelinek  * If grab_process() returns no errors (0), then release_process()
36853247Sgjelinek  * must eventually be called.
36863247Sgjelinek  *
36873247Sgjelinek  * Return values:
36883247Sgjelinek  *      0 Successful creation of agent thread
36893247Sgjelinek  *      1 Error grabbing
36903247Sgjelinek  *      2 Error creating agent
36913247Sgjelinek  */
36923247Sgjelinek static int
grab_process(pr_info_handle_t * p)36933247Sgjelinek grab_process(pr_info_handle_t *p)
36943247Sgjelinek {
36953247Sgjelinek 	int ret;
36963247Sgjelinek 
36973247Sgjelinek 	if ((p->pr = Pgrab(p->pid, 0, &ret)) != NULL) {
36983247Sgjelinek 
36993247Sgjelinek 		if (Psetflags(p->pr, PR_RLC) != 0) {
37003247Sgjelinek 			Prelease(p->pr, 0);
37013247Sgjelinek 			return (1);
37023247Sgjelinek 		}
37033247Sgjelinek 		if (Pcreate_agent(p->pr) == 0) {
37043247Sgjelinek 			return (0);
37053247Sgjelinek 
37063247Sgjelinek 		} else {
37073247Sgjelinek 			Prelease(p->pr, 0);
37083247Sgjelinek 			return (2);
37093247Sgjelinek 		}
37103247Sgjelinek 	} else {
37113247Sgjelinek 		return (1);
37123247Sgjelinek 	}
37133247Sgjelinek }
37143247Sgjelinek 
37153247Sgjelinek /*
37163247Sgjelinek  * Release the specified process. This destroys the agent
37173247Sgjelinek  * and releases the process. If the process is NULL, nothing
37183247Sgjelinek  * is done. This function should only be called if grab_process()
37193247Sgjelinek  * has previously been called and returned success.
37203247Sgjelinek  *
37213247Sgjelinek  * This function is Pgrab-safe.
37223247Sgjelinek  */
37233247Sgjelinek static void
release_process(struct ps_prochandle * Pr)37243247Sgjelinek release_process(struct ps_prochandle *Pr)
37253247Sgjelinek {
37263247Sgjelinek 	if (Pr == NULL)
37273247Sgjelinek 		return;
37283247Sgjelinek 
37293247Sgjelinek 	Pdestroy_agent(Pr);
37303247Sgjelinek 	Prelease(Pr, 0);
37313247Sgjelinek }
37323247Sgjelinek 
37333247Sgjelinek static boolean_t
grab_zone_proc(char * zonename,pr_info_handle_t * p)37343247Sgjelinek grab_zone_proc(char *zonename, pr_info_handle_t *p)
37353247Sgjelinek {
37363247Sgjelinek 	DIR *dirp;
37373247Sgjelinek 	struct dirent *dentp;
37383247Sgjelinek 	zoneid_t zoneid;
37393247Sgjelinek 	int pid_self;
37403247Sgjelinek 	psinfo_t psinfo;
37413247Sgjelinek 
37423247Sgjelinek 	if (zone_get_id(zonename, &zoneid) != 0)
37433247Sgjelinek 		return (B_FALSE);
37443247Sgjelinek 
37453247Sgjelinek 	pid_self = getpid();
37463247Sgjelinek 
37473247Sgjelinek 	if ((dirp = opendir("/proc")) == NULL)
37483247Sgjelinek 		return (B_FALSE);
37493247Sgjelinek 
37503247Sgjelinek 	while (dentp = readdir(dirp)) {
37513247Sgjelinek 		p->pid = atoi(dentp->d_name);
37523247Sgjelinek 
37533247Sgjelinek 		/* Skip self */
37543247Sgjelinek 		if (p->pid == pid_self)
37553247Sgjelinek 			continue;
37563247Sgjelinek 
37573247Sgjelinek 		if (proc_get_psinfo(p->pid, &psinfo) != 0)
37583247Sgjelinek 			continue;
37593247Sgjelinek 
37603247Sgjelinek 		if (psinfo.pr_zoneid != zoneid)
37613247Sgjelinek 			continue;
37623247Sgjelinek 
37633247Sgjelinek 		/* attempt to grab process */
37643247Sgjelinek 		if (grab_process(p) != 0)
37653247Sgjelinek 			continue;
37663247Sgjelinek 
37673247Sgjelinek 		if (pr_getzoneid(p->pr) != zoneid) {
37683247Sgjelinek 			release_process(p->pr);
37693247Sgjelinek 			continue;
37703247Sgjelinek 		}
37713247Sgjelinek 
37723247Sgjelinek 		(void) closedir(dirp);
37733247Sgjelinek 		return (B_TRUE);
37743247Sgjelinek 	}
37753247Sgjelinek 
37763247Sgjelinek 	(void) closedir(dirp);
37773247Sgjelinek 	return (B_FALSE);
37783247Sgjelinek }
37793247Sgjelinek 
37803247Sgjelinek static boolean_t
get_priv_rctl(struct ps_prochandle * pr,char * name,rctlblk_t * rblk)37813247Sgjelinek get_priv_rctl(struct ps_prochandle *pr, char *name, rctlblk_t *rblk)
37823247Sgjelinek {
37833247Sgjelinek 	if (pr_getrctl(pr, name, NULL, rblk, RCTL_FIRST))
37843247Sgjelinek 		return (B_FALSE);
37853247Sgjelinek 
37863247Sgjelinek 	if (rctlblk_get_privilege(rblk) == RCPRIV_PRIVILEGED)
37873247Sgjelinek 		return (B_TRUE);
37883247Sgjelinek 
37893247Sgjelinek 	while (pr_getrctl(pr, name, rblk, rblk, RCTL_NEXT) == 0) {
37903247Sgjelinek 		if (rctlblk_get_privilege(rblk) == RCPRIV_PRIVILEGED)
37913247Sgjelinek 			return (B_TRUE);
37923247Sgjelinek 	}
37933247Sgjelinek 
37943247Sgjelinek 	return (B_FALSE);
37953247Sgjelinek }
37963247Sgjelinek 
37973247Sgjelinek /*
37983247Sgjelinek  * Apply the current rctl settings to the specified, running zone.
37993247Sgjelinek  */
38003247Sgjelinek int
zonecfg_apply_rctls(char * zone_name,zone_dochandle_t handle)38013247Sgjelinek zonecfg_apply_rctls(char *zone_name, zone_dochandle_t handle)
38023247Sgjelinek {
38033247Sgjelinek 	int err;
38043247Sgjelinek 	int res = Z_OK;
38053247Sgjelinek 	rctlblk_t *rblk;
38063247Sgjelinek 	pr_info_handle_t p;
38073247Sgjelinek 	struct zone_rctltab rctl;
38083247Sgjelinek 
38093247Sgjelinek 	if ((err = zonecfg_setrctlent(handle)) != Z_OK)
38103247Sgjelinek 		return (err);
38113247Sgjelinek 
38123247Sgjelinek 	if ((rblk = (rctlblk_t *)malloc(rctlblk_size())) == NULL) {
38133247Sgjelinek 		(void) zonecfg_endrctlent(handle);
38143247Sgjelinek 		return (Z_NOMEM);
38153247Sgjelinek 	}
38163247Sgjelinek 
38173247Sgjelinek 	if (!grab_zone_proc(zone_name, &p)) {
38183247Sgjelinek 		(void) zonecfg_endrctlent(handle);
38193247Sgjelinek 		free(rblk);
38203247Sgjelinek 		return (Z_SYSTEM);
38213247Sgjelinek 	}
38223247Sgjelinek 
38233247Sgjelinek 	while (zonecfg_getrctlent(handle, &rctl) == Z_OK) {
38243247Sgjelinek 		char *rname;
38253247Sgjelinek 		struct zone_rctlvaltab *valptr;
38263247Sgjelinek 
38273247Sgjelinek 		rname = rctl.zone_rctl_name;
38283247Sgjelinek 
38293247Sgjelinek 		/* first delete all current privileged settings for this rctl */
38303247Sgjelinek 		while (get_priv_rctl(p.pr, rname, rblk)) {
38313247Sgjelinek 			if (pr_setrctl(p.pr, rname, NULL, rblk, RCTL_DELETE) !=
38323247Sgjelinek 			    0) {
38333247Sgjelinek 				res = Z_SYSTEM;
38343247Sgjelinek 				goto done;
38353247Sgjelinek 			}
38363247Sgjelinek 		}
38373247Sgjelinek 
38383247Sgjelinek 		/* now set each new value for the rctl */
38393247Sgjelinek 		for (valptr = rctl.zone_rctl_valptr; valptr != NULL;
38403247Sgjelinek 		    valptr = valptr->zone_rctlval_next) {
38413247Sgjelinek 			if ((err = zonecfg_construct_rctlblk(valptr, rblk))
38423247Sgjelinek 			    != Z_OK) {
38433247Sgjelinek 				res = errno = err;
38443247Sgjelinek 				goto done;
38453247Sgjelinek 			}
38463247Sgjelinek 
38473247Sgjelinek 			if (pr_setrctl(p.pr, rname, NULL, rblk, RCTL_INSERT)) {
38483247Sgjelinek 				res = Z_SYSTEM;
38493247Sgjelinek 				goto done;
38503247Sgjelinek 			}
38513247Sgjelinek 		}
38523247Sgjelinek 	}
38533247Sgjelinek 
38543247Sgjelinek done:
38553247Sgjelinek 	release_process(p.pr);
38563247Sgjelinek 	free(rblk);
38573247Sgjelinek 	(void) zonecfg_endrctlent(handle);
38583247Sgjelinek 
38593247Sgjelinek 	return (res);
38603247Sgjelinek }
38613247Sgjelinek 
38623247Sgjelinek static const xmlChar *
nm_to_dtd(char * nm)38633247Sgjelinek nm_to_dtd(char *nm)
38643247Sgjelinek {
38653247Sgjelinek 	if (strcmp(nm, "device") == 0)
38663247Sgjelinek 		return (DTD_ELEM_DEVICE);
38673247Sgjelinek 	if (strcmp(nm, "fs") == 0)
38683247Sgjelinek 		return (DTD_ELEM_FS);
38693247Sgjelinek 	if (strcmp(nm, "net") == 0)
38703247Sgjelinek 		return (DTD_ELEM_NET);
38713247Sgjelinek 	if (strcmp(nm, "attr") == 0)
38723247Sgjelinek 		return (DTD_ELEM_ATTR);
38733247Sgjelinek 	if (strcmp(nm, "rctl") == 0)
38743247Sgjelinek 		return (DTD_ELEM_RCTL);
38753247Sgjelinek 	if (strcmp(nm, "dataset") == 0)
38763247Sgjelinek 		return (DTD_ELEM_DATASET);
387712578SGlenn.Faden@Sun.COM 	if (strcmp(nm, "admin") == 0)
387812578SGlenn.Faden@Sun.COM 		return (DTD_ELEM_ADMIN);
38793247Sgjelinek 
38803247Sgjelinek 	return (NULL);
38813247Sgjelinek }
38823247Sgjelinek 
38833247Sgjelinek int
zonecfg_num_resources(zone_dochandle_t handle,char * rsrc)38843247Sgjelinek zonecfg_num_resources(zone_dochandle_t handle, char *rsrc)
38853247Sgjelinek {
38863247Sgjelinek 	int num = 0;
38873247Sgjelinek 	const xmlChar *dtd;
38883247Sgjelinek 	xmlNodePtr cur;
38893247Sgjelinek 
38903247Sgjelinek 	if ((dtd = nm_to_dtd(rsrc)) == NULL)
38913247Sgjelinek 		return (num);
38923247Sgjelinek 
38933247Sgjelinek 	if (zonecfg_setent(handle) != Z_OK)
38943247Sgjelinek 		return (num);
38953247Sgjelinek 
38963247Sgjelinek 	for (cur = handle->zone_dh_cur; cur != NULL; cur = cur->next)
38973247Sgjelinek 		if (xmlStrcmp(cur->name, dtd) == 0)
38983247Sgjelinek 			num++;
38993247Sgjelinek 
39003247Sgjelinek 	(void) zonecfg_endent(handle);
39013247Sgjelinek 
39023247Sgjelinek 	return (num);
39033247Sgjelinek }
39043247Sgjelinek 
39053247Sgjelinek int
zonecfg_del_all_resources(zone_dochandle_t handle,char * rsrc)39063247Sgjelinek zonecfg_del_all_resources(zone_dochandle_t handle, char *rsrc)
39073247Sgjelinek {
39083247Sgjelinek 	int err;
39093247Sgjelinek 	const xmlChar *dtd;
39103247Sgjelinek 	xmlNodePtr cur;
39113247Sgjelinek 
39123247Sgjelinek 	if ((dtd = nm_to_dtd(rsrc)) == NULL)
39133247Sgjelinek 		return (Z_NO_RESOURCE_TYPE);
39143247Sgjelinek 
39153247Sgjelinek 	if ((err = zonecfg_setent(handle)) != Z_OK)
39163247Sgjelinek 		return (err);
39173247Sgjelinek 
39183247Sgjelinek 	cur = handle->zone_dh_cur;
39193247Sgjelinek 	while (cur != NULL) {
39203247Sgjelinek 		xmlNodePtr tmp;
39213247Sgjelinek 
39223247Sgjelinek 		if (xmlStrcmp(cur->name, dtd)) {
39233247Sgjelinek 			cur = cur->next;
39243247Sgjelinek 			continue;
39253247Sgjelinek 		}
39263247Sgjelinek 
39273247Sgjelinek 		tmp = cur->next;
39283247Sgjelinek 		xmlUnlinkNode(cur);
39293247Sgjelinek 		xmlFreeNode(cur);
39303247Sgjelinek 		cur = tmp;
39313247Sgjelinek 	}
39323247Sgjelinek 
39333247Sgjelinek 	(void) zonecfg_endent(handle);
39343247Sgjelinek 	return (Z_OK);
39353247Sgjelinek }
39363247Sgjelinek 
39373247Sgjelinek static boolean_t
valid_uint(char * s,uint64_t * n)39383247Sgjelinek valid_uint(char *s, uint64_t *n)
39393247Sgjelinek {
39403247Sgjelinek 	char *endp;
39413247Sgjelinek 
39423247Sgjelinek 	/* strtoull accepts '-'?! so we want to flag that as an error */
39433247Sgjelinek 	if (strchr(s, '-') != NULL)
39443247Sgjelinek 		return (B_FALSE);
39453247Sgjelinek 
39463247Sgjelinek 	errno = 0;
39473247Sgjelinek 	*n = strtoull(s, &endp, 10);
39483247Sgjelinek 
39493247Sgjelinek 	if (errno != 0 || *endp != '\0')
39503247Sgjelinek 		return (B_FALSE);
39513247Sgjelinek 	return (B_TRUE);
39523247Sgjelinek }
39533247Sgjelinek 
39543247Sgjelinek /*
39553247Sgjelinek  * Convert a string representing a number (possibly a fraction) into an integer.
39563247Sgjelinek  * The string can have a modifier (K, M, G or T).   The modifiers are treated
39573247Sgjelinek  * as powers of two (not 10).
39583247Sgjelinek  */
39593247Sgjelinek int
zonecfg_str_to_bytes(char * str,uint64_t * bytes)39603247Sgjelinek zonecfg_str_to_bytes(char *str, uint64_t *bytes)
39613247Sgjelinek {
39623247Sgjelinek 	long double val;
39633247Sgjelinek 	char *unitp;
39643247Sgjelinek 	uint64_t scale;
39653247Sgjelinek 
39663247Sgjelinek 	if ((val = strtold(str, &unitp)) < 0)
39673247Sgjelinek 		return (-1);
39683247Sgjelinek 
39693247Sgjelinek 	/* remove any leading white space from units string */
39703247Sgjelinek 	while (isspace(*unitp) != 0)
39713247Sgjelinek 		++unitp;
39723247Sgjelinek 
39733247Sgjelinek 	/* if no units explicitly set, error */
39743247Sgjelinek 	if (unitp == NULL || *unitp == '\0') {
39753247Sgjelinek 		scale = 1;
39763247Sgjelinek 	} else {
39773247Sgjelinek 		int i;
39783247Sgjelinek 		char *units[] = {"K", "M", "G", "T", NULL};
39793247Sgjelinek 
39803247Sgjelinek 		scale = 1024;
39813247Sgjelinek 
39823247Sgjelinek 		/* update scale based on units */
39833247Sgjelinek 		for (i = 0; units[i] != NULL; i++) {
39843247Sgjelinek 			if (strcasecmp(unitp, units[i]) == 0)
39853247Sgjelinek 				break;
39863247Sgjelinek 			scale <<= 10;
39873247Sgjelinek 		}
39883247Sgjelinek 
39893247Sgjelinek 		if (units[i] == NULL)
39903247Sgjelinek 			return (-1);
39913247Sgjelinek 	}
39923247Sgjelinek 
39933247Sgjelinek 	*bytes = (uint64_t)(val * scale);
39943247Sgjelinek 	return (0);
39953247Sgjelinek }
39963247Sgjelinek 
39973247Sgjelinek boolean_t
zonecfg_valid_ncpus(char * lowstr,char * highstr)39983247Sgjelinek zonecfg_valid_ncpus(char *lowstr, char *highstr)
39993247Sgjelinek {
40003247Sgjelinek 	uint64_t low, high;
40013247Sgjelinek 
40023247Sgjelinek 	if (!valid_uint(lowstr, &low) || !valid_uint(highstr, &high) ||
40033247Sgjelinek 	    low < 1 || low > high)
40043247Sgjelinek 		return (B_FALSE);
40053247Sgjelinek 
40063247Sgjelinek 	return (B_TRUE);
40073247Sgjelinek }
40083247Sgjelinek 
40093247Sgjelinek boolean_t
zonecfg_valid_importance(char * impstr)40103247Sgjelinek zonecfg_valid_importance(char *impstr)
40113247Sgjelinek {
40123247Sgjelinek 	uint64_t num;
40133247Sgjelinek 
40143247Sgjelinek 	if (!valid_uint(impstr, &num))
40153247Sgjelinek 		return (B_FALSE);
40163247Sgjelinek 
40173247Sgjelinek 	return (B_TRUE);
40183247Sgjelinek }
40193247Sgjelinek 
40203247Sgjelinek boolean_t
zonecfg_valid_alias_limit(char * name,char * limitstr,uint64_t * limit)40213247Sgjelinek zonecfg_valid_alias_limit(char *name, char *limitstr, uint64_t *limit)
40223247Sgjelinek {
40233247Sgjelinek 	int i;
40243247Sgjelinek 
40253247Sgjelinek 	for (i = 0; aliases[i].shortname != NULL; i++)
40263247Sgjelinek 		if (strcmp(name, aliases[i].shortname) == 0)
40273247Sgjelinek 			break;
40283247Sgjelinek 
40293247Sgjelinek 	if (aliases[i].shortname == NULL)
40303247Sgjelinek 		return (B_FALSE);
40313247Sgjelinek 
40323247Sgjelinek 	if (!valid_uint(limitstr, limit) || *limit < aliases[i].low_limit)
40333247Sgjelinek 		return (B_FALSE);
40343247Sgjelinek 
40353247Sgjelinek 	return (B_TRUE);
40363247Sgjelinek }
40373247Sgjelinek 
40383247Sgjelinek boolean_t
zonecfg_valid_memlimit(char * memstr,uint64_t * mem_val)40393247Sgjelinek zonecfg_valid_memlimit(char *memstr, uint64_t *mem_val)
40403247Sgjelinek {
40413247Sgjelinek 	if (zonecfg_str_to_bytes(memstr, mem_val) != 0)
40423247Sgjelinek 		return (B_FALSE);
40433247Sgjelinek 
40443247Sgjelinek 	return (B_TRUE);
40453247Sgjelinek }
40463247Sgjelinek 
40473247Sgjelinek static int
zerr_pool(char * pool_err,int err_size,int res)40483247Sgjelinek zerr_pool(char *pool_err, int err_size, int res)
40493247Sgjelinek {
40503247Sgjelinek 	(void) strlcpy(pool_err, pool_strerror(pool_error()), err_size);
40513247Sgjelinek 	return (res);
40523247Sgjelinek }
40533247Sgjelinek 
40543247Sgjelinek static int
create_tmp_pset(char * pool_err,int err_size,pool_conf_t * pconf,pool_t * pool,char * name,int min,int max)40553247Sgjelinek create_tmp_pset(char *pool_err, int err_size, pool_conf_t *pconf, pool_t *pool,
40563247Sgjelinek     char *name, int min, int max)
40573247Sgjelinek {
40583247Sgjelinek 	pool_resource_t *res;
40593247Sgjelinek 	pool_elem_t *elem;
40603247Sgjelinek 	pool_value_t *val;
40613247Sgjelinek 
40623247Sgjelinek 	if ((res = pool_resource_create(pconf, "pset", name)) == NULL)
40633247Sgjelinek 		return (zerr_pool(pool_err, err_size, Z_POOL));
40643247Sgjelinek 
40653247Sgjelinek 	if (pool_associate(pconf, pool, res) != PO_SUCCESS)
40663247Sgjelinek 		return (zerr_pool(pool_err, err_size, Z_POOL));
40673247Sgjelinek 
40683247Sgjelinek 	if ((elem = pool_resource_to_elem(pconf, res)) == NULL)
40693247Sgjelinek 		return (zerr_pool(pool_err, err_size, Z_POOL));
40703247Sgjelinek 
40713247Sgjelinek 	if ((val = pool_value_alloc()) == NULL)
40723247Sgjelinek 		return (zerr_pool(pool_err, err_size, Z_POOL));
40733247Sgjelinek 
40743247Sgjelinek 	/* set the maximum number of cpus for the pset */
40753247Sgjelinek 	pool_value_set_uint64(val, (uint64_t)max);
40763247Sgjelinek 
40773247Sgjelinek 	if (pool_put_property(pconf, elem, "pset.max", val) != PO_SUCCESS) {
40783247Sgjelinek 		pool_value_free(val);
40793247Sgjelinek 		return (zerr_pool(pool_err, err_size, Z_POOL));
40803247Sgjelinek 	}
40813247Sgjelinek 
40823247Sgjelinek 	/* set the minimum number of cpus for the pset */
40833247Sgjelinek 	pool_value_set_uint64(val, (uint64_t)min);
40843247Sgjelinek 
40853247Sgjelinek 	if (pool_put_property(pconf, elem, "pset.min", val) != PO_SUCCESS) {
40863247Sgjelinek 		pool_value_free(val);
40873247Sgjelinek 		return (zerr_pool(pool_err, err_size, Z_POOL));
40883247Sgjelinek 	}
40893247Sgjelinek 
40903247Sgjelinek 	pool_value_free(val);
40913247Sgjelinek 
40923247Sgjelinek 	return (Z_OK);
40933247Sgjelinek }
40943247Sgjelinek 
40953247Sgjelinek static int
create_tmp_pool(char * pool_err,int err_size,pool_conf_t * pconf,char * name,struct zone_psettab * pset_tab)40963247Sgjelinek create_tmp_pool(char *pool_err, int err_size, pool_conf_t *pconf, char *name,
40973247Sgjelinek     struct zone_psettab *pset_tab)
40983247Sgjelinek {
40993247Sgjelinek 	pool_t *pool;
41003247Sgjelinek 	int res = Z_OK;
41013247Sgjelinek 
41023247Sgjelinek 	/* create a temporary pool configuration */
41033247Sgjelinek 	if (pool_conf_open(pconf, NULL, PO_TEMP) != PO_SUCCESS) {
41043247Sgjelinek 		res = zerr_pool(pool_err, err_size, Z_POOL);
41053247Sgjelinek 		return (res);
41063247Sgjelinek 	}
41073247Sgjelinek 
41083247Sgjelinek 	if ((pool = pool_create(pconf, name)) == NULL) {
41093247Sgjelinek 		res = zerr_pool(pool_err, err_size, Z_POOL_CREATE);
41103247Sgjelinek 		goto done;
41113247Sgjelinek 	}
41123247Sgjelinek 
41133247Sgjelinek 	/* set pool importance */
41143247Sgjelinek 	if (pset_tab->zone_importance[0] != '\0') {
41153247Sgjelinek 		pool_elem_t *elem;
41163247Sgjelinek 		pool_value_t *val;
41173247Sgjelinek 
41183247Sgjelinek 		if ((elem = pool_to_elem(pconf, pool)) == NULL) {
41193247Sgjelinek 			res = zerr_pool(pool_err, err_size, Z_POOL);
41203247Sgjelinek 			goto done;
41213247Sgjelinek 		}
41223247Sgjelinek 
41233247Sgjelinek 		if ((val = pool_value_alloc()) == NULL) {
41243247Sgjelinek 			res = zerr_pool(pool_err, err_size, Z_POOL);
41253247Sgjelinek 			goto done;
41263247Sgjelinek 		}
41273247Sgjelinek 
41283247Sgjelinek 		pool_value_set_int64(val,
41293247Sgjelinek 		    (int64_t)atoi(pset_tab->zone_importance));
41303247Sgjelinek 
41313247Sgjelinek 		if (pool_put_property(pconf, elem, "pool.importance", val)
41323247Sgjelinek 		    != PO_SUCCESS) {
41333247Sgjelinek 			res = zerr_pool(pool_err, err_size, Z_POOL);
41343247Sgjelinek 			pool_value_free(val);
41353247Sgjelinek 			goto done;
41363247Sgjelinek 		}
41373247Sgjelinek 
41383247Sgjelinek 		pool_value_free(val);
41393247Sgjelinek 	}
41403247Sgjelinek 
41413247Sgjelinek 	if ((res = create_tmp_pset(pool_err, err_size, pconf, pool, name,
41423247Sgjelinek 	    atoi(pset_tab->zone_ncpu_min),
41433247Sgjelinek 	    atoi(pset_tab->zone_ncpu_max))) != Z_OK)
41443247Sgjelinek 		goto done;
41453247Sgjelinek 
41463247Sgjelinek 	/* validation */
41473247Sgjelinek 	if (pool_conf_status(pconf) == POF_INVALID) {
41483247Sgjelinek 		res = zerr_pool(pool_err, err_size, Z_POOL);
41493247Sgjelinek 		goto done;
41503247Sgjelinek 	}
41513247Sgjelinek 
41523247Sgjelinek 	/*
41533247Sgjelinek 	 * This validation is the one we expect to fail if the user specified
41543247Sgjelinek 	 * an invalid configuration (too many cpus) for this system.
41553247Sgjelinek 	 */
41563247Sgjelinek 	if (pool_conf_validate(pconf, POV_RUNTIME) != PO_SUCCESS) {
41573247Sgjelinek 		res = zerr_pool(pool_err, err_size, Z_POOL_CREATE);
41583247Sgjelinek 		goto done;
41593247Sgjelinek 	}
41603247Sgjelinek 
41613247Sgjelinek 	/*
41623247Sgjelinek 	 * Commit the dynamic configuration but not the pool configuration
41633247Sgjelinek 	 * file.
41643247Sgjelinek 	 */
41653247Sgjelinek 	if (pool_conf_commit(pconf, 1) != PO_SUCCESS)
41663247Sgjelinek 		res = zerr_pool(pool_err, err_size, Z_POOL);
41673247Sgjelinek 
41683247Sgjelinek done:
41693247Sgjelinek 	(void) pool_conf_close(pconf);
41703247Sgjelinek 	return (res);
41713247Sgjelinek }
41723247Sgjelinek 
41733247Sgjelinek static int
get_running_tmp_pset(pool_conf_t * pconf,pool_t * pool,pool_resource_t * pset,struct zone_psettab * pset_tab)41743247Sgjelinek get_running_tmp_pset(pool_conf_t *pconf, pool_t *pool, pool_resource_t *pset,
41753247Sgjelinek     struct zone_psettab *pset_tab)
41763247Sgjelinek {
41773247Sgjelinek 	int nfound = 0;
41783247Sgjelinek 	pool_elem_t *pe;
41793247Sgjelinek 	pool_value_t *pv = pool_value_alloc();
41803247Sgjelinek 	uint64_t val_uint;
41813247Sgjelinek 
41823247Sgjelinek 	if (pool != NULL) {
41833247Sgjelinek 		pe = pool_to_elem(pconf, pool);
41843247Sgjelinek 		if (pool_get_property(pconf, pe, "pool.importance", pv)
41853247Sgjelinek 		    != POC_INVAL) {
41863247Sgjelinek 			int64_t val_int;
41873247Sgjelinek 
41883247Sgjelinek 			(void) pool_value_get_int64(pv, &val_int);
41893247Sgjelinek 			(void) snprintf(pset_tab->zone_importance,
41903247Sgjelinek 			    sizeof (pset_tab->zone_importance), "%d", val_int);
41913247Sgjelinek 			nfound++;
41923247Sgjelinek 		}
41933247Sgjelinek 	}
41943247Sgjelinek 
41953247Sgjelinek 	if (pset != NULL) {
41963247Sgjelinek 		pe = pool_resource_to_elem(pconf, pset);
41973247Sgjelinek 		if (pool_get_property(pconf, pe, "pset.min", pv) != POC_INVAL) {
41983247Sgjelinek 			(void) pool_value_get_uint64(pv, &val_uint);
41993247Sgjelinek 			(void) snprintf(pset_tab->zone_ncpu_min,
42003247Sgjelinek 			    sizeof (pset_tab->zone_ncpu_min), "%u", val_uint);
42013247Sgjelinek 			nfound++;
42023247Sgjelinek 		}
42033247Sgjelinek 
42043247Sgjelinek 		if (pool_get_property(pconf, pe, "pset.max", pv) != POC_INVAL) {
42053247Sgjelinek 			(void) pool_value_get_uint64(pv, &val_uint);
42063247Sgjelinek 			(void) snprintf(pset_tab->zone_ncpu_max,
42073247Sgjelinek 			    sizeof (pset_tab->zone_ncpu_max), "%u", val_uint);
42083247Sgjelinek 			nfound++;
42093247Sgjelinek 		}
42103247Sgjelinek 	}
42113247Sgjelinek 
42123247Sgjelinek 	pool_value_free(pv);
42133247Sgjelinek 
42143247Sgjelinek 	if (nfound == 3)
42153247Sgjelinek 		return (PO_SUCCESS);
42163247Sgjelinek 
42173247Sgjelinek 	return (PO_FAIL);
42183247Sgjelinek }
42193247Sgjelinek 
42203247Sgjelinek /*
42213247Sgjelinek  * Determine if a tmp pool is configured and if so, if the configuration is
42223247Sgjelinek  * still valid or if it has been changed since the tmp pool was created.
42233247Sgjelinek  * If the tmp pool configuration is no longer valid, delete the tmp pool.
42243247Sgjelinek  *
42253247Sgjelinek  * Set *valid=B_TRUE if there is an existing, valid tmp pool configuration.
42263247Sgjelinek  */
42273247Sgjelinek static int
verify_del_tmp_pool(pool_conf_t * pconf,char * tmp_name,char * pool_err,int err_size,struct zone_psettab * pset_tab,boolean_t * exists)42283247Sgjelinek verify_del_tmp_pool(pool_conf_t *pconf, char *tmp_name, char *pool_err,
42293247Sgjelinek     int err_size, struct zone_psettab *pset_tab, boolean_t *exists)
42303247Sgjelinek {
42313247Sgjelinek 	int res = Z_OK;
42323247Sgjelinek 	pool_t *pool;
42333247Sgjelinek 	pool_resource_t *pset;
42343247Sgjelinek 	struct zone_psettab pset_current;
42353247Sgjelinek 
42363247Sgjelinek 	*exists = B_FALSE;
42373247Sgjelinek 
42383247Sgjelinek 	if (pool_conf_open(pconf, pool_dynamic_location(), PO_RDWR)
42393247Sgjelinek 	    != PO_SUCCESS) {
42403247Sgjelinek 		res = zerr_pool(pool_err, err_size, Z_POOL);
42413247Sgjelinek 		return (res);
42423247Sgjelinek 	}
42433247Sgjelinek 
42443247Sgjelinek 	pool = pool_get_pool(pconf, tmp_name);
42453247Sgjelinek 	pset = pool_get_resource(pconf, "pset", tmp_name);
42463247Sgjelinek 
42473247Sgjelinek 	if (pool == NULL && pset == NULL) {
42483247Sgjelinek 		/* no tmp pool configured */
42493247Sgjelinek 		goto done;
42503247Sgjelinek 	}
42513247Sgjelinek 
42523247Sgjelinek 	/*
42533247Sgjelinek 	 * If an existing tmp pool for this zone is configured with the proper
42543247Sgjelinek 	 * settings, then the tmp pool is valid.
42553247Sgjelinek 	 */
42563247Sgjelinek 	if (get_running_tmp_pset(pconf, pool, pset, &pset_current)
42573247Sgjelinek 	    == PO_SUCCESS &&
42583247Sgjelinek 	    strcmp(pset_tab->zone_ncpu_min,
42593247Sgjelinek 	    pset_current.zone_ncpu_min) == 0 &&
42603247Sgjelinek 	    strcmp(pset_tab->zone_ncpu_max,
42613247Sgjelinek 	    pset_current.zone_ncpu_max) == 0 &&
42623247Sgjelinek 	    strcmp(pset_tab->zone_importance,
42633247Sgjelinek 	    pset_current.zone_importance) == 0) {
42643247Sgjelinek 		*exists = B_TRUE;
42653247Sgjelinek 
42663247Sgjelinek 	} else {
42673247Sgjelinek 		/*
42683247Sgjelinek 		 * An out-of-date tmp pool configuration exists.  Delete it
42693247Sgjelinek 		 * so that we can create the correct tmp pool config.
42703247Sgjelinek 		 */
42713247Sgjelinek 		if (pset != NULL &&
42723247Sgjelinek 		    pool_resource_destroy(pconf, pset) != PO_SUCCESS) {
42733247Sgjelinek 			res = zerr_pool(pool_err, err_size, Z_POOL);
42743247Sgjelinek 			goto done;
42753247Sgjelinek 		}
42763247Sgjelinek 
42773247Sgjelinek 		if (pool != NULL &&
42783247Sgjelinek 		    pool_destroy(pconf, pool) != PO_SUCCESS) {
42793247Sgjelinek 			res = zerr_pool(pool_err, err_size, Z_POOL);
42803247Sgjelinek 			goto done;
42813247Sgjelinek 		}
42823247Sgjelinek 
42833247Sgjelinek 		/* commit dynamic config */
42843247Sgjelinek 		if (pool_conf_commit(pconf, 0) != PO_SUCCESS)
42853247Sgjelinek 			res = zerr_pool(pool_err, err_size, Z_POOL);
42863247Sgjelinek 	}
42873247Sgjelinek 
42883247Sgjelinek done:
42893247Sgjelinek 	(void) pool_conf_close(pconf);
42903247Sgjelinek 
42913247Sgjelinek 	return (res);
42923247Sgjelinek }
42933247Sgjelinek 
42943247Sgjelinek /*
42953247Sgjelinek  * Destroy any existing tmp pool.
42963247Sgjelinek  */
42973247Sgjelinek int
zonecfg_destroy_tmp_pool(char * zone_name,char * pool_err,int err_size)42983247Sgjelinek zonecfg_destroy_tmp_pool(char *zone_name, char *pool_err, int err_size)
42993247Sgjelinek {
43003247Sgjelinek 	int status;
43013247Sgjelinek 	int res = Z_OK;
43023247Sgjelinek 	pool_conf_t *pconf;
43033247Sgjelinek 	pool_t *pool;
43043247Sgjelinek 	pool_resource_t *pset;
43053247Sgjelinek 	char tmp_name[MAX_TMP_POOL_NAME];
43063247Sgjelinek 
43073247Sgjelinek 	/* if pools not enabled then nothing to do */
43083247Sgjelinek 	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
43093247Sgjelinek 		return (Z_OK);
43103247Sgjelinek 
43113247Sgjelinek 	if ((pconf = pool_conf_alloc()) == NULL)
43123247Sgjelinek 		return (zerr_pool(pool_err, err_size, Z_POOL));
43133247Sgjelinek 
43143247Sgjelinek 	(void) snprintf(tmp_name, sizeof (tmp_name), TMP_POOL_NAME, zone_name);
43153247Sgjelinek 
43163247Sgjelinek 	if (pool_conf_open(pconf, pool_dynamic_location(), PO_RDWR)
43173247Sgjelinek 	    != PO_SUCCESS) {
43183247Sgjelinek 		res = zerr_pool(pool_err, err_size, Z_POOL);
43193247Sgjelinek 		pool_conf_free(pconf);
43203247Sgjelinek 		return (res);
43213247Sgjelinek 	}
43223247Sgjelinek 
43233247Sgjelinek 	pool = pool_get_pool(pconf, tmp_name);
43243247Sgjelinek 	pset = pool_get_resource(pconf, "pset", tmp_name);
43253247Sgjelinek 
43263247Sgjelinek 	if (pool == NULL && pset == NULL) {
43273247Sgjelinek 		/* nothing to destroy, we're done */
43283247Sgjelinek 		goto done;
43293247Sgjelinek 	}
43303247Sgjelinek 
43313247Sgjelinek 	if (pset != NULL && pool_resource_destroy(pconf, pset) != PO_SUCCESS) {
43323247Sgjelinek 		res = zerr_pool(pool_err, err_size, Z_POOL);
43333247Sgjelinek 		goto done;
43343247Sgjelinek 	}
43353247Sgjelinek 
43363247Sgjelinek 	if (pool != NULL && pool_destroy(pconf, pool) != PO_SUCCESS) {
43373247Sgjelinek 		res = zerr_pool(pool_err, err_size, Z_POOL);
43383247Sgjelinek 		goto done;
43393247Sgjelinek 	}
43403247Sgjelinek 
43413247Sgjelinek 	/* commit dynamic config */
43423247Sgjelinek 	if (pool_conf_commit(pconf, 0) != PO_SUCCESS)
43433247Sgjelinek 		res = zerr_pool(pool_err, err_size, Z_POOL);
43443247Sgjelinek 
43453247Sgjelinek done:
43463247Sgjelinek 	(void) pool_conf_close(pconf);
43473247Sgjelinek 	pool_conf_free(pconf);
43483247Sgjelinek 
43493247Sgjelinek 	return (res);
43503247Sgjelinek }
43513247Sgjelinek 
43523247Sgjelinek /*
43533247Sgjelinek  * Attempt to bind to a tmp pool for this zone.  If there is no tmp pool
43543247Sgjelinek  * configured, we just return Z_OK.
43553247Sgjelinek  *
43563247Sgjelinek  * We either attempt to create the tmp pool for this zone or rebind to an
43573247Sgjelinek  * existing tmp pool for this zone.
43583247Sgjelinek  *
43593247Sgjelinek  * Rebinding is used when a zone with a tmp pool reboots so that we don't have
43603247Sgjelinek  * to recreate the tmp pool.  To do this we need to be sure we work correctly
43613247Sgjelinek  * for the following cases:
43623247Sgjelinek  *
43633247Sgjelinek  *	- there is an existing, properly configured tmp pool.
43643247Sgjelinek  *	- zonecfg added tmp pool after zone was booted, must now create.
43653247Sgjelinek  *	- zonecfg updated tmp pool config after zone was booted, in this case
43663247Sgjelinek  *	  we destroy the old tmp pool and create a new one.
43673247Sgjelinek  */
43683247Sgjelinek int
zonecfg_bind_tmp_pool(zone_dochandle_t handle,zoneid_t zoneid,char * pool_err,int err_size)43693247Sgjelinek zonecfg_bind_tmp_pool(zone_dochandle_t handle, zoneid_t zoneid, char *pool_err,
43703247Sgjelinek     int err_size)
43713247Sgjelinek {
43723247Sgjelinek 	struct zone_psettab pset_tab;
43733247Sgjelinek 	int err;
43743247Sgjelinek 	int status;
43753247Sgjelinek 	pool_conf_t *pconf;
43763247Sgjelinek 	boolean_t exists;
43773247Sgjelinek 	char zone_name[ZONENAME_MAX];
43783247Sgjelinek 	char tmp_name[MAX_TMP_POOL_NAME];
43793247Sgjelinek 
43803247Sgjelinek 	(void) getzonenamebyid(zoneid, zone_name, sizeof (zone_name));
43813247Sgjelinek 
43823247Sgjelinek 	err = zonecfg_lookup_pset(handle, &pset_tab);
43833247Sgjelinek 
43843247Sgjelinek 	/* if no temporary pool configured, we're done */
43853247Sgjelinek 	if (err == Z_NO_ENTRY)
43863247Sgjelinek 		return (Z_OK);
43873247Sgjelinek 
43883247Sgjelinek 	/*
43893247Sgjelinek 	 * importance might not have a value but we need to validate it here,
43903247Sgjelinek 	 * so set the default.
43913247Sgjelinek 	 */
43923247Sgjelinek 	if (pset_tab.zone_importance[0] == '\0')
43933247Sgjelinek 		(void) strlcpy(pset_tab.zone_importance, "1",
43943247Sgjelinek 		    sizeof (pset_tab.zone_importance));
43953247Sgjelinek 
43963247Sgjelinek 	/* if pools not enabled, enable them now */
43973247Sgjelinek 	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) {
43983247Sgjelinek 		if (pool_set_status(POOL_ENABLED) != PO_SUCCESS)
43993247Sgjelinek 			return (Z_POOL_ENABLE);
44003247Sgjelinek 	}
44013247Sgjelinek 
44023247Sgjelinek 	if ((pconf = pool_conf_alloc()) == NULL)
44033247Sgjelinek 		return (zerr_pool(pool_err, err_size, Z_POOL));
44043247Sgjelinek 
44053247Sgjelinek 	(void) snprintf(tmp_name, sizeof (tmp_name), TMP_POOL_NAME, zone_name);
44063247Sgjelinek 
44073247Sgjelinek 	/*
44083247Sgjelinek 	 * Check if a valid tmp pool/pset already exists.  If so, we just
44093247Sgjelinek 	 * reuse it.
44103247Sgjelinek 	 */
44113247Sgjelinek 	if ((err = verify_del_tmp_pool(pconf, tmp_name, pool_err, err_size,
44123247Sgjelinek 	    &pset_tab, &exists)) != Z_OK) {
44133247Sgjelinek 		pool_conf_free(pconf);
44143247Sgjelinek 		return (err);
44153247Sgjelinek 	}
44163247Sgjelinek 
44173247Sgjelinek 	if (!exists)
44183247Sgjelinek 		err = create_tmp_pool(pool_err, err_size, pconf, tmp_name,
44193247Sgjelinek 		    &pset_tab);
44203247Sgjelinek 
44213247Sgjelinek 	pool_conf_free(pconf);
44223247Sgjelinek 
44233247Sgjelinek 	if (err != Z_OK)
44243247Sgjelinek 		return (err);
44253247Sgjelinek 
44263247Sgjelinek 	/* Bind the zone to the pool. */
44273247Sgjelinek 	if (pool_set_binding(tmp_name, P_ZONEID, zoneid) != PO_SUCCESS)
44283247Sgjelinek 		return (zerr_pool(pool_err, err_size, Z_POOL_BIND));
44293247Sgjelinek 
44303247Sgjelinek 	return (Z_OK);
44313247Sgjelinek }
44323247Sgjelinek 
44333247Sgjelinek /*
44343247Sgjelinek  * Attempt to bind to a permanent pool for this zone.  If there is no
44353247Sgjelinek  * permanent pool configured, we just return Z_OK.
44363247Sgjelinek  */
44373247Sgjelinek int
zonecfg_bind_pool(zone_dochandle_t handle,zoneid_t zoneid,char * pool_err,int err_size)44383247Sgjelinek zonecfg_bind_pool(zone_dochandle_t handle, zoneid_t zoneid, char *pool_err,
44393247Sgjelinek     int err_size)
44403247Sgjelinek {
44413247Sgjelinek 	pool_conf_t *poolconf;
44423247Sgjelinek 	pool_t *pool;
44433247Sgjelinek 	char poolname[MAXPATHLEN];
44443247Sgjelinek 	int status;
44453247Sgjelinek 	int error;
44463247Sgjelinek 
44473247Sgjelinek 	/*
44483247Sgjelinek 	 * Find the pool mentioned in the zone configuration, and bind to it.
44493247Sgjelinek 	 */
44503247Sgjelinek 	error = zonecfg_get_pool(handle, poolname, sizeof (poolname));
44513247Sgjelinek 	if (error == Z_NO_ENTRY || (error == Z_OK && strlen(poolname) == 0)) {
44523247Sgjelinek 		/*
44533247Sgjelinek 		 * The property is not set on the zone, so the pool
44543247Sgjelinek 		 * should be bound to the default pool.  But that's
44553247Sgjelinek 		 * already done by the kernel, so we can just return.
44563247Sgjelinek 		 */
44573247Sgjelinek 		return (Z_OK);
44583247Sgjelinek 	}
44593247Sgjelinek 	if (error != Z_OK) {
44603247Sgjelinek 		/*
44613247Sgjelinek 		 * Not an error, even though it shouldn't be happening.
44623247Sgjelinek 		 */
44633247Sgjelinek 		return (Z_OK);
44643247Sgjelinek 	}
44653247Sgjelinek 	/*
44663247Sgjelinek 	 * Don't do anything if pools aren't enabled.
44673247Sgjelinek 	 */
44683247Sgjelinek 	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
44693247Sgjelinek 		return (Z_POOLS_NOT_ACTIVE);
44703247Sgjelinek 
44713247Sgjelinek 	/*
44723247Sgjelinek 	 * Try to provide a sane error message if the requested pool doesn't
44733247Sgjelinek 	 * exist.
44743247Sgjelinek 	 */
44753247Sgjelinek 	if ((poolconf = pool_conf_alloc()) == NULL)
44763247Sgjelinek 		return (zerr_pool(pool_err, err_size, Z_POOL));
44773247Sgjelinek 
44783247Sgjelinek 	if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) !=
44793247Sgjelinek 	    PO_SUCCESS) {
44803247Sgjelinek 		pool_conf_free(poolconf);
44813247Sgjelinek 		return (zerr_pool(pool_err, err_size, Z_POOL));
44823247Sgjelinek 	}
44833247Sgjelinek 	pool = pool_get_pool(poolconf, poolname);
44843247Sgjelinek 	(void) pool_conf_close(poolconf);
44853247Sgjelinek 	pool_conf_free(poolconf);
44863247Sgjelinek 	if (pool == NULL)
44873247Sgjelinek 		return (Z_NO_POOL);
44883247Sgjelinek 
44893247Sgjelinek 	/*
44903247Sgjelinek 	 * Bind the zone to the pool.
44913247Sgjelinek 	 */
44923247Sgjelinek 	if (pool_set_binding(poolname, P_ZONEID, zoneid) != PO_SUCCESS) {
44933247Sgjelinek 		/* if bind fails, return poolname for the error msg */
44943247Sgjelinek 		(void) strlcpy(pool_err, poolname, err_size);
44953247Sgjelinek 		return (Z_POOL_BIND);
44963247Sgjelinek 	}
44973247Sgjelinek 
44983247Sgjelinek 	return (Z_OK);
44993247Sgjelinek }
45003247Sgjelinek 
450111878SVenu.Iyer@Sun.COM int
zonecfg_get_poolname(zone_dochandle_t handle,char * zone,char * pool,size_t poolsize)450211878SVenu.Iyer@Sun.COM zonecfg_get_poolname(zone_dochandle_t handle, char *zone, char *pool,
450311878SVenu.Iyer@Sun.COM     size_t poolsize)
450411878SVenu.Iyer@Sun.COM {
450511878SVenu.Iyer@Sun.COM 	int err;
450611878SVenu.Iyer@Sun.COM 	struct zone_psettab pset_tab;
450711878SVenu.Iyer@Sun.COM 
450811878SVenu.Iyer@Sun.COM 	err = zonecfg_lookup_pset(handle, &pset_tab);
450911878SVenu.Iyer@Sun.COM 	if ((err != Z_NO_ENTRY) && (err != Z_OK))
451011878SVenu.Iyer@Sun.COM 		return (err);
451111878SVenu.Iyer@Sun.COM 
451211878SVenu.Iyer@Sun.COM 	/* pset was found so a temporary pool was created */
451311878SVenu.Iyer@Sun.COM 	if (err == Z_OK) {
451411878SVenu.Iyer@Sun.COM 		(void) snprintf(pool, poolsize, TMP_POOL_NAME, zone);
451511878SVenu.Iyer@Sun.COM 		return (Z_OK);
451611878SVenu.Iyer@Sun.COM 	}
451711878SVenu.Iyer@Sun.COM 
451811878SVenu.Iyer@Sun.COM 	/* lookup the poolname in zonecfg */
451911878SVenu.Iyer@Sun.COM 	return (zonecfg_get_pool(handle, pool, poolsize));
452011878SVenu.Iyer@Sun.COM }
45213247Sgjelinek 
45223247Sgjelinek static boolean_t
svc_enabled(char * svc_name)45233247Sgjelinek svc_enabled(char *svc_name)
45243247Sgjelinek {
45253247Sgjelinek 	scf_simple_prop_t	*prop;
45263247Sgjelinek 	boolean_t		found = B_FALSE;
45273247Sgjelinek 
45283247Sgjelinek 	prop = scf_simple_prop_get(NULL, svc_name, SCF_PG_GENERAL,
45293247Sgjelinek 	    SCF_PROPERTY_ENABLED);
45303247Sgjelinek 
45313247Sgjelinek 	if (scf_simple_prop_numvalues(prop) == 1 &&
45323247Sgjelinek 	    *scf_simple_prop_next_boolean(prop) != 0)
45333247Sgjelinek 		found = B_TRUE;
45343247Sgjelinek 
45353247Sgjelinek 	scf_simple_prop_free(prop);
45363247Sgjelinek 
45373247Sgjelinek 	return (found);
45383247Sgjelinek }
45393247Sgjelinek 
45403247Sgjelinek /*
45413247Sgjelinek  * If the zone has capped-memory, make sure the rcap service is enabled.
45423247Sgjelinek  */
45433247Sgjelinek int
zonecfg_enable_rcapd(char * err,int size)45443247Sgjelinek zonecfg_enable_rcapd(char *err, int size)
45453247Sgjelinek {
45463247Sgjelinek 	if (!svc_enabled(RCAP_SERVICE) &&
45473247Sgjelinek 	    smf_enable_instance(RCAP_SERVICE, 0) == -1) {
45483247Sgjelinek 		(void) strlcpy(err, scf_strerror(scf_error()), size);
45493247Sgjelinek 		return (Z_SYSTEM);
45503247Sgjelinek 	}
45513247Sgjelinek 
45523247Sgjelinek 	return (Z_OK);
45533247Sgjelinek }
45543247Sgjelinek 
45553247Sgjelinek /*
45563247Sgjelinek  * Return true if pset has cpu range specified and poold is not enabled.
45573247Sgjelinek  */
45583247Sgjelinek boolean_t
zonecfg_warn_poold(zone_dochandle_t handle)45593247Sgjelinek zonecfg_warn_poold(zone_dochandle_t handle)
45603247Sgjelinek {
45613247Sgjelinek 	struct zone_psettab pset_tab;
45623247Sgjelinek 	int min, max;
45633247Sgjelinek 	int err;
45643247Sgjelinek 
45653247Sgjelinek 	err = zonecfg_lookup_pset(handle, &pset_tab);
45663247Sgjelinek 
45673247Sgjelinek 	/* if no temporary pool configured, we're done */
45683247Sgjelinek 	if (err == Z_NO_ENTRY)
45693247Sgjelinek 		return (B_FALSE);
45703247Sgjelinek 
45713247Sgjelinek 	min = atoi(pset_tab.zone_ncpu_min);
45723247Sgjelinek 	max = atoi(pset_tab.zone_ncpu_max);
45733247Sgjelinek 
45743247Sgjelinek 	/* range not specified, no need for poold */
45753247Sgjelinek 	if (min == max)
45763247Sgjelinek 		return (B_FALSE);
45773247Sgjelinek 
45783247Sgjelinek 	/* we have a range, check if poold service is enabled */
45793247Sgjelinek 	if (svc_enabled(POOLD_SERVICE))
45803247Sgjelinek 		return (B_FALSE);
45813247Sgjelinek 
45823247Sgjelinek 	return (B_TRUE);
45833247Sgjelinek }
45843247Sgjelinek 
458511435SJordan.Vaughan@Sun.com /*
458611435SJordan.Vaughan@Sun.com  * Retrieve the specified pool's thread scheduling class.  'poolname' must
458711435SJordan.Vaughan@Sun.com  * refer to the name of a configured resource pool.  The thread scheduling
458811435SJordan.Vaughan@Sun.com  * class specified by the pool will be stored in the buffer to which 'class'
458911435SJordan.Vaughan@Sun.com  * points.  'clsize' is the byte size of the buffer to which 'class' points.
459011435SJordan.Vaughan@Sun.com  *
459111435SJordan.Vaughan@Sun.com  * This function returns Z_OK if it successfully stored the specified pool's
459211435SJordan.Vaughan@Sun.com  * thread scheduling class into the buffer to which 'class' points.  It returns
459311435SJordan.Vaughan@Sun.com  * Z_NO_POOL if resource pools are not enabled, the function is unable to
459411435SJordan.Vaughan@Sun.com  * access the system's resource pools configuration, or the specified pool
459511435SJordan.Vaughan@Sun.com  * does not exist.  The function returns Z_TOO_BIG if the buffer to which
459611435SJordan.Vaughan@Sun.com  * 'class' points is not large enough to contain the thread scheduling class'
459711435SJordan.Vaughan@Sun.com  * name.  The function returns Z_NO_ENTRY if the pool does not specify a thread
459811435SJordan.Vaughan@Sun.com  * scheduling class.
459911435SJordan.Vaughan@Sun.com  */
46003247Sgjelinek static int
get_pool_sched_class(char * poolname,char * class,int clsize)46013247Sgjelinek get_pool_sched_class(char *poolname, char *class, int clsize)
46023247Sgjelinek {
46033247Sgjelinek 	int status;
46043247Sgjelinek 	pool_conf_t *poolconf;
46053247Sgjelinek 	pool_t *pool;
46063247Sgjelinek 	pool_elem_t *pe;
46073247Sgjelinek 	pool_value_t *pv = pool_value_alloc();
46083247Sgjelinek 	const char *sched_str;
46093247Sgjelinek 
46103247Sgjelinek 	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
46113247Sgjelinek 		return (Z_NO_POOL);
46123247Sgjelinek 
46133247Sgjelinek 	if ((poolconf = pool_conf_alloc()) == NULL)
46143247Sgjelinek 		return (Z_NO_POOL);
46153247Sgjelinek 
46163247Sgjelinek 	if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) !=
46173247Sgjelinek 	    PO_SUCCESS) {
46183247Sgjelinek 		pool_conf_free(poolconf);
46193247Sgjelinek 		return (Z_NO_POOL);
46203247Sgjelinek 	}
46213247Sgjelinek 
46223247Sgjelinek 	if ((pool = pool_get_pool(poolconf, poolname)) == NULL) {
46233247Sgjelinek 		(void) pool_conf_close(poolconf);
46243247Sgjelinek 		pool_conf_free(poolconf);
46253247Sgjelinek 		return (Z_NO_POOL);
46263247Sgjelinek 	}
46273247Sgjelinek 
46283247Sgjelinek 	pe = pool_to_elem(poolconf, pool);
462911435SJordan.Vaughan@Sun.com 	if (pool_get_property(poolconf, pe, "pool.scheduler", pv) !=
463011435SJordan.Vaughan@Sun.com 	    POC_STRING) {
463111435SJordan.Vaughan@Sun.com 		(void) pool_conf_close(poolconf);
463211435SJordan.Vaughan@Sun.com 		pool_conf_free(poolconf);
463311435SJordan.Vaughan@Sun.com 		return (Z_NO_ENTRY);
463411435SJordan.Vaughan@Sun.com 	}
463511435SJordan.Vaughan@Sun.com 	(void) pool_value_get_string(pv, &sched_str);
46363247Sgjelinek 	(void) pool_conf_close(poolconf);
46373247Sgjelinek 	pool_conf_free(poolconf);
463811435SJordan.Vaughan@Sun.com 	if (strlcpy(class, sched_str, clsize) >= clsize)
463911435SJordan.Vaughan@Sun.com 		return (Z_TOO_BIG);
46403247Sgjelinek 	return (Z_OK);
46413247Sgjelinek }
46423247Sgjelinek 
46433247Sgjelinek /*
46443247Sgjelinek  * Get the default scheduling class for the zone.  This will either be the
46453247Sgjelinek  * class set on the zone's pool or the system default scheduling class.
46463247Sgjelinek  */
46473247Sgjelinek int
zonecfg_get_dflt_sched_class(zone_dochandle_t handle,char * class,int clsize)46483247Sgjelinek zonecfg_get_dflt_sched_class(zone_dochandle_t handle, char *class, int clsize)
46493247Sgjelinek {
46503247Sgjelinek 	char poolname[MAXPATHLEN];
46513247Sgjelinek 
46523247Sgjelinek 	if (zonecfg_get_pool(handle, poolname, sizeof (poolname)) == Z_OK) {
46533247Sgjelinek 		/* check if the zone's pool specified a sched class */
46543247Sgjelinek 		if (get_pool_sched_class(poolname, class, clsize) == Z_OK)
46553247Sgjelinek 			return (Z_OK);
46563247Sgjelinek 	}
46573247Sgjelinek 
46583247Sgjelinek 	if (priocntl(0, 0, PC_GETDFLCL, class, (uint64_t)clsize) == -1)
46593247Sgjelinek 		return (Z_TOO_BIG);
46603247Sgjelinek 
46613247Sgjelinek 	return (Z_OK);
46623247Sgjelinek }
46633247Sgjelinek 
46640Sstevel@tonic-gate int
zonecfg_setfsent(zone_dochandle_t handle)46650Sstevel@tonic-gate zonecfg_setfsent(zone_dochandle_t handle)
46660Sstevel@tonic-gate {
46670Sstevel@tonic-gate 	return (zonecfg_setent(handle));
46680Sstevel@tonic-gate }
46690Sstevel@tonic-gate 
46700Sstevel@tonic-gate int
zonecfg_getfsent(zone_dochandle_t handle,struct zone_fstab * tabptr)46710Sstevel@tonic-gate zonecfg_getfsent(zone_dochandle_t handle, struct zone_fstab *tabptr)
46720Sstevel@tonic-gate {
46730Sstevel@tonic-gate 	xmlNodePtr cur, options;
46740Sstevel@tonic-gate 	char options_str[MAX_MNTOPT_STR];
46750Sstevel@tonic-gate 	int err;
46760Sstevel@tonic-gate 
46770Sstevel@tonic-gate 	if (handle == NULL)
46780Sstevel@tonic-gate 		return (Z_INVAL);
46790Sstevel@tonic-gate 
46800Sstevel@tonic-gate 	if ((cur = handle->zone_dh_cur) == NULL)
46810Sstevel@tonic-gate 		return (Z_NO_ENTRY);
46820Sstevel@tonic-gate 
46830Sstevel@tonic-gate 	for (; cur != NULL; cur = cur->next)
46840Sstevel@tonic-gate 		if (!xmlStrcmp(cur->name, DTD_ELEM_FS))
46850Sstevel@tonic-gate 			break;
46860Sstevel@tonic-gate 	if (cur == NULL) {
46870Sstevel@tonic-gate 		handle->zone_dh_cur = handle->zone_dh_top;
46880Sstevel@tonic-gate 		return (Z_NO_ENTRY);
46890Sstevel@tonic-gate 	}
46900Sstevel@tonic-gate 
46910Sstevel@tonic-gate 	if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
46920Sstevel@tonic-gate 	    sizeof (tabptr->zone_fs_special))) != Z_OK) {
46930Sstevel@tonic-gate 		handle->zone_dh_cur = handle->zone_dh_top;
46940Sstevel@tonic-gate 		return (err);
46950Sstevel@tonic-gate 	}
46960Sstevel@tonic-gate 
46970Sstevel@tonic-gate 	if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
46980Sstevel@tonic-gate 	    sizeof (tabptr->zone_fs_raw))) != Z_OK) {
46990Sstevel@tonic-gate 		handle->zone_dh_cur = handle->zone_dh_top;
47000Sstevel@tonic-gate 		return (err);
47010Sstevel@tonic-gate 	}
47020Sstevel@tonic-gate 
47030Sstevel@tonic-gate 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
47040Sstevel@tonic-gate 	    sizeof (tabptr->zone_fs_dir))) != Z_OK) {
47050Sstevel@tonic-gate 		handle->zone_dh_cur = handle->zone_dh_top;
47060Sstevel@tonic-gate 		return (err);
47070Sstevel@tonic-gate 	}
47080Sstevel@tonic-gate 
47090Sstevel@tonic-gate 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
47100Sstevel@tonic-gate 	    sizeof (tabptr->zone_fs_type))) != Z_OK) {
47110Sstevel@tonic-gate 		handle->zone_dh_cur = handle->zone_dh_top;
47120Sstevel@tonic-gate 		return (err);
47130Sstevel@tonic-gate 	}
47140Sstevel@tonic-gate 
47150Sstevel@tonic-gate 	/* OK for options to be NULL */
47160Sstevel@tonic-gate 	tabptr->zone_fs_options = NULL;
47170Sstevel@tonic-gate 	for (options = cur->xmlChildrenNode; options != NULL;
47180Sstevel@tonic-gate 	    options = options->next) {
47190Sstevel@tonic-gate 		if (fetchprop(options, DTD_ATTR_NAME, options_str,
47200Sstevel@tonic-gate 		    sizeof (options_str)) != Z_OK)
47210Sstevel@tonic-gate 			break;
47220Sstevel@tonic-gate 		if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
47230Sstevel@tonic-gate 			break;
47240Sstevel@tonic-gate 	}
47250Sstevel@tonic-gate 
47260Sstevel@tonic-gate 	handle->zone_dh_cur = cur->next;
47270Sstevel@tonic-gate 	return (Z_OK);
47280Sstevel@tonic-gate }
47290Sstevel@tonic-gate 
47300Sstevel@tonic-gate int
zonecfg_endfsent(zone_dochandle_t handle)47310Sstevel@tonic-gate zonecfg_endfsent(zone_dochandle_t handle)
47320Sstevel@tonic-gate {
47330Sstevel@tonic-gate 	return (zonecfg_endent(handle));
47340Sstevel@tonic-gate }
47350Sstevel@tonic-gate 
47360Sstevel@tonic-gate int
zonecfg_setnwifent(zone_dochandle_t handle)47370Sstevel@tonic-gate zonecfg_setnwifent(zone_dochandle_t handle)
47380Sstevel@tonic-gate {
47390Sstevel@tonic-gate 	return (zonecfg_setent(handle));
47400Sstevel@tonic-gate }
47410Sstevel@tonic-gate 
47420Sstevel@tonic-gate int
zonecfg_getnwifent(zone_dochandle_t handle,struct zone_nwiftab * tabptr)47430Sstevel@tonic-gate zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
47440Sstevel@tonic-gate {
47450Sstevel@tonic-gate 	xmlNodePtr cur;
47460Sstevel@tonic-gate 	int err;
47470Sstevel@tonic-gate 
47480Sstevel@tonic-gate 	if (handle == NULL)
47490Sstevel@tonic-gate 		return (Z_INVAL);
47500Sstevel@tonic-gate 
47510Sstevel@tonic-gate 	if ((cur = handle->zone_dh_cur) == NULL)
47520Sstevel@tonic-gate 		return (Z_NO_ENTRY);
47530Sstevel@tonic-gate 
47540Sstevel@tonic-gate 	for (; cur != NULL; cur = cur->next)
47550Sstevel@tonic-gate 		if (!xmlStrcmp(cur->name, DTD_ELEM_NET))
47560Sstevel@tonic-gate 			break;
47570Sstevel@tonic-gate 	if (cur == NULL) {
47580Sstevel@tonic-gate 		handle->zone_dh_cur = handle->zone_dh_top;
47590Sstevel@tonic-gate 		return (Z_NO_ENTRY);
47600Sstevel@tonic-gate 	}
47610Sstevel@tonic-gate 
47620Sstevel@tonic-gate 	if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
47630Sstevel@tonic-gate 	    sizeof (tabptr->zone_nwif_address))) != Z_OK) {
47640Sstevel@tonic-gate 		handle->zone_dh_cur = handle->zone_dh_top;
47650Sstevel@tonic-gate 		return (err);
47660Sstevel@tonic-gate 	}
47670Sstevel@tonic-gate 
476812748SSowmini.Varadhan@oracle.COM 	if ((err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
476912748SSowmini.Varadhan@oracle.COM 	    tabptr->zone_nwif_allowed_address,
477012748SSowmini.Varadhan@oracle.COM 	    sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK) {
477112748SSowmini.Varadhan@oracle.COM 		handle->zone_dh_cur = handle->zone_dh_top;
477212748SSowmini.Varadhan@oracle.COM 		return (err);
477312748SSowmini.Varadhan@oracle.COM 	}
477412748SSowmini.Varadhan@oracle.COM 
47750Sstevel@tonic-gate 	if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
47760Sstevel@tonic-gate 	    sizeof (tabptr->zone_nwif_physical))) != Z_OK) {
47770Sstevel@tonic-gate 		handle->zone_dh_cur = handle->zone_dh_top;
47780Sstevel@tonic-gate 		return (err);
47790Sstevel@tonic-gate 	}
47800Sstevel@tonic-gate 
47816076Sgfaden 	if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
47826076Sgfaden 	    tabptr->zone_nwif_defrouter,
47836076Sgfaden 	    sizeof (tabptr->zone_nwif_defrouter))) != Z_OK) {
47846076Sgfaden 		handle->zone_dh_cur = handle->zone_dh_top;
47856076Sgfaden 		return (err);
47866076Sgfaden 	}
47876076Sgfaden 
47880Sstevel@tonic-gate 	handle->zone_dh_cur = cur->next;
47890Sstevel@tonic-gate 	return (Z_OK);
47900Sstevel@tonic-gate }
47910Sstevel@tonic-gate 
47920Sstevel@tonic-gate int
zonecfg_endnwifent(zone_dochandle_t handle)47930Sstevel@tonic-gate zonecfg_endnwifent(zone_dochandle_t handle)
47940Sstevel@tonic-gate {
47950Sstevel@tonic-gate 	return (zonecfg_endent(handle));
47960Sstevel@tonic-gate }
47970Sstevel@tonic-gate 
47980Sstevel@tonic-gate int
zonecfg_setdevent(zone_dochandle_t handle)47990Sstevel@tonic-gate zonecfg_setdevent(zone_dochandle_t handle)
48000Sstevel@tonic-gate {
48010Sstevel@tonic-gate 	return (zonecfg_setent(handle));
48020Sstevel@tonic-gate }
48030Sstevel@tonic-gate 
48040Sstevel@tonic-gate int
zonecfg_getdevent(zone_dochandle_t handle,struct zone_devtab * tabptr)48050Sstevel@tonic-gate zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr)
48060Sstevel@tonic-gate {
48070Sstevel@tonic-gate 	xmlNodePtr cur;
48080Sstevel@tonic-gate 	int err;
48090Sstevel@tonic-gate 
48100Sstevel@tonic-gate 	if (handle == NULL)
48110Sstevel@tonic-gate 		return (Z_INVAL);
48120Sstevel@tonic-gate 
48130Sstevel@tonic-gate 	if ((cur = handle->zone_dh_cur) == NULL)
48140Sstevel@tonic-gate 		return (Z_NO_ENTRY);
48150Sstevel@tonic-gate 
48160Sstevel@tonic-gate 	for (; cur != NULL; cur = cur->next)
48170Sstevel@tonic-gate 		if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
48180Sstevel@tonic-gate 			break;
48190Sstevel@tonic-gate 	if (cur == NULL) {
48200Sstevel@tonic-gate 		handle->zone_dh_cur = handle->zone_dh_top;
48210Sstevel@tonic-gate 		return (Z_NO_ENTRY);
48220Sstevel@tonic-gate 	}
48230Sstevel@tonic-gate 
48240Sstevel@tonic-gate 	if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
48250Sstevel@tonic-gate 	    sizeof (tabptr->zone_dev_match))) != Z_OK) {
48260Sstevel@tonic-gate 		handle->zone_dh_cur = handle->zone_dh_top;
48270Sstevel@tonic-gate 		return (err);
48280Sstevel@tonic-gate 	}
48290Sstevel@tonic-gate 
48300Sstevel@tonic-gate 	handle->zone_dh_cur = cur->next;
48310Sstevel@tonic-gate 	return (Z_OK);
48320Sstevel@tonic-gate }
48330Sstevel@tonic-gate 
48340Sstevel@tonic-gate int
zonecfg_enddevent(zone_dochandle_t handle)48350Sstevel@tonic-gate zonecfg_enddevent(zone_dochandle_t handle)
48360Sstevel@tonic-gate {
48370Sstevel@tonic-gate 	return (zonecfg_endent(handle));
48380Sstevel@tonic-gate }
48390Sstevel@tonic-gate 
48400Sstevel@tonic-gate int
zonecfg_setrctlent(zone_dochandle_t handle)48410Sstevel@tonic-gate zonecfg_setrctlent(zone_dochandle_t handle)
48420Sstevel@tonic-gate {
48430Sstevel@tonic-gate 	return (zonecfg_setent(handle));
48440Sstevel@tonic-gate }
48450Sstevel@tonic-gate 
48460Sstevel@tonic-gate int
zonecfg_getrctlent(zone_dochandle_t handle,struct zone_rctltab * tabptr)48470Sstevel@tonic-gate zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr)
48480Sstevel@tonic-gate {
48490Sstevel@tonic-gate 	xmlNodePtr cur, val;
48500Sstevel@tonic-gate 	struct zone_rctlvaltab *valptr;
48510Sstevel@tonic-gate 	int err;
48520Sstevel@tonic-gate 
48530Sstevel@tonic-gate 	if (handle == NULL)
48540Sstevel@tonic-gate 		return (Z_INVAL);
48550Sstevel@tonic-gate 
48560Sstevel@tonic-gate 	if ((cur = handle->zone_dh_cur) == NULL)
48570Sstevel@tonic-gate 		return (Z_NO_ENTRY);
48580Sstevel@tonic-gate 
48590Sstevel@tonic-gate 	for (; cur != NULL; cur = cur->next)
48600Sstevel@tonic-gate 		if (!xmlStrcmp(cur->name, DTD_ELEM_RCTL))
48610Sstevel@tonic-gate 			break;
48620Sstevel@tonic-gate 	if (cur == NULL) {
48630Sstevel@tonic-gate 		handle->zone_dh_cur = handle->zone_dh_top;
48640Sstevel@tonic-gate 		return (Z_NO_ENTRY);
48650Sstevel@tonic-gate 	}
48660Sstevel@tonic-gate 
48670Sstevel@tonic-gate 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_rctl_name,
48680Sstevel@tonic-gate 	    sizeof (tabptr->zone_rctl_name))) != Z_OK) {
48690Sstevel@tonic-gate 		handle->zone_dh_cur = handle->zone_dh_top;
48700Sstevel@tonic-gate 		return (err);
48710Sstevel@tonic-gate 	}
48720Sstevel@tonic-gate 
48730Sstevel@tonic-gate 	tabptr->zone_rctl_valptr = NULL;
48740Sstevel@tonic-gate 	for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
48750Sstevel@tonic-gate 		valptr = (struct zone_rctlvaltab *)malloc(
48760Sstevel@tonic-gate 		    sizeof (struct zone_rctlvaltab));
48770Sstevel@tonic-gate 		if (valptr == NULL)
48780Sstevel@tonic-gate 			return (Z_NOMEM);
48790Sstevel@tonic-gate 		if (fetchprop(val, DTD_ATTR_PRIV, valptr->zone_rctlval_priv,
48800Sstevel@tonic-gate 		    sizeof (valptr->zone_rctlval_priv)) != Z_OK)
48810Sstevel@tonic-gate 			break;
48820Sstevel@tonic-gate 		if (fetchprop(val, DTD_ATTR_LIMIT, valptr->zone_rctlval_limit,
48830Sstevel@tonic-gate 		    sizeof (valptr->zone_rctlval_limit)) != Z_OK)
48840Sstevel@tonic-gate 			break;
48850Sstevel@tonic-gate 		if (fetchprop(val, DTD_ATTR_ACTION, valptr->zone_rctlval_action,
48860Sstevel@tonic-gate 		    sizeof (valptr->zone_rctlval_action)) != Z_OK)
48870Sstevel@tonic-gate 			break;
48880Sstevel@tonic-gate 		if (zonecfg_add_rctl_value(tabptr, valptr) != Z_OK)
48890Sstevel@tonic-gate 			break;
48900Sstevel@tonic-gate 	}
48910Sstevel@tonic-gate 
48920Sstevel@tonic-gate 	handle->zone_dh_cur = cur->next;
48930Sstevel@tonic-gate 	return (Z_OK);
48940Sstevel@tonic-gate }
48950Sstevel@tonic-gate 
48960Sstevel@tonic-gate int
zonecfg_endrctlent(zone_dochandle_t handle)48970Sstevel@tonic-gate zonecfg_endrctlent(zone_dochandle_t handle)
48980Sstevel@tonic-gate {
48990Sstevel@tonic-gate 	return (zonecfg_endent(handle));
49000Sstevel@tonic-gate }
49010Sstevel@tonic-gate 
49020Sstevel@tonic-gate int
zonecfg_setattrent(zone_dochandle_t handle)49030Sstevel@tonic-gate zonecfg_setattrent(zone_dochandle_t handle)
49040Sstevel@tonic-gate {
49050Sstevel@tonic-gate 	return (zonecfg_setent(handle));
49060Sstevel@tonic-gate }
49070Sstevel@tonic-gate 
49080Sstevel@tonic-gate int
zonecfg_getattrent(zone_dochandle_t handle,struct zone_attrtab * tabptr)49090Sstevel@tonic-gate zonecfg_getattrent(zone_dochandle_t handle, struct zone_attrtab *tabptr)
49100Sstevel@tonic-gate {
49110Sstevel@tonic-gate 	xmlNodePtr cur;
49120Sstevel@tonic-gate 	int err;
49130Sstevel@tonic-gate 
49140Sstevel@tonic-gate 	if (handle == NULL)
49150Sstevel@tonic-gate 		return (Z_INVAL);
49160Sstevel@tonic-gate 
49170Sstevel@tonic-gate 	if ((cur = handle->zone_dh_cur) == NULL)
49180Sstevel@tonic-gate 		return (Z_NO_ENTRY);
49190Sstevel@tonic-gate 
49200Sstevel@tonic-gate 	for (; cur != NULL; cur = cur->next)
49210Sstevel@tonic-gate 		if (!xmlStrcmp(cur->name, DTD_ELEM_ATTR))
49220Sstevel@tonic-gate 			break;
49230Sstevel@tonic-gate 	if (cur == NULL) {
49240Sstevel@tonic-gate 		handle->zone_dh_cur = handle->zone_dh_top;
49250Sstevel@tonic-gate 		return (Z_NO_ENTRY);
49260Sstevel@tonic-gate 	}
49270Sstevel@tonic-gate 
49280Sstevel@tonic-gate 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
49290Sstevel@tonic-gate 	    sizeof (tabptr->zone_attr_name))) != Z_OK) {
49300Sstevel@tonic-gate 		handle->zone_dh_cur = handle->zone_dh_top;
49310Sstevel@tonic-gate 		return (err);
49320Sstevel@tonic-gate 	}
49330Sstevel@tonic-gate 
49340Sstevel@tonic-gate 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
49350Sstevel@tonic-gate 	    sizeof (tabptr->zone_attr_type))) != Z_OK) {
49360Sstevel@tonic-gate 		handle->zone_dh_cur = handle->zone_dh_top;
49370Sstevel@tonic-gate 		return (err);
49380Sstevel@tonic-gate 	}
49390Sstevel@tonic-gate 
49400Sstevel@tonic-gate 	if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
49410Sstevel@tonic-gate 	    sizeof (tabptr->zone_attr_value))) != Z_OK) {
49420Sstevel@tonic-gate 		handle->zone_dh_cur = handle->zone_dh_top;
49430Sstevel@tonic-gate 		return (err);
49440Sstevel@tonic-gate 	}
49450Sstevel@tonic-gate 
49460Sstevel@tonic-gate 	handle->zone_dh_cur = cur->next;
49470Sstevel@tonic-gate 	return (Z_OK);
49480Sstevel@tonic-gate }
49490Sstevel@tonic-gate 
49500Sstevel@tonic-gate int
zonecfg_endattrent(zone_dochandle_t handle)49510Sstevel@tonic-gate zonecfg_endattrent(zone_dochandle_t handle)
49520Sstevel@tonic-gate {
49530Sstevel@tonic-gate 	return (zonecfg_endent(handle));
49540Sstevel@tonic-gate }
49550Sstevel@tonic-gate 
495612578SGlenn.Faden@Sun.COM int
zonecfg_setadminent(zone_dochandle_t handle)495712578SGlenn.Faden@Sun.COM zonecfg_setadminent(zone_dochandle_t handle)
495812578SGlenn.Faden@Sun.COM {
495912578SGlenn.Faden@Sun.COM 	return (zonecfg_setent(handle));
496012578SGlenn.Faden@Sun.COM }
496112578SGlenn.Faden@Sun.COM 
496212578SGlenn.Faden@Sun.COM int
zonecfg_getadminent(zone_dochandle_t handle,struct zone_admintab * tabptr)496312578SGlenn.Faden@Sun.COM zonecfg_getadminent(zone_dochandle_t handle, struct zone_admintab *tabptr)
496412578SGlenn.Faden@Sun.COM {
496512578SGlenn.Faden@Sun.COM 	xmlNodePtr cur;
496612578SGlenn.Faden@Sun.COM 	int err;
496712578SGlenn.Faden@Sun.COM 
496812578SGlenn.Faden@Sun.COM 	if (handle == NULL)
496912578SGlenn.Faden@Sun.COM 		return (Z_INVAL);
497012578SGlenn.Faden@Sun.COM 
497112578SGlenn.Faden@Sun.COM 	if ((cur = handle->zone_dh_cur) == NULL)
497212578SGlenn.Faden@Sun.COM 		return (Z_NO_ENTRY);
497312578SGlenn.Faden@Sun.COM 
497412578SGlenn.Faden@Sun.COM 	for (; cur != NULL; cur = cur->next)
497512578SGlenn.Faden@Sun.COM 		if (!xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
497612578SGlenn.Faden@Sun.COM 			break;
497712578SGlenn.Faden@Sun.COM 	if (cur == NULL) {
497812578SGlenn.Faden@Sun.COM 		handle->zone_dh_cur = handle->zone_dh_top;
497912578SGlenn.Faden@Sun.COM 		return (Z_NO_ENTRY);
498012578SGlenn.Faden@Sun.COM 	}
498112578SGlenn.Faden@Sun.COM 
498212578SGlenn.Faden@Sun.COM 	if ((err = fetchprop(cur, DTD_ATTR_USER, tabptr->zone_admin_user,
498312578SGlenn.Faden@Sun.COM 	    sizeof (tabptr->zone_admin_user))) != Z_OK) {
498412578SGlenn.Faden@Sun.COM 		handle->zone_dh_cur = handle->zone_dh_top;
498512578SGlenn.Faden@Sun.COM 		return (err);
498612578SGlenn.Faden@Sun.COM 	}
498712578SGlenn.Faden@Sun.COM 
498812578SGlenn.Faden@Sun.COM 
498912578SGlenn.Faden@Sun.COM 	if ((err = fetchprop(cur, DTD_ATTR_AUTHS, tabptr->zone_admin_auths,
499012578SGlenn.Faden@Sun.COM 	    sizeof (tabptr->zone_admin_auths))) != Z_OK) {
499112578SGlenn.Faden@Sun.COM 		handle->zone_dh_cur = handle->zone_dh_top;
499212578SGlenn.Faden@Sun.COM 		return (err);
499312578SGlenn.Faden@Sun.COM 	}
499412578SGlenn.Faden@Sun.COM 
499512578SGlenn.Faden@Sun.COM 	handle->zone_dh_cur = cur->next;
499612578SGlenn.Faden@Sun.COM 	return (Z_OK);
499712578SGlenn.Faden@Sun.COM }
499812578SGlenn.Faden@Sun.COM 
499912578SGlenn.Faden@Sun.COM int
zonecfg_endadminent(zone_dochandle_t handle)500012578SGlenn.Faden@Sun.COM zonecfg_endadminent(zone_dochandle_t handle)
500112578SGlenn.Faden@Sun.COM {
500212578SGlenn.Faden@Sun.COM 	return (zonecfg_endent(handle));
500312578SGlenn.Faden@Sun.COM }
500412578SGlenn.Faden@Sun.COM 
50051645Scomay /*
50061645Scomay  * The privileges available on the system and described in privileges(5)
50072712Snn35248  * fall into four categories with respect to non-global zones:
50082712Snn35248  *
50092712Snn35248  *      Default set of privileges considered safe for all non-global
50102712Snn35248  *      zones.  These privileges are "safe" in the sense that a
50112712Snn35248  *      privileged process in the zone cannot affect processes in any
50122712Snn35248  *      other zone on the system.
50132712Snn35248  *
50142712Snn35248  *      Set of privileges not currently permitted within a non-global
50152712Snn35248  *      zone.  These privileges are considered by default, "unsafe,"
50162712Snn35248  *      and include ones which affect global resources (such as the
50172712Snn35248  *      system clock or physical memory) or are overly broad and cover
50182712Snn35248  *      more than one mechanism in the system.  In other cases, there
50192712Snn35248  *      has not been sufficient virtualization in the parts of the
50202712Snn35248  *      system the privilege covers to allow its use within a
50212712Snn35248  *      non-global zone.
50222712Snn35248  *
50232712Snn35248  *      Set of privileges required in order to get a zone booted and
50242712Snn35248  *      init(1M) started.  These cannot be removed from the zone's
50252712Snn35248  *      privilege set.
50262712Snn35248  *
50272712Snn35248  * All other privileges are optional and are potentially useful for
50281645Scomay  * processes executing inside a non-global zone.
50291645Scomay  *
50301645Scomay  * When privileges are added to the system, a determination needs to be
50311645Scomay  * made as to which category the privilege belongs to.  Ideally,
50321645Scomay  * privileges should be fine-grained enough and the mechanisms they cover
50331645Scomay  * virtualized enough so that they can be made available to non-global
50341645Scomay  * zones.
50351645Scomay  */
50361645Scomay 
50371645Scomay /*
50381645Scomay  * Define some of the tokens that priv_str_to_set(3C) recognizes.  Since
50391645Scomay  * the privilege string separator can be any character, although it is
50401645Scomay  * usually a comma character, define these here as well in the event that
50411645Scomay  * they change or are augmented in the future.
50421645Scomay  */
50431645Scomay #define	BASIC_TOKEN		"basic"
50441645Scomay #define	DEFAULT_TOKEN		"default"
50451645Scomay #define	ZONE_TOKEN		"zone"
50461645Scomay #define	TOKEN_PRIV_CHAR		','
50471645Scomay #define	TOKEN_PRIV_STR		","
50481645Scomay 
50492712Snn35248 typedef struct priv_node {
50502712Snn35248 	struct priv_node	*pn_next;	/* Next privilege */
50512712Snn35248 	char			*pn_priv;	/* Privileges name */
50522712Snn35248 } priv_node_t;
50532712Snn35248 
50542712Snn35248 /* Privileges lists can differ across brands */
50552712Snn35248 typedef struct priv_lists {
50562712Snn35248 	/* Privileges considered safe for all non-global zones of a brand */
50572712Snn35248 	struct priv_node	*pl_default;
50582712Snn35248 
50592712Snn35248 	/* Privileges not permitted for all non-global zones of a brand */
50602712Snn35248 	struct priv_node	*pl_prohibited;
50612712Snn35248 
50622712Snn35248 	/* Privileges required for all non-global zones of a brand */
50632712Snn35248 	struct priv_node	*pl_required;
50643673Sdh155122 
50653673Sdh155122 	/*
50663673Sdh155122 	 * ip-type of the zone these privileges lists apply to.
50673673Sdh155122 	 * It is used to pass ip-type to the callback function,
50683673Sdh155122 	 * priv_lists_cb, which has no way of getting the ip-type.
50693673Sdh155122 	 */
50703673Sdh155122 	const char		*pl_iptype;
50712712Snn35248 } priv_lists_t;
50722712Snn35248 
50732712Snn35248 static int
priv_lists_cb(void * data,priv_iter_t * priv_iter)50743673Sdh155122 priv_lists_cb(void *data, priv_iter_t *priv_iter)
50752712Snn35248 {
50762712Snn35248 	priv_lists_t *plp = (priv_lists_t *)data;
50772712Snn35248 	priv_node_t *pnp;
50782712Snn35248 
50793673Sdh155122 	/* Skip this privilege if ip-type does not match */
50803673Sdh155122 	if ((strcmp(priv_iter->pi_iptype, "all") != 0) &&
50813673Sdh155122 	    (strcmp(priv_iter->pi_iptype, plp->pl_iptype) != 0))
50823673Sdh155122 		return (0);
50833673Sdh155122 
50842712Snn35248 	/* Allocate a new priv list node. */
50852712Snn35248 	if ((pnp = malloc(sizeof (*pnp))) == NULL)
50862712Snn35248 		return (-1);
50873673Sdh155122 	if ((pnp->pn_priv = strdup(priv_iter->pi_name)) == NULL) {
50882712Snn35248 		free(pnp);
50892712Snn35248 		return (-1);
50902712Snn35248 	}
50912712Snn35248 
50922712Snn35248 	/* Insert the new priv list node into the right list */
50933673Sdh155122 	if (strcmp(priv_iter->pi_set, "default") == 0) {
50942712Snn35248 		pnp->pn_next = plp->pl_default;
50952712Snn35248 		plp->pl_default = pnp;
50963673Sdh155122 	} else if (strcmp(priv_iter->pi_set, "prohibited") == 0) {
50972712Snn35248 		pnp->pn_next = plp->pl_prohibited;
50982712Snn35248 		plp->pl_prohibited = pnp;
50993673Sdh155122 	} else if (strcmp(priv_iter->pi_set, "required") == 0) {
51002712Snn35248 		pnp->pn_next = plp->pl_required;
51012712Snn35248 		plp->pl_required = pnp;
51022712Snn35248 	} else {
51032712Snn35248 		free(pnp->pn_priv);
51042712Snn35248 		free(pnp);
51052712Snn35248 		return (-1);
51062712Snn35248 	}
51072712Snn35248 	return (0);
51082712Snn35248 }
51092712Snn35248 
51102712Snn35248 static void
priv_lists_destroy(priv_lists_t * plp)51112712Snn35248 priv_lists_destroy(priv_lists_t *plp)
51122712Snn35248 {
51132712Snn35248 	priv_node_t *pnp;
51142712Snn35248 
51152712Snn35248 	assert(plp != NULL);
51162712Snn35248 
51172712Snn35248 	while ((pnp = plp->pl_default) != NULL) {
51182712Snn35248 		plp->pl_default = pnp->pn_next;
51192712Snn35248 		free(pnp->pn_priv);
51202712Snn35248 		free(pnp);
51212712Snn35248 	}
51222712Snn35248 	while ((pnp = plp->pl_prohibited) != NULL) {
51232712Snn35248 		plp->pl_prohibited = pnp->pn_next;
51242712Snn35248 		free(pnp->pn_priv);
51252712Snn35248 		free(pnp);
51262712Snn35248 	}
51272712Snn35248 	while ((pnp = plp->pl_required) != NULL) {
51282712Snn35248 		plp->pl_required = pnp->pn_next;
51292712Snn35248 		free(pnp->pn_priv);
51302712Snn35248 		free(pnp);
51312712Snn35248 	}
51322712Snn35248 	free(plp);
51332712Snn35248 }
51342712Snn35248 
51352712Snn35248 static int
priv_lists_create(zone_dochandle_t handle,char * brand,priv_lists_t ** plpp,const char * curr_iptype)513610943SEdward.Pilatowicz@Sun.COM priv_lists_create(zone_dochandle_t handle, char *brand, priv_lists_t **plpp,
51373673Sdh155122     const char *curr_iptype)
51382712Snn35248 {
51392712Snn35248 	priv_lists_t *plp;
51402727Sedp 	brand_handle_t bh;
514110943SEdward.Pilatowicz@Sun.COM 	char brand_str[MAXNAMELEN];
514210943SEdward.Pilatowicz@Sun.COM 
514310943SEdward.Pilatowicz@Sun.COM 	/* handle or brand must be set, but never both */
514410943SEdward.Pilatowicz@Sun.COM 	assert((handle != NULL) || (brand != NULL));
514510943SEdward.Pilatowicz@Sun.COM 	assert((handle == NULL) || (brand == NULL));
51462712Snn35248 
51472712Snn35248 	if (handle != NULL) {
514810943SEdward.Pilatowicz@Sun.COM 		brand = brand_str;
514910943SEdward.Pilatowicz@Sun.COM 		if (zonecfg_get_brand(handle, brand, sizeof (brand_str)) != 0)
51502712Snn35248 			return (Z_BRAND_ERROR);
51512712Snn35248 	}
51522712Snn35248 
51532727Sedp 	if ((bh = brand_open(brand)) == NULL)
51542712Snn35248 		return (Z_BRAND_ERROR);
51552712Snn35248 
51562712Snn35248 	if ((plp = calloc(1, sizeof (priv_lists_t))) == NULL) {
51572727Sedp 		brand_close(bh);
51582712Snn35248 		return (Z_NOMEM);
51592712Snn35248 	}
51602712Snn35248 
51613673Sdh155122 	plp->pl_iptype = curr_iptype;
51623673Sdh155122 
51632712Snn35248 	/* construct the privilege lists */
51642727Sedp 	if (brand_config_iter_privilege(bh, priv_lists_cb, plp) != 0) {
51652712Snn35248 		priv_lists_destroy(plp);
51662727Sedp 		brand_close(bh);
51672712Snn35248 		return (Z_BRAND_ERROR);
51682712Snn35248 	}
51692712Snn35248 
51702727Sedp 	brand_close(bh);
51712712Snn35248 	*plpp = plp;
51722712Snn35248 	return (Z_OK);
51732712Snn35248 }
51742712Snn35248 
51752712Snn35248 static int
get_default_privset(priv_set_t * privs,priv_lists_t * plp)51762712Snn35248 get_default_privset(priv_set_t *privs, priv_lists_t *plp)
51772712Snn35248 {
51782712Snn35248 	priv_node_t *pnp;
51791645Scomay 	priv_set_t *basic;
51801645Scomay 
51811645Scomay 	basic = priv_str_to_set(BASIC_TOKEN, TOKEN_PRIV_STR, NULL);
51820Sstevel@tonic-gate 	if (basic == NULL)
51831645Scomay 		return (errno == ENOMEM ? Z_NOMEM : Z_INVAL);
51840Sstevel@tonic-gate 
51850Sstevel@tonic-gate 	priv_union(basic, privs);
51860Sstevel@tonic-gate 	priv_freeset(basic);
51870Sstevel@tonic-gate 
51882712Snn35248 	for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) {
51892712Snn35248 		if (priv_addset(privs, pnp->pn_priv) != 0)
51900Sstevel@tonic-gate 			return (Z_INVAL);
51910Sstevel@tonic-gate 	}
51922712Snn35248 
51930Sstevel@tonic-gate 	return (Z_OK);
51940Sstevel@tonic-gate }
51950Sstevel@tonic-gate 
51962712Snn35248 int
zonecfg_default_brand(char * brand,size_t brandsize)519710943SEdward.Pilatowicz@Sun.COM zonecfg_default_brand(char *brand, size_t brandsize)
519810943SEdward.Pilatowicz@Sun.COM {
519910943SEdward.Pilatowicz@Sun.COM 	zone_dochandle_t handle;
520011176SEdward.Pilatowicz@Sun.COM 	int myzoneid = getzoneid();
520110943SEdward.Pilatowicz@Sun.COM 	int ret;
520210943SEdward.Pilatowicz@Sun.COM 
520311176SEdward.Pilatowicz@Sun.COM 	/*
520411176SEdward.Pilatowicz@Sun.COM 	 * If we're running within a zone, then the default brand is the
520511176SEdward.Pilatowicz@Sun.COM 	 * current zone's brand.
520611176SEdward.Pilatowicz@Sun.COM 	 */
520711176SEdward.Pilatowicz@Sun.COM 	if (myzoneid != GLOBAL_ZONEID) {
520811176SEdward.Pilatowicz@Sun.COM 		ret = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brand, brandsize);
520911176SEdward.Pilatowicz@Sun.COM 		if (ret < 0)
521011176SEdward.Pilatowicz@Sun.COM 			return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL);
521111176SEdward.Pilatowicz@Sun.COM 		return (Z_OK);
521211176SEdward.Pilatowicz@Sun.COM 	}
521311176SEdward.Pilatowicz@Sun.COM 
521410943SEdward.Pilatowicz@Sun.COM 	if ((handle = zonecfg_init_handle()) == NULL)
521510943SEdward.Pilatowicz@Sun.COM 		return (Z_NOMEM);
521610943SEdward.Pilatowicz@Sun.COM 	if ((ret = zonecfg_get_handle("SUNWdefault", handle)) == Z_OK) {
521710943SEdward.Pilatowicz@Sun.COM 		ret = i_zonecfg_get_brand(handle, brand, brandsize, B_TRUE);
521810943SEdward.Pilatowicz@Sun.COM 		zonecfg_fini_handle(handle);
521910943SEdward.Pilatowicz@Sun.COM 		return (ret);
522010943SEdward.Pilatowicz@Sun.COM 	}
522110943SEdward.Pilatowicz@Sun.COM 	return (ret);
522210943SEdward.Pilatowicz@Sun.COM }
522310943SEdward.Pilatowicz@Sun.COM 
522410943SEdward.Pilatowicz@Sun.COM int
zonecfg_default_privset(priv_set_t * privs,const char * curr_iptype)52253673Sdh155122 zonecfg_default_privset(priv_set_t *privs, const char *curr_iptype)
52262712Snn35248 {
52272712Snn35248 	priv_lists_t *plp;
522810943SEdward.Pilatowicz@Sun.COM 	char buf[MAXNAMELEN];
52292712Snn35248 	int ret;
52302712Snn35248 
523110943SEdward.Pilatowicz@Sun.COM 	if ((ret = zonecfg_default_brand(buf, sizeof (buf))) != Z_OK)
523210943SEdward.Pilatowicz@Sun.COM 		return (ret);
523310943SEdward.Pilatowicz@Sun.COM 	if ((ret = priv_lists_create(NULL, buf, &plp, curr_iptype)) != Z_OK)
52342712Snn35248 		return (ret);
52352712Snn35248 	ret = get_default_privset(privs, plp);
52362712Snn35248 	priv_lists_destroy(plp);
52372712Snn35248 	return (ret);
52382712Snn35248 }
52392712Snn35248 
52401645Scomay void
append_priv_token(char * priv,char * str,size_t strlen)52411645Scomay append_priv_token(char *priv, char *str, size_t strlen)
52421645Scomay {
52431645Scomay 	if (*str != '\0')
52441645Scomay 		(void) strlcat(str, TOKEN_PRIV_STR, strlen);
52451645Scomay 	(void) strlcat(str, priv, strlen);
52461645Scomay }
52471645Scomay 
52481645Scomay /*
52491645Scomay  * Verify that the supplied string is a valid privilege limit set for a
52501645Scomay  * non-global zone.  This string must not only be acceptable to
52511645Scomay  * priv_str_to_set(3C) which parses it, but it also must resolve to a
52521645Scomay  * privilege set that includes certain required privileges and lacks
52531645Scomay  * certain prohibited privileges.
52541645Scomay  */
52551645Scomay static int
verify_privset(char * privbuf,priv_set_t * privs,char ** privname,boolean_t add_default,priv_lists_t * plp)52561645Scomay verify_privset(char *privbuf, priv_set_t *privs, char **privname,
52572712Snn35248     boolean_t add_default, priv_lists_t *plp)
52582712Snn35248 {
52592712Snn35248 	priv_node_t *pnp;
52602712Snn35248 	char *tmp, *cp, *lasts;
52611645Scomay 	size_t len;
52621645Scomay 	priv_set_t *mergeset;
52631645Scomay 	const char *token;
52641645Scomay 
52651645Scomay 	/*
52661645Scomay 	 * The verification of the privilege string occurs in several
52671645Scomay 	 * phases.  In the first phase, the supplied string is scanned for
52681645Scomay 	 * the ZONE_TOKEN token which is not support as part of the
52691645Scomay 	 * "limitpriv" property.
52701645Scomay 	 *
52711645Scomay 	 * Duplicate the supplied privilege string since strtok_r(3C)
52721645Scomay 	 * tokenizes its input by null-terminating the tokens.
52731645Scomay 	 */
52741645Scomay 	if ((tmp = strdup(privbuf)) == NULL)
52751645Scomay 		return (Z_NOMEM);
52761645Scomay 	for (cp = strtok_r(tmp, TOKEN_PRIV_STR, &lasts); cp != NULL;
52771645Scomay 	    cp = strtok_r(NULL, TOKEN_PRIV_STR, &lasts)) {
52781645Scomay 		if (strcmp(cp, ZONE_TOKEN) == 0) {
52791645Scomay 			free(tmp);
52801645Scomay 			if ((*privname = strdup(ZONE_TOKEN)) == NULL)
52811645Scomay 				return (Z_NOMEM);
52821645Scomay 			else
52831645Scomay 				return (Z_PRIV_UNKNOWN);
52841645Scomay 		}
52851645Scomay 	}
52861645Scomay 	free(tmp);
52871645Scomay 
52881645Scomay 	if (add_default) {
52891645Scomay 		/*
52901645Scomay 		 * If DEFAULT_TOKEN was specified, a string needs to be
52911645Scomay 		 * built containing the privileges from the default, safe
52921645Scomay 		 * set along with those of the "limitpriv" property.
52931645Scomay 		 */
52941645Scomay 		len = strlen(privbuf) + sizeof (BASIC_TOKEN) + 2;
52952712Snn35248 
52962712Snn35248 		for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next)
52972712Snn35248 			len += strlen(pnp->pn_priv) + 1;
52981645Scomay 		tmp = alloca(len);
52991645Scomay 		*tmp = '\0';
53001645Scomay 
53011645Scomay 		append_priv_token(BASIC_TOKEN, tmp, len);
53022712Snn35248 		for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next)
53032712Snn35248 			append_priv_token(pnp->pn_priv, tmp, len);
53041645Scomay 		(void) strlcat(tmp, TOKEN_PRIV_STR, len);
53051645Scomay 		(void) strlcat(tmp, privbuf, len);
53061645Scomay 	} else {
53071645Scomay 		tmp = privbuf;
53081645Scomay 	}
53091645Scomay 
53101645Scomay 
53111645Scomay 	/*
53121645Scomay 	 * In the next phase, attempt to convert the merged privilege
53131645Scomay 	 * string into a privilege set.  In the case of an error, either
53141645Scomay 	 * there was a memory allocation failure or there was an invalid
53151645Scomay 	 * privilege token in the string.  In either case, return an
53161645Scomay 	 * appropriate error code but in the event of an invalid token,
53171645Scomay 	 * allocate a string containing its name and return that back to
53181645Scomay 	 * the caller.
53191645Scomay 	 */
53201645Scomay 	mergeset = priv_str_to_set(tmp, TOKEN_PRIV_STR, &token);
53211645Scomay 	if (mergeset == NULL) {
53221645Scomay 		if (token == NULL)
53231645Scomay 			return (Z_NOMEM);
53241645Scomay 		if ((cp = strchr(token, TOKEN_PRIV_CHAR)) != NULL)
53251645Scomay 			*cp = '\0';
53261645Scomay 		if ((*privname = strdup(token)) == NULL)
53271645Scomay 			return (Z_NOMEM);
53281645Scomay 		else
53291645Scomay 			return (Z_PRIV_UNKNOWN);
53301645Scomay 	}
53311645Scomay 
53321645Scomay 	/*
53331645Scomay 	 * Next, verify that none of the prohibited zone privileges are
53341645Scomay 	 * present in the merged privilege set.
53351645Scomay 	 */
53362712Snn35248 	for (pnp = plp->pl_prohibited; pnp != NULL; pnp = pnp->pn_next) {
53372712Snn35248 		if (priv_ismember(mergeset, pnp->pn_priv)) {
53381645Scomay 			priv_freeset(mergeset);
53392712Snn35248 			if ((*privname = strdup(pnp->pn_priv)) == NULL)
53401645Scomay 				return (Z_NOMEM);
53411645Scomay 			else
53421645Scomay 				return (Z_PRIV_PROHIBITED);
53431645Scomay 		}
53441645Scomay 	}
53451645Scomay 
53461645Scomay 	/*
53471645Scomay 	 * Finally, verify that all of the required zone privileges are
53481645Scomay 	 * present in the merged privilege set.
53491645Scomay 	 */
53502712Snn35248 	for (pnp = plp->pl_required; pnp != NULL; pnp = pnp->pn_next) {
53512712Snn35248 		if (!priv_ismember(mergeset, pnp->pn_priv)) {
53521645Scomay 			priv_freeset(mergeset);
53532712Snn35248 			if ((*privname = strdup(pnp->pn_priv)) == NULL)
53541645Scomay 				return (Z_NOMEM);
53551645Scomay 			else
53561645Scomay 				return (Z_PRIV_REQUIRED);
53571645Scomay 		}
53581645Scomay 	}
53591645Scomay 
53601645Scomay 	priv_copyset(mergeset, privs);
53611645Scomay 	priv_freeset(mergeset);
53621645Scomay 	return (Z_OK);
53631645Scomay }
53641645Scomay 
53651645Scomay /*
53661645Scomay  * Fill in the supplied privilege set with either the default, safe set of
53671645Scomay  * privileges suitable for a non-global zone, or one based on the
53681645Scomay  * "limitpriv" property in the zone's configuration.
53691645Scomay  *
53701645Scomay  * In the event of an invalid privilege specification in the
53711645Scomay  * configuration, a string is allocated and returned containing the
53721645Scomay  * "privilege" causing the issue.  It is the caller's responsibility to
53731645Scomay  * free this memory when it is done with it.
53741645Scomay  */
53751645Scomay int
zonecfg_get_privset(zone_dochandle_t handle,priv_set_t * privs,char ** privname)53761645Scomay zonecfg_get_privset(zone_dochandle_t handle, priv_set_t *privs,
53771645Scomay     char **privname)
53781645Scomay {
53792712Snn35248 	priv_lists_t *plp;
53802712Snn35248 	char *cp, *limitpriv = NULL;
53812712Snn35248 	int err, limitlen;
53823673Sdh155122 	zone_iptype_t iptype;
53833673Sdh155122 	const char *curr_iptype;
53841645Scomay 
53851645Scomay 	/*
53861645Scomay 	 * Attempt to lookup the "limitpriv" property.  If it does not
53871645Scomay 	 * exist or matches the string DEFAULT_TOKEN exactly, then the
53881645Scomay 	 * default, safe privilege set is returned.
53891645Scomay 	 */
53902712Snn35248 	if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) != Z_OK)
53911645Scomay 		return (err);
53922712Snn35248 
53933673Sdh155122 	if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK)
53943673Sdh155122 		return (err);
53953673Sdh155122 
53963673Sdh155122 	switch (iptype) {
53973673Sdh155122 	case ZS_SHARED:
53983673Sdh155122 		curr_iptype = "shared";
53993673Sdh155122 		break;
54003673Sdh155122 	case ZS_EXCLUSIVE:
54013673Sdh155122 		curr_iptype = "exclusive";
54023673Sdh155122 		break;
54033673Sdh155122 	}
54043673Sdh155122 
540510943SEdward.Pilatowicz@Sun.COM 	if ((err = priv_lists_create(handle, NULL, &plp, curr_iptype)) != Z_OK)
54062712Snn35248 		return (err);
54072712Snn35248 
54081645Scomay 	limitlen = strlen(limitpriv);
54091645Scomay 	if (limitlen == 0 || strcmp(limitpriv, DEFAULT_TOKEN) == 0) {
54101645Scomay 		free(limitpriv);
54112712Snn35248 		err = get_default_privset(privs, plp);
54122712Snn35248 		priv_lists_destroy(plp);
54132712Snn35248 		return (err);
54141645Scomay 	}
54151645Scomay 
54161645Scomay 	/*
54171645Scomay 	 * Check if the string DEFAULT_TOKEN is the first token in a list
54181645Scomay 	 * of privileges.
54191645Scomay 	 */
54201645Scomay 	cp = strchr(limitpriv, TOKEN_PRIV_CHAR);
54211645Scomay 	if (cp != NULL &&
54221645Scomay 	    strncmp(limitpriv, DEFAULT_TOKEN, cp - limitpriv) == 0)
54232712Snn35248 		err = verify_privset(cp + 1, privs, privname, B_TRUE, plp);
54241645Scomay 	else
54252712Snn35248 		err = verify_privset(limitpriv, privs, privname, B_FALSE, plp);
54261645Scomay 
54271645Scomay 	free(limitpriv);
54282712Snn35248 	priv_lists_destroy(plp);
54291645Scomay 	return (err);
54301645Scomay }
54311645Scomay 
54320Sstevel@tonic-gate int
zone_get_zonepath(char * zone_name,char * zonepath,size_t rp_sz)54330Sstevel@tonic-gate zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz)
54340Sstevel@tonic-gate {
54350Sstevel@tonic-gate 	zone_dochandle_t handle;
54360Sstevel@tonic-gate 	boolean_t found = B_FALSE;
54370Sstevel@tonic-gate 	struct zoneent *ze;
54380Sstevel@tonic-gate 	FILE *cookie;
54390Sstevel@tonic-gate 	int err;
5440766Scarlsonj 	char *cp;
54410Sstevel@tonic-gate 
54420Sstevel@tonic-gate 	if (zone_name == NULL)
54430Sstevel@tonic-gate 		return (Z_INVAL);
54440Sstevel@tonic-gate 
5445766Scarlsonj 	(void) strlcpy(zonepath, zonecfg_root, rp_sz);
5446766Scarlsonj 	cp = zonepath + strlen(zonepath);
5447766Scarlsonj 	while (cp > zonepath && cp[-1] == '/')
5448766Scarlsonj 		*--cp = '\0';
5449766Scarlsonj 
54500Sstevel@tonic-gate 	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) {
5451766Scarlsonj 		if (zonepath[0] == '\0')
5452766Scarlsonj 			(void) strlcpy(zonepath, "/", rp_sz);
54530Sstevel@tonic-gate 		return (Z_OK);
54540Sstevel@tonic-gate 	}
54550Sstevel@tonic-gate 
54560Sstevel@tonic-gate 	/*
54570Sstevel@tonic-gate 	 * First check the index file.  Because older versions did not have
54580Sstevel@tonic-gate 	 * a copy of the zone path, allow for it to be zero length, in which
54590Sstevel@tonic-gate 	 * case we ignore this result and fall back to the XML files.
54600Sstevel@tonic-gate 	 */
54610Sstevel@tonic-gate 	cookie = setzoneent();
54620Sstevel@tonic-gate 	while ((ze = getzoneent_private(cookie)) != NULL) {
54630Sstevel@tonic-gate 		if (strcmp(ze->zone_name, zone_name) == 0) {
54640Sstevel@tonic-gate 			found = B_TRUE;
5465766Scarlsonj 			if (ze->zone_path[0] != '\0')
5466766Scarlsonj 				(void) strlcpy(cp, ze->zone_path,
5467766Scarlsonj 				    rp_sz - (cp - zonepath));
54680Sstevel@tonic-gate 		}
54690Sstevel@tonic-gate 		free(ze);
54700Sstevel@tonic-gate 		if (found)
54710Sstevel@tonic-gate 			break;
54720Sstevel@tonic-gate 	}
54730Sstevel@tonic-gate 	endzoneent(cookie);
5474766Scarlsonj 	if (found && *cp != '\0')
54750Sstevel@tonic-gate 		return (Z_OK);
54760Sstevel@tonic-gate 
54770Sstevel@tonic-gate 	/* Fall back to the XML files. */
54780Sstevel@tonic-gate 	if ((handle = zonecfg_init_handle()) == NULL)
54790Sstevel@tonic-gate 		return (Z_NOMEM);
54800Sstevel@tonic-gate 
54810Sstevel@tonic-gate 	/*
54820Sstevel@tonic-gate 	 * Check the snapshot first: if a zone is running, its zonepath
54830Sstevel@tonic-gate 	 * may have changed.
54840Sstevel@tonic-gate 	 */
54850Sstevel@tonic-gate 	if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
54863716Sgjelinek 		if ((err = zonecfg_get_handle(zone_name, handle)) != Z_OK) {
54873716Sgjelinek 			zonecfg_fini_handle(handle);
54880Sstevel@tonic-gate 			return (err);
54893716Sgjelinek 		}
54900Sstevel@tonic-gate 	}
54910Sstevel@tonic-gate 	err = zonecfg_get_zonepath(handle, zonepath, rp_sz);
54920Sstevel@tonic-gate 	zonecfg_fini_handle(handle);
54930Sstevel@tonic-gate 	return (err);
54940Sstevel@tonic-gate }
54950Sstevel@tonic-gate 
54960Sstevel@tonic-gate int
zone_get_rootpath(char * zone_name,char * rootpath,size_t rp_sz)54970Sstevel@tonic-gate zone_get_rootpath(char *zone_name, char *rootpath, size_t rp_sz)
54980Sstevel@tonic-gate {
54990Sstevel@tonic-gate 	int err;
55000Sstevel@tonic-gate 
55010Sstevel@tonic-gate 	/* This function makes sense for non-global zones only. */
55020Sstevel@tonic-gate 	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
55030Sstevel@tonic-gate 		return (Z_BOGUS_ZONE_NAME);
55040Sstevel@tonic-gate 	if ((err = zone_get_zonepath(zone_name, rootpath, rp_sz)) != Z_OK)
55050Sstevel@tonic-gate 		return (err);
55060Sstevel@tonic-gate 	if (strlcat(rootpath, "/root", rp_sz) >= rp_sz)
55070Sstevel@tonic-gate 		return (Z_TOO_BIG);
55080Sstevel@tonic-gate 	return (Z_OK);
55090Sstevel@tonic-gate }
55100Sstevel@tonic-gate 
55112712Snn35248 int
zone_get_brand(char * zone_name,char * brandname,size_t rp_sz)55122712Snn35248 zone_get_brand(char *zone_name, char *brandname, size_t rp_sz)
55132712Snn35248 {
55142712Snn35248 	int err;
55152712Snn35248 	zone_dochandle_t handle;
55162712Snn35248 	char myzone[MAXNAMELEN];
55172712Snn35248 	int myzoneid = getzoneid();
55182712Snn35248 
55192712Snn35248 	/*
55202712Snn35248 	 * If we are not in the global zone, then we don't have the zone
55212712Snn35248 	 * .xml files with the brand name available.  Thus, we are going to
55222712Snn35248 	 * have to ask the kernel for the information.
55232712Snn35248 	 */
55242712Snn35248 	if (myzoneid != GLOBAL_ZONEID) {
55253979Sgjelinek 		if (is_system_labeled()) {
55263979Sgjelinek 			(void) strlcpy(brandname, NATIVE_BRAND_NAME, rp_sz);
55273979Sgjelinek 			return (Z_OK);
55283979Sgjelinek 		}
55292712Snn35248 		if (zone_getattr(myzoneid, ZONE_ATTR_NAME, myzone,
55302712Snn35248 		    sizeof (myzone)) < 0)
55312712Snn35248 			return (Z_NO_ZONE);
55329719SSaurabh.Vyas@Sun.COM 		if (!zonecfg_is_scratch(myzone)) {
55339719SSaurabh.Vyas@Sun.COM 			if (strncmp(zone_name, myzone, MAXNAMELEN) != 0)
55349719SSaurabh.Vyas@Sun.COM 				return (Z_NO_ZONE);
55359719SSaurabh.Vyas@Sun.COM 		}
55362712Snn35248 		err = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brandname, rp_sz);
55372712Snn35248 		if (err < 0)
55382712Snn35248 			return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL);
55399719SSaurabh.Vyas@Sun.COM 
55402712Snn35248 		return (Z_OK);
55412712Snn35248 	}
55422712Snn35248 
554310943SEdward.Pilatowicz@Sun.COM 	if (strcmp(zone_name, "global") == 0)
554410943SEdward.Pilatowicz@Sun.COM 		return (zonecfg_default_brand(brandname, rp_sz));
554510943SEdward.Pilatowicz@Sun.COM 
55462712Snn35248 	if ((handle = zonecfg_init_handle()) == NULL)
55472712Snn35248 		return (Z_NOMEM);
55482712Snn35248 
55492712Snn35248 	err = zonecfg_get_handle((char *)zone_name, handle);
55502712Snn35248 	if (err == Z_OK)
55512712Snn35248 		err = zonecfg_get_brand(handle, brandname, rp_sz);
55522712Snn35248 
55532712Snn35248 	zonecfg_fini_handle(handle);
55542712Snn35248 	return (err);
55552712Snn35248 }
55562712Snn35248 
55572621Sllai1 /*
55582621Sllai1  * Return the appropriate root for the active /dev.
55592621Sllai1  * For normal zone, the path is $ZONEPATH/root;
55602621Sllai1  * for scratch zone, the dev path is $ZONEPATH/lu.
55612621Sllai1  */
55622621Sllai1 int
zone_get_devroot(char * zone_name,char * devroot,size_t rp_sz)55632621Sllai1 zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz)
55642621Sllai1 {
55652621Sllai1 	int err;
55662621Sllai1 	char *suffix;
55672621Sllai1 	zone_state_t state;
55682621Sllai1 
55692621Sllai1 	/* This function makes sense for non-global zones only. */
55702621Sllai1 	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
55712621Sllai1 		return (Z_BOGUS_ZONE_NAME);
55722621Sllai1 	if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK)
55732621Sllai1 		return (err);
55742621Sllai1 
55752621Sllai1 	if (zone_get_state(zone_name, &state) == Z_OK &&
55762621Sllai1 	    state == ZONE_STATE_MOUNTED)
55772621Sllai1 		suffix = "/lu";
55782621Sllai1 	else
55792621Sllai1 		suffix = "/root";
55802621Sllai1 	if (strlcat(devroot, suffix, rp_sz) >= rp_sz)
55812621Sllai1 		return (Z_TOO_BIG);
55822621Sllai1 	return (Z_OK);
55832621Sllai1 }
55842621Sllai1 
55850Sstevel@tonic-gate static zone_state_t
kernel_state_to_user_state(zoneid_t zoneid,zone_status_t kernel_state)5586766Scarlsonj kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state)
55870Sstevel@tonic-gate {
5588766Scarlsonj 	char zoneroot[MAXPATHLEN];
5589766Scarlsonj 	size_t zlen;
5590766Scarlsonj 
55910Sstevel@tonic-gate 	assert(kernel_state <= ZONE_MAX_STATE);
55920Sstevel@tonic-gate 	switch (kernel_state) {
55930Sstevel@tonic-gate 		case ZONE_IS_UNINITIALIZED:
55945880Snordmark 		case ZONE_IS_INITIALIZED:
55955880Snordmark 			/* The kernel will not return these two states */
5596766Scarlsonj 			return (ZONE_STATE_READY);
55970Sstevel@tonic-gate 		case ZONE_IS_READY:
5598766Scarlsonj 			/*
5599766Scarlsonj 			 * If the zone's root is mounted on $ZONEPATH/lu, then
5600766Scarlsonj 			 * it's a mounted scratch zone.
5601766Scarlsonj 			 */
5602766Scarlsonj 			if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot,
5603766Scarlsonj 			    sizeof (zoneroot)) >= 0) {
5604766Scarlsonj 				zlen = strlen(zoneroot);
5605766Scarlsonj 				if (zlen > 3 &&
5606766Scarlsonj 				    strcmp(zoneroot + zlen - 3, "/lu") == 0)
5607766Scarlsonj 					return (ZONE_STATE_MOUNTED);
5608766Scarlsonj 			}
56090Sstevel@tonic-gate 			return (ZONE_STATE_READY);
56100Sstevel@tonic-gate 		case ZONE_IS_BOOTING:
56110Sstevel@tonic-gate 		case ZONE_IS_RUNNING:
56120Sstevel@tonic-gate 			return (ZONE_STATE_RUNNING);
56130Sstevel@tonic-gate 		case ZONE_IS_SHUTTING_DOWN:
56140Sstevel@tonic-gate 		case ZONE_IS_EMPTY:
56150Sstevel@tonic-gate 			return (ZONE_STATE_SHUTTING_DOWN);
56160Sstevel@tonic-gate 		case ZONE_IS_DOWN:
56170Sstevel@tonic-gate 		case ZONE_IS_DYING:
56180Sstevel@tonic-gate 		case ZONE_IS_DEAD:
56190Sstevel@tonic-gate 		default:
56200Sstevel@tonic-gate 			return (ZONE_STATE_DOWN);
56210Sstevel@tonic-gate 	}
56220Sstevel@tonic-gate 	/* NOTREACHED */
56230Sstevel@tonic-gate }
56240Sstevel@tonic-gate 
56250Sstevel@tonic-gate int
zone_get_state(char * zone_name,zone_state_t * state_num)56260Sstevel@tonic-gate zone_get_state(char *zone_name, zone_state_t *state_num)
56270Sstevel@tonic-gate {
56280Sstevel@tonic-gate 	zone_status_t status;
56290Sstevel@tonic-gate 	zoneid_t zone_id;
56300Sstevel@tonic-gate 	struct zoneent *ze;
56310Sstevel@tonic-gate 	boolean_t found = B_FALSE;
56320Sstevel@tonic-gate 	FILE *cookie;
5633766Scarlsonj 	char kernzone[ZONENAME_MAX];
5634766Scarlsonj 	FILE *fp;
56350Sstevel@tonic-gate 
56360Sstevel@tonic-gate 	if (zone_name == NULL)
56370Sstevel@tonic-gate 		return (Z_INVAL);
56380Sstevel@tonic-gate 
5639766Scarlsonj 	/*
5640766Scarlsonj 	 * If we're looking at an alternate root, then we need to query the
5641766Scarlsonj 	 * kernel using the scratch zone name.
5642766Scarlsonj 	 */
5643766Scarlsonj 	zone_id = -1;
5644766Scarlsonj 	if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) {
5645766Scarlsonj 		if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) {
5646766Scarlsonj 			if (zonecfg_find_scratch(fp, zone_name, zonecfg_root,
5647766Scarlsonj 			    kernzone, sizeof (kernzone)) == 0)
5648766Scarlsonj 				zone_id = getzoneidbyname(kernzone);
5649766Scarlsonj 			zonecfg_close_scratch(fp);
5650766Scarlsonj 		}
5651766Scarlsonj 	} else {
5652766Scarlsonj 		zone_id = getzoneidbyname(zone_name);
5653766Scarlsonj 	}
5654766Scarlsonj 
56550Sstevel@tonic-gate 	/* check to see if zone is running */
5656766Scarlsonj 	if (zone_id != -1 &&
56570Sstevel@tonic-gate 	    zone_getattr(zone_id, ZONE_ATTR_STATUS, &status,
56580Sstevel@tonic-gate 	    sizeof (status)) >= 0) {
5659766Scarlsonj 		*state_num = kernel_state_to_user_state(zone_id, status);
56600Sstevel@tonic-gate 		return (Z_OK);
56610Sstevel@tonic-gate 	}
56620Sstevel@tonic-gate 
56630Sstevel@tonic-gate 	cookie = setzoneent();
56640Sstevel@tonic-gate 	while ((ze = getzoneent_private(cookie)) != NULL) {
56650Sstevel@tonic-gate 		if (strcmp(ze->zone_name, zone_name) == 0) {
56660Sstevel@tonic-gate 			found = B_TRUE;
56670Sstevel@tonic-gate 			*state_num = ze->zone_state;
56680Sstevel@tonic-gate 		}
56690Sstevel@tonic-gate 		free(ze);
56700Sstevel@tonic-gate 		if (found)
56710Sstevel@tonic-gate 			break;
56720Sstevel@tonic-gate 	}
56730Sstevel@tonic-gate 	endzoneent(cookie);
56740Sstevel@tonic-gate 	return ((found) ? Z_OK : Z_NO_ZONE);
56750Sstevel@tonic-gate }
56760Sstevel@tonic-gate 
56770Sstevel@tonic-gate int
zone_set_state(char * zone,zone_state_t state)56780Sstevel@tonic-gate zone_set_state(char *zone, zone_state_t state)
56790Sstevel@tonic-gate {
56800Sstevel@tonic-gate 	struct zoneent ze;
56810Sstevel@tonic-gate 
56820Sstevel@tonic-gate 	if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED &&
56830Sstevel@tonic-gate 	    state != ZONE_STATE_INCOMPLETE)
56840Sstevel@tonic-gate 		return (Z_INVAL);
56850Sstevel@tonic-gate 
5686565Sdp 	bzero(&ze, sizeof (ze));
56870Sstevel@tonic-gate 	(void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name));
56880Sstevel@tonic-gate 	ze.zone_state = state;
56890Sstevel@tonic-gate 	(void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path));
56900Sstevel@tonic-gate 	return (putzoneent(&ze, PZE_MODIFY));
56910Sstevel@tonic-gate }
56920Sstevel@tonic-gate 
56930Sstevel@tonic-gate /*
56940Sstevel@tonic-gate  * Get id (if any) for specified zone.  There are four possible outcomes:
56950Sstevel@tonic-gate  * - If the string corresponds to the numeric id of an active (booted)
56960Sstevel@tonic-gate  *   zone, sets *zip to the zone id and returns 0.
56970Sstevel@tonic-gate  * - If the string corresponds to the name of an active (booted) zone,
56980Sstevel@tonic-gate  *   sets *zip to the zone id and returns 0.
56990Sstevel@tonic-gate  * - If the string is a name in the configuration but is not booted,
57000Sstevel@tonic-gate  *   sets *zip to ZONE_ID_UNDEFINED and returns 0.
57010Sstevel@tonic-gate  * - Otherwise, leaves *zip unchanged and returns -1.
57020Sstevel@tonic-gate  *
57030Sstevel@tonic-gate  * This function acts as an auxiliary filter on the function of the same
57040Sstevel@tonic-gate  * name in libc; the linker binds to this version if libzonecfg exists,
57050Sstevel@tonic-gate  * and the libc version if it doesn't.  Any changes to this version of
57060Sstevel@tonic-gate  * the function should probably be reflected in the libc version as well.
57070Sstevel@tonic-gate  */
57080Sstevel@tonic-gate int
zone_get_id(const char * str,zoneid_t * zip)57090Sstevel@tonic-gate zone_get_id(const char *str, zoneid_t *zip)
57100Sstevel@tonic-gate {
57110Sstevel@tonic-gate 	zone_dochandle_t hdl;
57120Sstevel@tonic-gate 	zoneid_t zoneid;
57130Sstevel@tonic-gate 	char *cp;
57140Sstevel@tonic-gate 	int err;
57150Sstevel@tonic-gate 
57160Sstevel@tonic-gate 	/* first try looking for active zone by id */
57170Sstevel@tonic-gate 	errno = 0;
57180Sstevel@tonic-gate 	zoneid = (zoneid_t)strtol(str, &cp, 0);
57190Sstevel@tonic-gate 	if (errno == 0 && cp != str && *cp == '\0' &&
57200Sstevel@tonic-gate 	    getzonenamebyid(zoneid, NULL, 0) != -1) {
57210Sstevel@tonic-gate 		*zip = zoneid;
57220Sstevel@tonic-gate 		return (0);
57230Sstevel@tonic-gate 	}
57240Sstevel@tonic-gate 
57250Sstevel@tonic-gate 	/* then look for active zone by name */
57260Sstevel@tonic-gate 	if ((zoneid = getzoneidbyname(str)) != -1) {
57270Sstevel@tonic-gate 		*zip = zoneid;
57280Sstevel@tonic-gate 		return (0);
57290Sstevel@tonic-gate 	}
57300Sstevel@tonic-gate 
57310Sstevel@tonic-gate 	/* if in global zone, try looking up name in configuration database */
57320Sstevel@tonic-gate 	if (getzoneid() != GLOBAL_ZONEID ||
57330Sstevel@tonic-gate 	    (hdl = zonecfg_init_handle()) == NULL)
57340Sstevel@tonic-gate 		return (-1);
57350Sstevel@tonic-gate 
5736766Scarlsonj 	if (zonecfg_get_handle(str, hdl) == Z_OK) {
57370Sstevel@tonic-gate 		/* zone exists but isn't active */
57380Sstevel@tonic-gate 		*zip = ZONE_ID_UNDEFINED;
57390Sstevel@tonic-gate 		err = 0;
57400Sstevel@tonic-gate 	} else {
57410Sstevel@tonic-gate 		err = -1;
57420Sstevel@tonic-gate 	}
57430Sstevel@tonic-gate 
57440Sstevel@tonic-gate 	zonecfg_fini_handle(hdl);
57450Sstevel@tonic-gate 	return (err);
57460Sstevel@tonic-gate }
57470Sstevel@tonic-gate 
57480Sstevel@tonic-gate char *
zone_state_str(zone_state_t state_num)57490Sstevel@tonic-gate zone_state_str(zone_state_t state_num)
57500Sstevel@tonic-gate {
57510Sstevel@tonic-gate 	switch (state_num) {
57520Sstevel@tonic-gate 	case ZONE_STATE_CONFIGURED:
57530Sstevel@tonic-gate 		return (ZONE_STATE_STR_CONFIGURED);
57540Sstevel@tonic-gate 	case ZONE_STATE_INCOMPLETE:
57550Sstevel@tonic-gate 		return (ZONE_STATE_STR_INCOMPLETE);
57560Sstevel@tonic-gate 	case ZONE_STATE_INSTALLED:
57570Sstevel@tonic-gate 		return (ZONE_STATE_STR_INSTALLED);
57580Sstevel@tonic-gate 	case ZONE_STATE_READY:
57590Sstevel@tonic-gate 		return (ZONE_STATE_STR_READY);
5760766Scarlsonj 	case ZONE_STATE_MOUNTED:
5761766Scarlsonj 		return (ZONE_STATE_STR_MOUNTED);
57620Sstevel@tonic-gate 	case ZONE_STATE_RUNNING:
57630Sstevel@tonic-gate 		return (ZONE_STATE_STR_RUNNING);
57640Sstevel@tonic-gate 	case ZONE_STATE_SHUTTING_DOWN:
57650Sstevel@tonic-gate 		return (ZONE_STATE_STR_SHUTTING_DOWN);
57660Sstevel@tonic-gate 	case ZONE_STATE_DOWN:
57670Sstevel@tonic-gate 		return (ZONE_STATE_STR_DOWN);
57680Sstevel@tonic-gate 	default:
57690Sstevel@tonic-gate 		return ("unknown");
57700Sstevel@tonic-gate 	}
57710Sstevel@tonic-gate }
57720Sstevel@tonic-gate 
57730Sstevel@tonic-gate /*
5774766Scarlsonj  * Given a UUID value, find an associated zone name.  This is intended to be
5775766Scarlsonj  * used by callers who set up some 'default' name (corresponding to the
5776766Scarlsonj  * expected name for the zone) in the zonename buffer, and thus the function
5777766Scarlsonj  * doesn't touch this buffer on failure.
5778766Scarlsonj  */
5779766Scarlsonj int
zonecfg_get_name_by_uuid(const uuid_t uuidin,char * zonename,size_t namelen)57802303Scarlsonj zonecfg_get_name_by_uuid(const uuid_t uuidin, char *zonename, size_t namelen)
5781766Scarlsonj {
5782766Scarlsonj 	FILE *fp;
5783766Scarlsonj 	struct zoneent *ze;
57842303Scarlsonj 	uchar_t *uuid;
5785766Scarlsonj 
5786766Scarlsonj 	/*
5787766Scarlsonj 	 * A small amount of subterfuge via casts is necessary here because
5788766Scarlsonj 	 * libuuid doesn't use const correctly, but we don't want to export
5789766Scarlsonj 	 * this brokenness to our clients.
5790766Scarlsonj 	 */
57912303Scarlsonj 	uuid = (uchar_t *)uuidin;
57922303Scarlsonj 	if (uuid_is_null(uuid))
5793766Scarlsonj 		return (Z_NO_ZONE);
5794766Scarlsonj 	if ((fp = setzoneent()) == NULL)
5795766Scarlsonj 		return (Z_NO_ZONE);
5796766Scarlsonj 	while ((ze = getzoneent_private(fp)) != NULL) {
57972303Scarlsonj 		if (uuid_compare(uuid, ze->zone_uuid) == 0)
5798766Scarlsonj 			break;
5799766Scarlsonj 		free(ze);
5800766Scarlsonj 	}
5801766Scarlsonj 	endzoneent(fp);
5802766Scarlsonj 	if (ze != NULL) {
5803766Scarlsonj 		(void) strlcpy(zonename, ze->zone_name, namelen);
5804766Scarlsonj 		free(ze);
5805766Scarlsonj 		return (Z_OK);
5806766Scarlsonj 	} else {
5807766Scarlsonj 		return (Z_NO_ZONE);
5808766Scarlsonj 	}
5809766Scarlsonj }
5810766Scarlsonj 
5811766Scarlsonj /*
5812766Scarlsonj  * Given a zone name, get its UUID.  Returns a "NULL" UUID value if the zone
5813766Scarlsonj  * exists but the file doesn't have a value set yet.  Returns an error if the
5814766Scarlsonj  * zone cannot be located.
5815766Scarlsonj  */
5816766Scarlsonj int
zonecfg_get_uuid(const char * zonename,uuid_t uuid)5817766Scarlsonj zonecfg_get_uuid(const char *zonename, uuid_t uuid)
5818766Scarlsonj {
5819766Scarlsonj 	FILE *fp;
5820766Scarlsonj 	struct zoneent *ze;
5821766Scarlsonj 
5822766Scarlsonj 	if ((fp = setzoneent()) == NULL)
5823766Scarlsonj 		return (Z_NO_ZONE);
5824766Scarlsonj 	while ((ze = getzoneent_private(fp)) != NULL) {
5825766Scarlsonj 		if (strcmp(ze->zone_name, zonename) == 0)
5826766Scarlsonj 			break;
5827766Scarlsonj 		free(ze);
5828766Scarlsonj 	}
5829766Scarlsonj 	endzoneent(fp);
5830766Scarlsonj 	if (ze != NULL) {
5831766Scarlsonj 		uuid_copy(uuid, ze->zone_uuid);
5832766Scarlsonj 		free(ze);
5833766Scarlsonj 		return (Z_OK);
5834766Scarlsonj 	} else {
5835766Scarlsonj 		return (Z_NO_ZONE);
5836766Scarlsonj 	}
5837766Scarlsonj }
5838766Scarlsonj 
5839766Scarlsonj /*
58400Sstevel@tonic-gate  * File-system convenience functions.
58410Sstevel@tonic-gate  */
58420Sstevel@tonic-gate boolean_t
zonecfg_valid_fs_type(const char * type)58430Sstevel@tonic-gate zonecfg_valid_fs_type(const char *type)
58440Sstevel@tonic-gate {
58450Sstevel@tonic-gate 	/*
58460Sstevel@tonic-gate 	 * We already know which FS types don't work.
58470Sstevel@tonic-gate 	 */
58480Sstevel@tonic-gate 	if (strcmp(type, "proc") == 0 ||
58490Sstevel@tonic-gate 	    strcmp(type, "mntfs") == 0 ||
58500Sstevel@tonic-gate 	    strcmp(type, "autofs") == 0 ||
58510Sstevel@tonic-gate 	    strncmp(type, "nfs", sizeof ("nfs") - 1) == 0 ||
58520Sstevel@tonic-gate 	    strcmp(type, "cachefs") == 0)
58530Sstevel@tonic-gate 		return (B_FALSE);
58540Sstevel@tonic-gate 	/*
58550Sstevel@tonic-gate 	 * The caller may do more detailed verification to make sure other
58560Sstevel@tonic-gate 	 * aspects of this filesystem type make sense.
58570Sstevel@tonic-gate 	 */
58580Sstevel@tonic-gate 	return (B_TRUE);
58590Sstevel@tonic-gate }
58600Sstevel@tonic-gate 
58610Sstevel@tonic-gate /*
58620Sstevel@tonic-gate  * Generally uninteresting rctl convenience functions.
58630Sstevel@tonic-gate  */
58640Sstevel@tonic-gate 
58650Sstevel@tonic-gate int
zonecfg_construct_rctlblk(const struct zone_rctlvaltab * rctlval,rctlblk_t * rctlblk)58660Sstevel@tonic-gate zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval,
58670Sstevel@tonic-gate     rctlblk_t *rctlblk)
58680Sstevel@tonic-gate {
58690Sstevel@tonic-gate 	unsigned long long ull;
58700Sstevel@tonic-gate 	char *endp;
58710Sstevel@tonic-gate 	rctl_priv_t priv;
58720Sstevel@tonic-gate 	rctl_qty_t limit;
58730Sstevel@tonic-gate 	uint_t action;
58740Sstevel@tonic-gate 
58750Sstevel@tonic-gate 	/* Get the privilege */
58760Sstevel@tonic-gate 	if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) {
58770Sstevel@tonic-gate 		priv = RCPRIV_BASIC;
58780Sstevel@tonic-gate 	} else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) {
58790Sstevel@tonic-gate 		priv = RCPRIV_PRIVILEGED;
58800Sstevel@tonic-gate 	} else {
58810Sstevel@tonic-gate 		/* Invalid privilege */
58820Sstevel@tonic-gate 		return (Z_INVAL);
58830Sstevel@tonic-gate 	}
58840Sstevel@tonic-gate 
58850Sstevel@tonic-gate 	/* deal with negative input; strtoull(3c) doesn't do what we want */
58860Sstevel@tonic-gate 	if (rctlval->zone_rctlval_limit[0] == '-')
58870Sstevel@tonic-gate 		return (Z_INVAL);
58880Sstevel@tonic-gate 	/* Get the limit */
58890Sstevel@tonic-gate 	errno = 0;
58900Sstevel@tonic-gate 	ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0);
58910Sstevel@tonic-gate 	if (errno != 0 || *endp != '\0') {
58920Sstevel@tonic-gate 		/* parse failed */
58930Sstevel@tonic-gate 		return (Z_INVAL);
58940Sstevel@tonic-gate 	}
58950Sstevel@tonic-gate 	limit = (rctl_qty_t)ull;
58960Sstevel@tonic-gate 
58970Sstevel@tonic-gate 	/* Get the action */
58980Sstevel@tonic-gate 	if (strcmp(rctlval->zone_rctlval_action, "none") == 0) {
58990Sstevel@tonic-gate 		action = RCTL_LOCAL_NOACTION;
59000Sstevel@tonic-gate 	} else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) {
59010Sstevel@tonic-gate 		action = RCTL_LOCAL_SIGNAL;
59020Sstevel@tonic-gate 	} else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) {
59030Sstevel@tonic-gate 		action = RCTL_LOCAL_DENY;
59040Sstevel@tonic-gate 	} else {
59050Sstevel@tonic-gate 		/* Invalid Action */
59060Sstevel@tonic-gate 		return (Z_INVAL);
59070Sstevel@tonic-gate 	}
59080Sstevel@tonic-gate 	rctlblk_set_local_action(rctlblk, action, 0);
59090Sstevel@tonic-gate 	rctlblk_set_privilege(rctlblk, priv);
59100Sstevel@tonic-gate 	rctlblk_set_value(rctlblk, limit);
59110Sstevel@tonic-gate 	return (Z_OK);
59120Sstevel@tonic-gate }
59130Sstevel@tonic-gate 
59140Sstevel@tonic-gate static int
rctl_check(const char * rctlname,void * arg)59150Sstevel@tonic-gate rctl_check(const char *rctlname, void *arg)
59160Sstevel@tonic-gate {
59170Sstevel@tonic-gate 	const char *attrname = arg;
59180Sstevel@tonic-gate 
59190Sstevel@tonic-gate 	/*
59200Sstevel@tonic-gate 	 * Returning 1 here is our signal to zonecfg_is_rctl() that it is
59210Sstevel@tonic-gate 	 * indeed an rctl name recognized by the system.
59220Sstevel@tonic-gate 	 */
59230Sstevel@tonic-gate 	return (strcmp(rctlname, attrname) == 0 ? 1 : 0);
59240Sstevel@tonic-gate }
59250Sstevel@tonic-gate 
59260Sstevel@tonic-gate boolean_t
zonecfg_is_rctl(const char * name)59270Sstevel@tonic-gate zonecfg_is_rctl(const char *name)
59280Sstevel@tonic-gate {
59290Sstevel@tonic-gate 	return (rctl_walk(rctl_check, (void *)name) == 1);
59300Sstevel@tonic-gate }
59310Sstevel@tonic-gate 
59320Sstevel@tonic-gate boolean_t
zonecfg_valid_rctlname(const char * name)59330Sstevel@tonic-gate zonecfg_valid_rctlname(const char *name)
59340Sstevel@tonic-gate {
59350Sstevel@tonic-gate 	const char *c;
59360Sstevel@tonic-gate 
59370Sstevel@tonic-gate 	if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0)
59380Sstevel@tonic-gate 		return (B_FALSE);
59390Sstevel@tonic-gate 	if (strlen(name) == sizeof ("zone.") - 1)
59400Sstevel@tonic-gate 		return (B_FALSE);
59410Sstevel@tonic-gate 	for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) {
59420Sstevel@tonic-gate 		if (!isalpha(*c) && *c != '-')
59430Sstevel@tonic-gate 			return (B_FALSE);
59440Sstevel@tonic-gate 	}
59450Sstevel@tonic-gate 	return (B_TRUE);
59460Sstevel@tonic-gate }
59470Sstevel@tonic-gate 
59480Sstevel@tonic-gate boolean_t
zonecfg_valid_rctlblk(const rctlblk_t * rctlblk)59490Sstevel@tonic-gate zonecfg_valid_rctlblk(const rctlblk_t *rctlblk)
59500Sstevel@tonic-gate {
59510Sstevel@tonic-gate 	rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk);
59520Sstevel@tonic-gate 	uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
59530Sstevel@tonic-gate 
59540Sstevel@tonic-gate 	if (priv != RCPRIV_PRIVILEGED)
59550Sstevel@tonic-gate 		return (B_FALSE);
59560Sstevel@tonic-gate 	if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY)
59570Sstevel@tonic-gate 		return (B_FALSE);
59580Sstevel@tonic-gate 	return (B_TRUE);
59590Sstevel@tonic-gate }
59600Sstevel@tonic-gate 
59610Sstevel@tonic-gate boolean_t
zonecfg_valid_rctl(const char * name,const rctlblk_t * rctlblk)59620Sstevel@tonic-gate zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk)
59630Sstevel@tonic-gate {
59640Sstevel@tonic-gate 	rctlblk_t *current, *next;
59650Sstevel@tonic-gate 	rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk);
59660Sstevel@tonic-gate 	uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
59670Sstevel@tonic-gate 	uint_t global_flags;
59680Sstevel@tonic-gate 
59690Sstevel@tonic-gate 	if (!zonecfg_valid_rctlblk(rctlblk))
59700Sstevel@tonic-gate 		return (B_FALSE);
59710Sstevel@tonic-gate 	if (!zonecfg_valid_rctlname(name))
59720Sstevel@tonic-gate 		return (B_FALSE);
59730Sstevel@tonic-gate 
59740Sstevel@tonic-gate 	current = alloca(rctlblk_size());
59750Sstevel@tonic-gate 	if (getrctl(name, NULL, current, RCTL_FIRST) != 0)
59760Sstevel@tonic-gate 		return (B_TRUE);	/* not an rctl on this system */
59770Sstevel@tonic-gate 	/*
59780Sstevel@tonic-gate 	 * Make sure the proposed value isn't greater than the current system
59790Sstevel@tonic-gate 	 * value.
59800Sstevel@tonic-gate 	 */
59810Sstevel@tonic-gate 	next = alloca(rctlblk_size());
59820Sstevel@tonic-gate 	while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) {
59830Sstevel@tonic-gate 		rctlblk_t *tmp;
59840Sstevel@tonic-gate 
59850Sstevel@tonic-gate 		if (getrctl(name, current, next, RCTL_NEXT) != 0)
59860Sstevel@tonic-gate 			return (B_FALSE);	/* shouldn't happen */
59870Sstevel@tonic-gate 		tmp = current;
59880Sstevel@tonic-gate 		current = next;
59890Sstevel@tonic-gate 		next = tmp;
59900Sstevel@tonic-gate 	}
59910Sstevel@tonic-gate 	if (limit > rctlblk_get_value(current))
59920Sstevel@tonic-gate 		return (B_FALSE);
59930Sstevel@tonic-gate 
59940Sstevel@tonic-gate 	/*
59950Sstevel@tonic-gate 	 * Make sure the proposed action is allowed.
59960Sstevel@tonic-gate 	 */
59970Sstevel@tonic-gate 	global_flags = rctlblk_get_global_flags(current);
59980Sstevel@tonic-gate 	if ((global_flags & RCTL_GLOBAL_DENY_NEVER) &&
59990Sstevel@tonic-gate 	    action == RCTL_LOCAL_DENY)
60000Sstevel@tonic-gate 		return (B_FALSE);
60010Sstevel@tonic-gate 	if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) &&
60020Sstevel@tonic-gate 	    action == RCTL_LOCAL_NOACTION)
60030Sstevel@tonic-gate 		return (B_FALSE);
60040Sstevel@tonic-gate 
60050Sstevel@tonic-gate 	return (B_TRUE);
60060Sstevel@tonic-gate }
6007789Sahrens 
60081166Sdstaff /*
60091166Sdstaff  * There is always a race condition between reading the initial copy of
60101166Sdstaff  * a zones state and its state changing.  We address this by providing
60111166Sdstaff  * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions.
60121166Sdstaff  * When zonecfg_critical_enter is called, sets the state field to LOCKED
60131166Sdstaff  * and aquires biglock. Biglock protects against other threads executing
60141166Sdstaff  * critical_enter and the state field protects against state changes during
60151166Sdstaff  * the critical period.
60161166Sdstaff  *
60171166Sdstaff  * If any state changes occur, zn_cb will set the failed field of the znotify
60181166Sdstaff  * structure.  This will cause the critical_exit function to re-lock the
60191166Sdstaff  * channel and return an error. Since evsnts may be delayed, the critical_exit
60201166Sdstaff  * function "flushes" the queue by putting an event on the queue and waiting for
60211166Sdstaff  * zn_cb to notify critical_exit that it received the ping event.
60221166Sdstaff  */
60231166Sdstaff static const char *
string_get_tok(const char * in,char delim,int num)60241166Sdstaff string_get_tok(const char *in, char delim, int num)
60251166Sdstaff {
60261166Sdstaff 	int i = 0;
60271166Sdstaff 
60281166Sdstaff 	for (; i < num; in++) {
60291166Sdstaff 		if (*in == delim)
60301166Sdstaff 			i++;
60311166Sdstaff 		if (*in == 0)
60321166Sdstaff 			return (NULL);
60331166Sdstaff 	}
60341166Sdstaff 	return (in);
60351166Sdstaff }
60361166Sdstaff 
60371166Sdstaff static boolean_t
is_ping(sysevent_t * ev)60381166Sdstaff is_ping(sysevent_t *ev)
60391166Sdstaff {
60401166Sdstaff 	if (strcmp(sysevent_get_subclass_name(ev),
60411645Scomay 	    ZONE_EVENT_PING_SUBCLASS) == 0) {
60421166Sdstaff 		return (B_TRUE);
60431166Sdstaff 	} else {
60441166Sdstaff 		return (B_FALSE);
60451166Sdstaff 	}
60461166Sdstaff }
60471166Sdstaff 
60481166Sdstaff static boolean_t
is_my_ping(sysevent_t * ev)60491166Sdstaff is_my_ping(sysevent_t *ev)
60501166Sdstaff {
60511166Sdstaff 	const char *sender;
60521166Sdstaff 	char mypid[sizeof (pid_t) * 3 + 1];
60531166Sdstaff 
60541166Sdstaff 	(void) snprintf(mypid, sizeof (mypid), "%i", getpid());
60551166Sdstaff 	sender = string_get_tok(sysevent_get_pub(ev), ':', 3);
60561166Sdstaff 	if (sender == NULL)
60571166Sdstaff 		return (B_FALSE);
60581166Sdstaff 	if (strcmp(sender, mypid) != 0)
60591166Sdstaff 		return (B_FALSE);
60601166Sdstaff 	return (B_TRUE);
60611166Sdstaff }
60621166Sdstaff 
60631166Sdstaff static int
do_callback(struct znotify * zevtchan,sysevent_t * ev)60641166Sdstaff do_callback(struct znotify *zevtchan, sysevent_t *ev)
60651166Sdstaff {
60661166Sdstaff 	nvlist_t *l;
60671166Sdstaff 	int zid;
60681166Sdstaff 	char *zonename;
60691166Sdstaff 	char *newstate;
60701166Sdstaff 	char *oldstate;
60711166Sdstaff 	int ret;
60721166Sdstaff 	hrtime_t when;
60731166Sdstaff 
60741166Sdstaff 	if (strcmp(sysevent_get_subclass_name(ev),
60751166Sdstaff 	    ZONE_EVENT_STATUS_SUBCLASS) == 0) {
60761166Sdstaff 
60771166Sdstaff 		if (sysevent_get_attr_list(ev, &l) != 0) {
60781166Sdstaff 			if (errno == ENOMEM) {
60791166Sdstaff 				zevtchan->zn_failure_count++;
60801166Sdstaff 				return (EAGAIN);
60811166Sdstaff 			}
60821166Sdstaff 			return (0);
60831166Sdstaff 		}
60841166Sdstaff 		ret = 0;
60851166Sdstaff 
60861166Sdstaff 		if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) &&
60871166Sdstaff 		    (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate)
60881645Scomay 		    == 0) &&
60891166Sdstaff 		    (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate)
60901645Scomay 		    == 0) &&
60911166Sdstaff 		    (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP,
60921645Scomay 		    (uint64_t *)&when) == 0) &&
60931166Sdstaff 		    (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) {
60941166Sdstaff 			ret = zevtchan->zn_callback(zonename, zid, newstate,
60951166Sdstaff 			    oldstate, when, zevtchan->zn_private);
60961166Sdstaff 		}
60971166Sdstaff 
60981166Sdstaff 		zevtchan->zn_failure_count = 0;
60991166Sdstaff 		nvlist_free(l);
61001166Sdstaff 		return (ret);
61011166Sdstaff 	} else {
61021166Sdstaff 		/*
61031166Sdstaff 		 * We have received an event in an unknown subclass. Ignore.
61041166Sdstaff 		 */
61051166Sdstaff 		zevtchan->zn_failure_count = 0;
61061166Sdstaff 		return (0);
61071166Sdstaff 	}
61081166Sdstaff }
61091166Sdstaff 
61101166Sdstaff static int
zn_cb(sysevent_t * ev,void * p)61111166Sdstaff zn_cb(sysevent_t *ev, void *p)
61121166Sdstaff {
61131166Sdstaff 	struct znotify *zevtchan = p;
61141166Sdstaff 	int error;
61151166Sdstaff 
61161166Sdstaff 	(void) pthread_mutex_lock(&(zevtchan->zn_mutex));
61171166Sdstaff 
61181166Sdstaff 	if (is_ping(ev) && !is_my_ping(ev)) {
61191166Sdstaff 		(void) pthread_mutex_unlock((&zevtchan->zn_mutex));
61201166Sdstaff 		return (0);
61211166Sdstaff 	}
61221166Sdstaff 
61231166Sdstaff 	if (zevtchan->zn_state == ZN_LOCKED) {
61241166Sdstaff 		assert(!is_ping(ev));
61251166Sdstaff 		zevtchan->zn_failed = B_TRUE;
61261166Sdstaff 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
61271166Sdstaff 		return (0);
61281166Sdstaff 	}
61291166Sdstaff 
61301166Sdstaff 	if (zevtchan->zn_state == ZN_PING_INFLIGHT) {
61311166Sdstaff 		if (is_ping(ev)) {
61321166Sdstaff 			zevtchan->zn_state = ZN_PING_RECEIVED;
61331166Sdstaff 			(void) pthread_cond_signal(&(zevtchan->zn_cond));
61341166Sdstaff 			(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
61351166Sdstaff 			return (0);
61361166Sdstaff 		} else {
61371166Sdstaff 			zevtchan->zn_failed = B_TRUE;
61381166Sdstaff 			(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
61391166Sdstaff 			return (0);
61401166Sdstaff 		}
61411166Sdstaff 	}
61421166Sdstaff 
61431166Sdstaff 	if (zevtchan->zn_state == ZN_UNLOCKED) {
61441166Sdstaff 
61451166Sdstaff 		error = do_callback(zevtchan, ev);
61461166Sdstaff 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
61471166Sdstaff 		/*
61481166Sdstaff 		 * Every ENOMEM failure causes do_callback to increment
61491166Sdstaff 		 * zn_failure_count and every success causes it to
61501166Sdstaff 		 * set zn_failure_count to zero.  If we got EAGAIN,
61511166Sdstaff 		 * we will sleep for zn_failure_count seconds and return
61521166Sdstaff 		 * EAGAIN to gpec to try again.
61531166Sdstaff 		 *
61541166Sdstaff 		 * After 55 seconds, or 10 try's we give up and drop the
61551166Sdstaff 		 * event.
61561166Sdstaff 		 */
61571166Sdstaff 		if (error == EAGAIN) {
61581166Sdstaff 			if (zevtchan->zn_failure_count > ZONE_CB_RETRY_COUNT) {
61591166Sdstaff 				return (0);
61601166Sdstaff 			}
61611166Sdstaff 			(void) sleep(zevtchan->zn_failure_count);
61621166Sdstaff 		}
61631166Sdstaff 		return (error);
61641166Sdstaff 	}
61651166Sdstaff 
61661166Sdstaff 	if (zevtchan->zn_state == ZN_PING_RECEIVED) {
61671166Sdstaff 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
61681166Sdstaff 		return (0);
61691166Sdstaff 	}
61701166Sdstaff 
61711166Sdstaff 	abort();
61721166Sdstaff 	return (0);
61731166Sdstaff }
61741166Sdstaff 
61751166Sdstaff void
zonecfg_notify_critical_enter(void * h)61761166Sdstaff zonecfg_notify_critical_enter(void *h)
61771166Sdstaff {
61781166Sdstaff 	struct znotify *zevtchan = h;
61791166Sdstaff 
61801166Sdstaff 	(void) pthread_mutex_lock(&(zevtchan->zn_bigmutex));
61811166Sdstaff 	zevtchan->zn_state = ZN_LOCKED;
61821166Sdstaff }
61831166Sdstaff 
61841166Sdstaff int
zonecfg_notify_critical_exit(void * h)61851166Sdstaff zonecfg_notify_critical_exit(void * h)
61861166Sdstaff {
61871166Sdstaff 
61881166Sdstaff 	struct znotify *zevtchan = h;
61891166Sdstaff 
61901166Sdstaff 	if (zevtchan->zn_state == ZN_UNLOCKED)
61911166Sdstaff 		return (0);
61921166Sdstaff 
61931166Sdstaff 	(void) pthread_mutex_lock(&(zevtchan->zn_mutex));
61941166Sdstaff 	zevtchan->zn_state = ZN_PING_INFLIGHT;
61951166Sdstaff 
61961507Sgjelinek 	(void) sysevent_evc_publish(zevtchan->zn_eventchan,
61971507Sgjelinek 	    ZONE_EVENT_STATUS_CLASS,
61981166Sdstaff 	    ZONE_EVENT_PING_SUBCLASS, ZONE_EVENT_PING_PUBLISHER,
61991166Sdstaff 	    zevtchan->zn_subscriber_id, NULL, EVCH_SLEEP);
62001166Sdstaff 
62011166Sdstaff 	while (zevtchan->zn_state != ZN_PING_RECEIVED) {
62021166Sdstaff 		(void) pthread_cond_wait(&(zevtchan->zn_cond),
62031166Sdstaff 		    &(zevtchan->zn_mutex));
62041166Sdstaff 	}
62051166Sdstaff 
62061166Sdstaff 	if (zevtchan->zn_failed == B_TRUE) {
62071166Sdstaff 		zevtchan->zn_state = ZN_LOCKED;
62081166Sdstaff 		zevtchan->zn_failed = B_FALSE;
62091166Sdstaff 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
62101166Sdstaff 		return (1);
62111166Sdstaff 	}
62121166Sdstaff 
62131166Sdstaff 	zevtchan->zn_state = ZN_UNLOCKED;
62141166Sdstaff 	(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
62151166Sdstaff 	(void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex));
62161166Sdstaff 	return (0);
62171166Sdstaff }
62181166Sdstaff 
62191166Sdstaff void
zonecfg_notify_critical_abort(void * h)62201166Sdstaff zonecfg_notify_critical_abort(void *h)
62211166Sdstaff {
62221166Sdstaff 	struct znotify *zevtchan = h;
62231166Sdstaff 
62241166Sdstaff 	zevtchan->zn_state = ZN_UNLOCKED;
62251166Sdstaff 	zevtchan->zn_failed = B_FALSE;
62261166Sdstaff 	/*
62271166Sdstaff 	 * Don't do anything about zn_lock. If it is held, it could only be
62281166Sdstaff 	 * held by zn_cb and it will be unlocked soon.
62291166Sdstaff 	 */
62301166Sdstaff 	(void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex));
62311166Sdstaff }
62321166Sdstaff 
62331166Sdstaff void *
zonecfg_notify_bind(int (* func)(const char * zonename,zoneid_t zid,const char * newstate,const char * oldstate,hrtime_t when,void * p),void * p)62341166Sdstaff zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid,
62351166Sdstaff     const char *newstate, const char *oldstate, hrtime_t when, void *p),
62361166Sdstaff     void *p)
62371166Sdstaff {
62381166Sdstaff 	struct znotify *zevtchan;
62391166Sdstaff 	int i = 1;
62401166Sdstaff 	int r;
62411166Sdstaff 
62421166Sdstaff 	zevtchan = malloc(sizeof (struct znotify));
62431166Sdstaff 
62441166Sdstaff 	if (zevtchan == NULL)
62451166Sdstaff 		return (NULL);
62461166Sdstaff 
62471166Sdstaff 	zevtchan->zn_private = p;
62481166Sdstaff 	zevtchan->zn_callback = func;
62491166Sdstaff 	zevtchan->zn_state = ZN_UNLOCKED;
62501166Sdstaff 	zevtchan->zn_failed = B_FALSE;
62511166Sdstaff 
62521166Sdstaff 	if (pthread_mutex_init(&(zevtchan->zn_mutex), NULL))
62531374Sdstaff 		goto out3;
62541166Sdstaff 	if (pthread_cond_init(&(zevtchan->zn_cond), NULL)) {
62551166Sdstaff 		(void) pthread_mutex_destroy(&(zevtchan->zn_mutex));
62561374Sdstaff 		goto out3;
62571166Sdstaff 	}
62581166Sdstaff 	if (pthread_mutex_init(&(zevtchan->zn_bigmutex), NULL)) {
62591166Sdstaff 		(void) pthread_mutex_destroy(&(zevtchan->zn_mutex));
62601166Sdstaff 		(void) pthread_cond_destroy(&(zevtchan->zn_cond));
62611374Sdstaff 		goto out3;
62621166Sdstaff 	}
62631166Sdstaff 
62641166Sdstaff 	if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &(zevtchan->zn_eventchan),
62651645Scomay 	    0) != 0)
62661166Sdstaff 		goto out2;
62671166Sdstaff 
62681166Sdstaff 	do {
62691166Sdstaff 		/*
62701166Sdstaff 		 * At 4 digits the subscriber ID gets too long and we have
62711166Sdstaff 		 * no chance of successfully registering.
62721166Sdstaff 		 */
62731166Sdstaff 		if (i > 999)
62741374Sdstaff 			goto out1;
62751166Sdstaff 
62761166Sdstaff 		(void) sprintf(zevtchan->zn_subscriber_id, "zone_%li_%i",
62771166Sdstaff 		    getpid() % 999999l, i);
62781166Sdstaff 
62791166Sdstaff 		r = sysevent_evc_subscribe(zevtchan->zn_eventchan,
62801166Sdstaff 		    zevtchan->zn_subscriber_id, ZONE_EVENT_STATUS_CLASS, zn_cb,
62811166Sdstaff 		    zevtchan, 0);
62821166Sdstaff 
62831166Sdstaff 		i++;
62841166Sdstaff 
62851166Sdstaff 	} while (r);
62861166Sdstaff 
62871166Sdstaff 	return (zevtchan);
62881374Sdstaff out1:
628911102SGavin.Maltby@Sun.COM 	(void) sysevent_evc_unbind(zevtchan->zn_eventchan);
62901374Sdstaff out2:
62911166Sdstaff 	(void) pthread_mutex_destroy(&zevtchan->zn_mutex);
62921166Sdstaff 	(void) pthread_cond_destroy(&zevtchan->zn_cond);
62931166Sdstaff 	(void) pthread_mutex_destroy(&(zevtchan->zn_bigmutex));
62941374Sdstaff out3:
62951166Sdstaff 	free(zevtchan);
62961166Sdstaff 
62971166Sdstaff 	return (NULL);
62981166Sdstaff }
62991166Sdstaff 
63001166Sdstaff void
zonecfg_notify_unbind(void * handle)63011166Sdstaff zonecfg_notify_unbind(void *handle)
63021166Sdstaff {
63031166Sdstaff 
63041166Sdstaff 	int ret;
63051166Sdstaff 
630611102SGavin.Maltby@Sun.COM 	(void) sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan);
63071166Sdstaff 	/*
63081166Sdstaff 	 * Check that all evc threads have gone away. This should be
63091166Sdstaff 	 * enforced by sysevent_evc_unbind.
63101166Sdstaff 	 */
63111166Sdstaff 	ret = pthread_mutex_trylock(&((struct znotify *)handle)->zn_mutex);
63121166Sdstaff 
63131166Sdstaff 	if (ret)
63141166Sdstaff 		abort();
63151166Sdstaff 
63161166Sdstaff 	(void) pthread_mutex_unlock(&((struct znotify *)handle)->zn_mutex);
63171166Sdstaff 	(void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_mutex);
63181166Sdstaff 	(void) pthread_cond_destroy(&((struct znotify *)handle)->zn_cond);
63191166Sdstaff 	(void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_bigmutex);
63201166Sdstaff 
63211166Sdstaff 	free(handle);
63221166Sdstaff }
63231166Sdstaff 
6324789Sahrens static int
zonecfg_add_ds_core(zone_dochandle_t handle,struct zone_dstab * tabptr)6325789Sahrens zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
6326789Sahrens {
6327789Sahrens 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
6328789Sahrens 	int err;
6329789Sahrens 
6330789Sahrens 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DATASET, NULL);
6331789Sahrens 	if ((err = newprop(newnode, DTD_ATTR_NAME,
6332789Sahrens 	    tabptr->zone_dataset_name)) != Z_OK)
6333789Sahrens 		return (err);
6334789Sahrens 	return (Z_OK);
6335789Sahrens }
6336789Sahrens 
6337789Sahrens int
zonecfg_add_ds(zone_dochandle_t handle,struct zone_dstab * tabptr)6338789Sahrens zonecfg_add_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
6339789Sahrens {
6340789Sahrens 	int err;
6341789Sahrens 
6342789Sahrens 	if (tabptr == NULL)
6343789Sahrens 		return (Z_INVAL);
6344789Sahrens 
6345789Sahrens 	if ((err = operation_prep(handle)) != Z_OK)
6346789Sahrens 		return (err);
6347789Sahrens 
6348789Sahrens 	if ((err = zonecfg_add_ds_core(handle, tabptr)) != Z_OK)
6349789Sahrens 		return (err);
6350789Sahrens 
6351789Sahrens 	return (Z_OK);
6352789Sahrens }
6353789Sahrens 
6354789Sahrens static int
zonecfg_delete_ds_core(zone_dochandle_t handle,struct zone_dstab * tabptr)6355789Sahrens zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
6356789Sahrens {
6357789Sahrens 	xmlNodePtr cur = handle->zone_dh_cur;
6358789Sahrens 
6359789Sahrens 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6360789Sahrens 		if (xmlStrcmp(cur->name, DTD_ELEM_DATASET))
6361789Sahrens 			continue;
6362789Sahrens 
6363789Sahrens 		if (match_prop(cur, DTD_ATTR_NAME,
6364789Sahrens 		    tabptr->zone_dataset_name)) {
6365789Sahrens 			xmlUnlinkNode(cur);
6366789Sahrens 			xmlFreeNode(cur);
6367789Sahrens 			return (Z_OK);
6368789Sahrens 		}
6369789Sahrens 	}
6370789Sahrens 	return (Z_NO_RESOURCE_ID);
6371789Sahrens }
6372789Sahrens 
6373789Sahrens int
zonecfg_delete_ds(zone_dochandle_t handle,struct zone_dstab * tabptr)6374789Sahrens zonecfg_delete_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
6375789Sahrens {
6376789Sahrens 	int err;
6377789Sahrens 
6378789Sahrens 	if (tabptr == NULL)
6379789Sahrens 		return (Z_INVAL);
6380789Sahrens 
6381789Sahrens 	if ((err = operation_prep(handle)) != Z_OK)
6382789Sahrens 		return (err);
6383789Sahrens 
6384789Sahrens 	if ((err = zonecfg_delete_ds_core(handle, tabptr)) != Z_OK)
6385789Sahrens 		return (err);
6386789Sahrens 
6387789Sahrens 	return (Z_OK);
6388789Sahrens }
6389789Sahrens 
6390789Sahrens int
zonecfg_modify_ds(zone_dochandle_t handle,struct zone_dstab * oldtabptr,struct zone_dstab * newtabptr)6391789Sahrens zonecfg_modify_ds(
6392789Sahrens 	zone_dochandle_t handle,
6393789Sahrens 	struct zone_dstab *oldtabptr,
6394789Sahrens 	struct zone_dstab *newtabptr)
6395789Sahrens {
6396789Sahrens 	int err;
6397789Sahrens 
6398789Sahrens 	if (oldtabptr == NULL || newtabptr == NULL)
6399789Sahrens 		return (Z_INVAL);
6400789Sahrens 
6401789Sahrens 	if ((err = operation_prep(handle)) != Z_OK)
6402789Sahrens 		return (err);
6403789Sahrens 
6404789Sahrens 	if ((err = zonecfg_delete_ds_core(handle, oldtabptr)) != Z_OK)
6405789Sahrens 		return (err);
6406789Sahrens 
6407789Sahrens 	if ((err = zonecfg_add_ds_core(handle, newtabptr)) != Z_OK)
6408789Sahrens 		return (err);
6409789Sahrens 
6410789Sahrens 	return (Z_OK);
6411789Sahrens }
6412789Sahrens 
6413789Sahrens int
zonecfg_lookup_ds(zone_dochandle_t handle,struct zone_dstab * tabptr)6414789Sahrens zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
6415789Sahrens {
6416789Sahrens 	xmlNodePtr cur, firstmatch;
6417789Sahrens 	int err;
6418789Sahrens 	char dataset[MAXNAMELEN];
6419789Sahrens 
6420789Sahrens 	if (tabptr == NULL)
6421789Sahrens 		return (Z_INVAL);
6422789Sahrens 
6423789Sahrens 	if ((err = operation_prep(handle)) != Z_OK)
6424789Sahrens 		return (err);
6425789Sahrens 
6426789Sahrens 	cur = handle->zone_dh_cur;
6427789Sahrens 	firstmatch = NULL;
6428789Sahrens 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6429789Sahrens 		if (xmlStrcmp(cur->name, DTD_ELEM_DATASET))
6430789Sahrens 			continue;
6431789Sahrens 		if (strlen(tabptr->zone_dataset_name) > 0) {
6432789Sahrens 			if ((fetchprop(cur, DTD_ATTR_NAME, dataset,
6433789Sahrens 			    sizeof (dataset)) == Z_OK) &&
6434789Sahrens 			    (strcmp(tabptr->zone_dataset_name,
6435789Sahrens 			    dataset) == 0)) {
6436789Sahrens 				if (firstmatch == NULL)
6437789Sahrens 					firstmatch = cur;
6438789Sahrens 				else
6439789Sahrens 					return (Z_INSUFFICIENT_SPEC);
6440789Sahrens 			}
6441789Sahrens 		}
6442789Sahrens 	}
6443789Sahrens 	if (firstmatch == NULL)
6444789Sahrens 		return (Z_NO_RESOURCE_ID);
6445789Sahrens 
6446789Sahrens 	cur = firstmatch;
6447789Sahrens 
6448789Sahrens 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
6449789Sahrens 	    sizeof (tabptr->zone_dataset_name))) != Z_OK)
6450789Sahrens 		return (err);
6451789Sahrens 
6452789Sahrens 	return (Z_OK);
6453789Sahrens }
6454789Sahrens 
6455789Sahrens int
zonecfg_setdsent(zone_dochandle_t handle)6456789Sahrens zonecfg_setdsent(zone_dochandle_t handle)
6457789Sahrens {
6458789Sahrens 	return (zonecfg_setent(handle));
6459789Sahrens }
6460789Sahrens 
6461789Sahrens int
zonecfg_getdsent(zone_dochandle_t handle,struct zone_dstab * tabptr)6462789Sahrens zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr)
6463789Sahrens {
6464789Sahrens 	xmlNodePtr cur;
6465789Sahrens 	int err;
6466789Sahrens 
6467789Sahrens 	if (handle == NULL)
6468789Sahrens 		return (Z_INVAL);
6469789Sahrens 
6470789Sahrens 	if ((cur = handle->zone_dh_cur) == NULL)
6471789Sahrens 		return (Z_NO_ENTRY);
6472789Sahrens 
6473789Sahrens 	for (; cur != NULL; cur = cur->next)
6474789Sahrens 		if (!xmlStrcmp(cur->name, DTD_ELEM_DATASET))
6475789Sahrens 			break;
6476789Sahrens 	if (cur == NULL) {
6477789Sahrens 		handle->zone_dh_cur = handle->zone_dh_top;
6478789Sahrens 		return (Z_NO_ENTRY);
6479789Sahrens 	}
6480789Sahrens 
6481789Sahrens 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
6482789Sahrens 	    sizeof (tabptr->zone_dataset_name))) != Z_OK) {
6483789Sahrens 		handle->zone_dh_cur = handle->zone_dh_top;
6484789Sahrens 		return (err);
6485789Sahrens 	}
6486789Sahrens 
6487789Sahrens 	handle->zone_dh_cur = cur->next;
6488789Sahrens 	return (Z_OK);
6489789Sahrens }
6490789Sahrens 
6491789Sahrens int
zonecfg_enddsent(zone_dochandle_t handle)6492789Sahrens zonecfg_enddsent(zone_dochandle_t handle)
6493789Sahrens {
6494789Sahrens 	return (zonecfg_endent(handle));
6495789Sahrens }
64961507Sgjelinek 
64973247Sgjelinek /*
64983247Sgjelinek  * Support for aliased rctls; that is, rctls that have simplified names in
64993247Sgjelinek  * zonecfg.  For example, max-lwps is an alias for a well defined zone.max-lwps
65003247Sgjelinek  * rctl.  If there are multiple existing values for one of these rctls or if
65013247Sgjelinek  * there is a single value that does not match the well defined template (i.e.
65023247Sgjelinek  * it has a different action) then we cannot treat the rctl as having an alias
65033247Sgjelinek  * so we return Z_ALIAS_DISALLOW.  That means that the rctl cannot be
65043247Sgjelinek  * managed in zonecfg via an alias and that the standard rctl syntax must be
65053247Sgjelinek  * used.
65063247Sgjelinek  *
65073247Sgjelinek  * The possible return values are:
65083247Sgjelinek  *	Z_NO_PROPERTY_ID - invalid alias name
65093247Sgjelinek  *	Z_ALIAS_DISALLOW - pre-existing, incompatible rctl definition
65103247Sgjelinek  *	Z_NO_ENTRY - no rctl is configured for this alias
65113247Sgjelinek  *	Z_OK - we got a valid rctl for the specified alias
65123247Sgjelinek  */
65133247Sgjelinek int
zonecfg_get_aliased_rctl(zone_dochandle_t handle,char * name,uint64_t * rval)65143247Sgjelinek zonecfg_get_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t *rval)
65153247Sgjelinek {
65163247Sgjelinek 	boolean_t found = B_FALSE;
65173247Sgjelinek 	boolean_t found_val = B_FALSE;
65183247Sgjelinek 	xmlNodePtr cur, val;
65193247Sgjelinek 	char savedname[MAXNAMELEN];
65203247Sgjelinek 	struct zone_rctlvaltab rctl;
65213247Sgjelinek 	int i;
65223247Sgjelinek 	int err;
65233247Sgjelinek 
65243247Sgjelinek 	for (i = 0; aliases[i].shortname != NULL; i++)
65253247Sgjelinek 		if (strcmp(name, aliases[i].shortname) == 0)
65263247Sgjelinek 			break;
65273247Sgjelinek 
65283247Sgjelinek 	if (aliases[i].shortname == NULL)
65293247Sgjelinek 		return (Z_NO_PROPERTY_ID);
65303247Sgjelinek 
65313247Sgjelinek 	if ((err = operation_prep(handle)) != Z_OK)
65323247Sgjelinek 		return (err);
65333247Sgjelinek 
65343247Sgjelinek 	cur = handle->zone_dh_cur;
65353247Sgjelinek 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
65363247Sgjelinek 		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL) != 0)
65373247Sgjelinek 			continue;
65383247Sgjelinek 		if ((fetchprop(cur, DTD_ATTR_NAME, savedname,
65393247Sgjelinek 		    sizeof (savedname)) == Z_OK) &&
65403247Sgjelinek 		    (strcmp(savedname, aliases[i].realname) == 0)) {
65413247Sgjelinek 
65423247Sgjelinek 			/*
65433247Sgjelinek 			 * If we already saw one of these, we can't have an
65443247Sgjelinek 			 * alias since we just found another.
65453247Sgjelinek 			 */
65463247Sgjelinek 			if (found)
65473247Sgjelinek 				return (Z_ALIAS_DISALLOW);
65483247Sgjelinek 			found = B_TRUE;
65493247Sgjelinek 
65503247Sgjelinek 			for (val = cur->xmlChildrenNode; val != NULL;
65513247Sgjelinek 			    val = val->next) {
65523247Sgjelinek 				/*
65533247Sgjelinek 				 * If we already have one value, we can't have
65543247Sgjelinek 				 * an alias since we just found another.
65553247Sgjelinek 				 */
65563247Sgjelinek 				if (found_val)
65573247Sgjelinek 					return (Z_ALIAS_DISALLOW);
65583247Sgjelinek 				found_val = B_TRUE;
65593247Sgjelinek 
65603247Sgjelinek 				if ((fetchprop(val, DTD_ATTR_PRIV,
65613247Sgjelinek 				    rctl.zone_rctlval_priv,
65623247Sgjelinek 				    sizeof (rctl.zone_rctlval_priv)) != Z_OK))
65633247Sgjelinek 					break;
65643247Sgjelinek 				if ((fetchprop(val, DTD_ATTR_LIMIT,
65653247Sgjelinek 				    rctl.zone_rctlval_limit,
65663247Sgjelinek 				    sizeof (rctl.zone_rctlval_limit)) != Z_OK))
65673247Sgjelinek 					break;
65683247Sgjelinek 				if ((fetchprop(val, DTD_ATTR_ACTION,
65693247Sgjelinek 				    rctl.zone_rctlval_action,
65703247Sgjelinek 				    sizeof (rctl.zone_rctlval_action)) != Z_OK))
65713247Sgjelinek 					break;
65723247Sgjelinek 			}
65733247Sgjelinek 
65743247Sgjelinek 			/* check priv and action match the expected vals */
65753247Sgjelinek 			if (strcmp(rctl.zone_rctlval_priv,
65763247Sgjelinek 			    aliases[i].priv) != 0 ||
65773247Sgjelinek 			    strcmp(rctl.zone_rctlval_action,
65783247Sgjelinek 			    aliases[i].action) != 0)
65793247Sgjelinek 				return (Z_ALIAS_DISALLOW);
65803247Sgjelinek 		}
65813247Sgjelinek 	}
65823247Sgjelinek 
65833247Sgjelinek 	if (found) {
65843247Sgjelinek 		*rval = strtoull(rctl.zone_rctlval_limit, NULL, 10);
65853247Sgjelinek 		return (Z_OK);
65863247Sgjelinek 	}
65873247Sgjelinek 
65883247Sgjelinek 	return (Z_NO_ENTRY);
65893247Sgjelinek }
65903247Sgjelinek 
65913247Sgjelinek int
zonecfg_rm_aliased_rctl(zone_dochandle_t handle,char * name)65923247Sgjelinek zonecfg_rm_aliased_rctl(zone_dochandle_t handle, char *name)
65933247Sgjelinek {
65943247Sgjelinek 	int i;
65953247Sgjelinek 	uint64_t val;
65963247Sgjelinek 	struct zone_rctltab rctltab;
65973247Sgjelinek 
65983247Sgjelinek 	/*
65993247Sgjelinek 	 * First check that we have a valid aliased rctl to remove.
66003247Sgjelinek 	 * This will catch an rctl entry with non-standard values or
66013247Sgjelinek 	 * multiple rctl values for this name.  We need to ignore those
66023247Sgjelinek 	 * rctl entries.
66033247Sgjelinek 	 */
66043247Sgjelinek 	if (zonecfg_get_aliased_rctl(handle, name, &val) != Z_OK)
66053247Sgjelinek 		return (Z_OK);
66063247Sgjelinek 
66073247Sgjelinek 	for (i = 0; aliases[i].shortname != NULL; i++)
66083247Sgjelinek 		if (strcmp(name, aliases[i].shortname) == 0)
66093247Sgjelinek 			break;
66103247Sgjelinek 
66113247Sgjelinek 	if (aliases[i].shortname == NULL)
66123247Sgjelinek 		return (Z_NO_RESOURCE_ID);
66133247Sgjelinek 
66143247Sgjelinek 	(void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname,
66153247Sgjelinek 	    sizeof (rctltab.zone_rctl_name));
66163247Sgjelinek 
66173247Sgjelinek 	return (zonecfg_delete_rctl(handle, &rctltab));
66183247Sgjelinek }
66193247Sgjelinek 
66203247Sgjelinek boolean_t
zonecfg_aliased_rctl_ok(zone_dochandle_t handle,char * name)66213247Sgjelinek zonecfg_aliased_rctl_ok(zone_dochandle_t handle, char *name)
66223247Sgjelinek {
66233247Sgjelinek 	uint64_t tmp_val;
66243247Sgjelinek 
66253247Sgjelinek 	switch (zonecfg_get_aliased_rctl(handle, name, &tmp_val)) {
66263247Sgjelinek 	case Z_OK:
66273247Sgjelinek 		/*FALLTHRU*/
66283247Sgjelinek 	case Z_NO_ENTRY:
66293247Sgjelinek 		return (B_TRUE);
66303247Sgjelinek 	default:
66313247Sgjelinek 		return (B_FALSE);
66323247Sgjelinek 	}
66333247Sgjelinek }
66343247Sgjelinek 
66353247Sgjelinek int
zonecfg_set_aliased_rctl(zone_dochandle_t handle,char * name,uint64_t val)66363247Sgjelinek zonecfg_set_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t val)
66373247Sgjelinek {
66383247Sgjelinek 	int i;
66393247Sgjelinek 	int err;
66403247Sgjelinek 	struct zone_rctltab rctltab;
66413247Sgjelinek 	struct zone_rctlvaltab *rctlvaltab;
66423247Sgjelinek 	char buf[128];
66433247Sgjelinek 
66443247Sgjelinek 	if (!zonecfg_aliased_rctl_ok(handle, name))
66453247Sgjelinek 		return (Z_ALIAS_DISALLOW);
66463247Sgjelinek 
66473247Sgjelinek 	for (i = 0; aliases[i].shortname != NULL; i++)
66483247Sgjelinek 		if (strcmp(name, aliases[i].shortname) == 0)
66493247Sgjelinek 			break;
66503247Sgjelinek 
66513247Sgjelinek 	if (aliases[i].shortname == NULL)
66523247Sgjelinek 		return (Z_NO_RESOURCE_ID);
66533247Sgjelinek 
66543247Sgjelinek 	/* remove any pre-existing definition for this rctl */
66553247Sgjelinek 	(void) zonecfg_rm_aliased_rctl(handle, name);
66563247Sgjelinek 
66573247Sgjelinek 	(void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname,
66583247Sgjelinek 	    sizeof (rctltab.zone_rctl_name));
66593247Sgjelinek 
66603247Sgjelinek 	rctltab.zone_rctl_valptr = NULL;
66613247Sgjelinek 
66623247Sgjelinek 	if ((rctlvaltab = calloc(1, sizeof (struct zone_rctlvaltab))) == NULL)
66633247Sgjelinek 		return (Z_NOMEM);
66643247Sgjelinek 
66653247Sgjelinek 	(void) snprintf(buf, sizeof (buf), "%llu", (long long)val);
66663247Sgjelinek 
66673247Sgjelinek 	(void) strlcpy(rctlvaltab->zone_rctlval_priv, aliases[i].priv,
66683247Sgjelinek 	    sizeof (rctlvaltab->zone_rctlval_priv));
66693247Sgjelinek 	(void) strlcpy(rctlvaltab->zone_rctlval_limit, buf,
66703247Sgjelinek 	    sizeof (rctlvaltab->zone_rctlval_limit));
66713247Sgjelinek 	(void) strlcpy(rctlvaltab->zone_rctlval_action, aliases[i].action,
66723247Sgjelinek 	    sizeof (rctlvaltab->zone_rctlval_action));
66733247Sgjelinek 
66743247Sgjelinek 	rctlvaltab->zone_rctlval_next = NULL;
66753247Sgjelinek 
66763247Sgjelinek 	if ((err = zonecfg_add_rctl_value(&rctltab, rctlvaltab)) != Z_OK)
66773247Sgjelinek 		return (err);
66783247Sgjelinek 
66793247Sgjelinek 	return (zonecfg_add_rctl(handle, &rctltab));
66803247Sgjelinek }
66813247Sgjelinek 
66823247Sgjelinek static int
delete_tmp_pool(zone_dochandle_t handle)66833247Sgjelinek delete_tmp_pool(zone_dochandle_t handle)
66843247Sgjelinek {
66853247Sgjelinek 	int err;
66863247Sgjelinek 	xmlNodePtr cur = handle->zone_dh_cur;
66873247Sgjelinek 
66883247Sgjelinek 	if ((err = operation_prep(handle)) != Z_OK)
66893247Sgjelinek 		return (err);
66903247Sgjelinek 
66913247Sgjelinek 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
66923247Sgjelinek 		if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) {
66933247Sgjelinek 			xmlUnlinkNode(cur);
66943247Sgjelinek 			xmlFreeNode(cur);
66953247Sgjelinek 			return (Z_OK);
66963247Sgjelinek 		}
66973247Sgjelinek 	}
66983247Sgjelinek 
66993247Sgjelinek 	return (Z_NO_RESOURCE_ID);
67003247Sgjelinek }
67013247Sgjelinek 
67023247Sgjelinek static int
modify_tmp_pool(zone_dochandle_t handle,char * pool_importance)67033247Sgjelinek modify_tmp_pool(zone_dochandle_t handle, char *pool_importance)
67043247Sgjelinek {
67053247Sgjelinek 	int err;
67063247Sgjelinek 	xmlNodePtr cur = handle->zone_dh_cur;
67073247Sgjelinek 	xmlNodePtr newnode;
67083247Sgjelinek 
67093247Sgjelinek 	err = delete_tmp_pool(handle);
67103247Sgjelinek 	if (err != Z_OK && err != Z_NO_RESOURCE_ID)
67113247Sgjelinek 		return (err);
67123247Sgjelinek 
67133247Sgjelinek 	if (*pool_importance != '\0') {
67143247Sgjelinek 		if ((err = operation_prep(handle)) != Z_OK)
67153247Sgjelinek 			return (err);
67163247Sgjelinek 
67173247Sgjelinek 		newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_TMPPOOL, NULL);
67183247Sgjelinek 		if ((err = newprop(newnode, DTD_ATTR_IMPORTANCE,
67193247Sgjelinek 		    pool_importance)) != Z_OK)
67203247Sgjelinek 			return (err);
67213247Sgjelinek 	}
67223247Sgjelinek 
67233247Sgjelinek 	return (Z_OK);
67243247Sgjelinek }
67253247Sgjelinek 
67263247Sgjelinek static int
add_pset_core(zone_dochandle_t handle,struct zone_psettab * tabptr)67273247Sgjelinek add_pset_core(zone_dochandle_t handle, struct zone_psettab *tabptr)
67283247Sgjelinek {
67293247Sgjelinek 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
67303247Sgjelinek 	int err;
67313247Sgjelinek 
67323247Sgjelinek 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PSET, NULL);
67333247Sgjelinek 	if ((err = newprop(newnode, DTD_ATTR_NCPU_MIN,
67343247Sgjelinek 	    tabptr->zone_ncpu_min)) != Z_OK)
67353247Sgjelinek 		return (err);
67363247Sgjelinek 	if ((err = newprop(newnode, DTD_ATTR_NCPU_MAX,
67373247Sgjelinek 	    tabptr->zone_ncpu_max)) != Z_OK)
67383247Sgjelinek 		return (err);
67393247Sgjelinek 
67403247Sgjelinek 	if ((err = modify_tmp_pool(handle, tabptr->zone_importance)) != Z_OK)
67413247Sgjelinek 		return (err);
67423247Sgjelinek 
67433247Sgjelinek 	return (Z_OK);
67443247Sgjelinek }
67453247Sgjelinek 
67463247Sgjelinek int
zonecfg_add_pset(zone_dochandle_t handle,struct zone_psettab * tabptr)67473247Sgjelinek zonecfg_add_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
67483247Sgjelinek {
67493247Sgjelinek 	int err;
67503247Sgjelinek 
67513247Sgjelinek 	if (tabptr == NULL)
67523247Sgjelinek 		return (Z_INVAL);
67533247Sgjelinek 
67543247Sgjelinek 	if ((err = operation_prep(handle)) != Z_OK)
67553247Sgjelinek 		return (err);
67563247Sgjelinek 
67573247Sgjelinek 	if ((err = add_pset_core(handle, tabptr)) != Z_OK)
67583247Sgjelinek 		return (err);
67593247Sgjelinek 
67603247Sgjelinek 	return (Z_OK);
67613247Sgjelinek }
67623247Sgjelinek 
67633247Sgjelinek int
zonecfg_delete_pset(zone_dochandle_t handle)67643247Sgjelinek zonecfg_delete_pset(zone_dochandle_t handle)
67653247Sgjelinek {
67663247Sgjelinek 	int err;
67673247Sgjelinek 	int res = Z_NO_RESOURCE_ID;
67683247Sgjelinek 	xmlNodePtr cur = handle->zone_dh_cur;
67693247Sgjelinek 
67703247Sgjelinek 	if ((err = operation_prep(handle)) != Z_OK)
67713247Sgjelinek 		return (err);
67723247Sgjelinek 
67733247Sgjelinek 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
67743247Sgjelinek 		if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) {
67753247Sgjelinek 			xmlUnlinkNode(cur);
67763247Sgjelinek 			xmlFreeNode(cur);
67773247Sgjelinek 			res = Z_OK;
67783247Sgjelinek 			break;
67793247Sgjelinek 		}
67803247Sgjelinek 	}
67813247Sgjelinek 
67823247Sgjelinek 	/*
67833247Sgjelinek 	 * Once we have msets, we should check that a mset
67843247Sgjelinek 	 * do not exist before we delete the tmp_pool data.
67853247Sgjelinek 	 */
67863247Sgjelinek 	err = delete_tmp_pool(handle);
67873247Sgjelinek 	if (err != Z_OK && err != Z_NO_RESOURCE_ID)
67883247Sgjelinek 		return (err);
67893247Sgjelinek 
67903247Sgjelinek 	return (res);
67913247Sgjelinek }
67923247Sgjelinek 
67933247Sgjelinek int
zonecfg_modify_pset(zone_dochandle_t handle,struct zone_psettab * tabptr)67943247Sgjelinek zonecfg_modify_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
67953247Sgjelinek {
67963247Sgjelinek 	int err;
67973247Sgjelinek 
67983247Sgjelinek 	if (tabptr == NULL)
67993247Sgjelinek 		return (Z_INVAL);
68003247Sgjelinek 
68013247Sgjelinek 	if ((err = zonecfg_delete_pset(handle)) != Z_OK)
68023247Sgjelinek 		return (err);
68033247Sgjelinek 
68043247Sgjelinek 	if ((err = add_pset_core(handle, tabptr)) != Z_OK)
68053247Sgjelinek 		return (err);
68063247Sgjelinek 
68073247Sgjelinek 	return (Z_OK);
68083247Sgjelinek }
68093247Sgjelinek 
68103247Sgjelinek int
zonecfg_lookup_pset(zone_dochandle_t handle,struct zone_psettab * tabptr)68113247Sgjelinek zonecfg_lookup_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
68123247Sgjelinek {
68133247Sgjelinek 	xmlNodePtr cur;
68143247Sgjelinek 	int err;
68153247Sgjelinek 	int res = Z_NO_ENTRY;
68163247Sgjelinek 
68173247Sgjelinek 	if (tabptr == NULL)
68183247Sgjelinek 		return (Z_INVAL);
68193247Sgjelinek 
68203247Sgjelinek 	if ((err = operation_prep(handle)) != Z_OK)
68213247Sgjelinek 		return (err);
68223247Sgjelinek 
68233247Sgjelinek 	/* this is an optional component */
68243247Sgjelinek 	tabptr->zone_importance[0] = '\0';
68253247Sgjelinek 
68263247Sgjelinek 	cur = handle->zone_dh_cur;
68273247Sgjelinek 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
68283247Sgjelinek 		if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) {
68293247Sgjelinek 			if ((err = fetchprop(cur, DTD_ATTR_NCPU_MIN,
68303247Sgjelinek 			    tabptr->zone_ncpu_min,
68313247Sgjelinek 			    sizeof (tabptr->zone_ncpu_min))) != Z_OK) {
68323247Sgjelinek 				handle->zone_dh_cur = handle->zone_dh_top;
68333247Sgjelinek 				return (err);
68343247Sgjelinek 			}
68353247Sgjelinek 
68363247Sgjelinek 			if ((err = fetchprop(cur, DTD_ATTR_NCPU_MAX,
68373247Sgjelinek 			    tabptr->zone_ncpu_max,
68383247Sgjelinek 			    sizeof (tabptr->zone_ncpu_max))) != Z_OK) {
68393247Sgjelinek 				handle->zone_dh_cur = handle->zone_dh_top;
68403247Sgjelinek 				return (err);
68413247Sgjelinek 			}
68423247Sgjelinek 
68433247Sgjelinek 			res = Z_OK;
68443247Sgjelinek 
68453247Sgjelinek 		} else if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) {
68463247Sgjelinek 			if ((err = fetchprop(cur, DTD_ATTR_IMPORTANCE,
68473247Sgjelinek 			    tabptr->zone_importance,
68483247Sgjelinek 			    sizeof (tabptr->zone_importance))) != Z_OK) {
68493247Sgjelinek 				handle->zone_dh_cur = handle->zone_dh_top;
68503247Sgjelinek 				return (err);
68513247Sgjelinek 			}
68523247Sgjelinek 		}
68533247Sgjelinek 	}
68543247Sgjelinek 
68553247Sgjelinek 	return (res);
68563247Sgjelinek }
68573247Sgjelinek 
68583247Sgjelinek int
zonecfg_getpsetent(zone_dochandle_t handle,struct zone_psettab * tabptr)68593247Sgjelinek zonecfg_getpsetent(zone_dochandle_t handle, struct zone_psettab *tabptr)
68603247Sgjelinek {
68613247Sgjelinek 	int err;
68623247Sgjelinek 
68633247Sgjelinek 	if ((err = zonecfg_setent(handle)) != Z_OK)
68643247Sgjelinek 		return (err);
68653247Sgjelinek 
68663247Sgjelinek 	err = zonecfg_lookup_pset(handle, tabptr);
68673247Sgjelinek 
68683247Sgjelinek 	(void) zonecfg_endent(handle);
68693247Sgjelinek 
68703247Sgjelinek 	return (err);
68713247Sgjelinek }
68723247Sgjelinek 
68733247Sgjelinek static int
add_mcap(zone_dochandle_t handle,struct zone_mcaptab * tabptr)68743247Sgjelinek add_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
68753247Sgjelinek {
68763247Sgjelinek 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
68773247Sgjelinek 	int err;
68783247Sgjelinek 
68793247Sgjelinek 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_MCAP, NULL);
68803247Sgjelinek 	if ((err = newprop(newnode, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap))
68813247Sgjelinek 	    != Z_OK)
68823247Sgjelinek 		return (err);
68833247Sgjelinek 
68843247Sgjelinek 	return (Z_OK);
68853247Sgjelinek }
68863247Sgjelinek 
68873247Sgjelinek int
zonecfg_delete_mcap(zone_dochandle_t handle)68883247Sgjelinek zonecfg_delete_mcap(zone_dochandle_t handle)
68893247Sgjelinek {
68903247Sgjelinek 	int err;
68913247Sgjelinek 	xmlNodePtr cur = handle->zone_dh_cur;
68923247Sgjelinek 
68933247Sgjelinek 	if ((err = operation_prep(handle)) != Z_OK)
68943247Sgjelinek 		return (err);
68953247Sgjelinek 
68963247Sgjelinek 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
68973247Sgjelinek 		if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
68983247Sgjelinek 			continue;
68993247Sgjelinek 
69003247Sgjelinek 		xmlUnlinkNode(cur);
69013247Sgjelinek 		xmlFreeNode(cur);
69023247Sgjelinek 		return (Z_OK);
69033247Sgjelinek 	}
69043247Sgjelinek 	return (Z_NO_RESOURCE_ID);
69053247Sgjelinek }
69063247Sgjelinek 
69073247Sgjelinek int
zonecfg_modify_mcap(zone_dochandle_t handle,struct zone_mcaptab * tabptr)69083247Sgjelinek zonecfg_modify_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
69093247Sgjelinek {
69103247Sgjelinek 	int err;
69113247Sgjelinek 
69123247Sgjelinek 	if (tabptr == NULL)
69133247Sgjelinek 		return (Z_INVAL);
69143247Sgjelinek 
69153247Sgjelinek 	err = zonecfg_delete_mcap(handle);
69163247Sgjelinek 	/* it is ok if there is no mcap entry */
69173247Sgjelinek 	if (err != Z_OK && err != Z_NO_RESOURCE_ID)
69183247Sgjelinek 		return (err);
69193247Sgjelinek 
69203247Sgjelinek 	if ((err = add_mcap(handle, tabptr)) != Z_OK)
69213247Sgjelinek 		return (err);
69223247Sgjelinek 
69233247Sgjelinek 	return (Z_OK);
69243247Sgjelinek }
69253247Sgjelinek 
69263247Sgjelinek int
zonecfg_lookup_mcap(zone_dochandle_t handle,struct zone_mcaptab * tabptr)69273247Sgjelinek zonecfg_lookup_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
69283247Sgjelinek {
69293247Sgjelinek 	xmlNodePtr cur;
69303247Sgjelinek 	int err;
69313247Sgjelinek 
69323247Sgjelinek 	if (tabptr == NULL)
69333247Sgjelinek 		return (Z_INVAL);
69343247Sgjelinek 
69353247Sgjelinek 	if ((err = operation_prep(handle)) != Z_OK)
69363247Sgjelinek 		return (err);
69373247Sgjelinek 
69383247Sgjelinek 	cur = handle->zone_dh_cur;
69393247Sgjelinek 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
69403247Sgjelinek 		if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
69413247Sgjelinek 			continue;
69423247Sgjelinek 		if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP,
69433247Sgjelinek 		    tabptr->zone_physmem_cap,
69443247Sgjelinek 		    sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
69453247Sgjelinek 			handle->zone_dh_cur = handle->zone_dh_top;
69463247Sgjelinek 			return (err);
69473247Sgjelinek 		}
69483247Sgjelinek 
69493247Sgjelinek 		return (Z_OK);
69503247Sgjelinek 	}
69513247Sgjelinek 
69523247Sgjelinek 	return (Z_NO_ENTRY);
69533247Sgjelinek }
69543247Sgjelinek 
69553247Sgjelinek static int
getmcapent_core(zone_dochandle_t handle,struct zone_mcaptab * tabptr)69563247Sgjelinek getmcapent_core(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
69573247Sgjelinek {
69583247Sgjelinek 	xmlNodePtr cur;
69593247Sgjelinek 	int err;
69603247Sgjelinek 
69613247Sgjelinek 	if (handle == NULL)
69623247Sgjelinek 		return (Z_INVAL);
69633247Sgjelinek 
69643247Sgjelinek 	if ((cur = handle->zone_dh_cur) == NULL)
69653247Sgjelinek 		return (Z_NO_ENTRY);
69663247Sgjelinek 
69673247Sgjelinek 	for (; cur != NULL; cur = cur->next)
69683247Sgjelinek 		if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) == 0)
69693247Sgjelinek 			break;
69703247Sgjelinek 	if (cur == NULL) {
69713247Sgjelinek 		handle->zone_dh_cur = handle->zone_dh_top;
69723247Sgjelinek 		return (Z_NO_ENTRY);
69733247Sgjelinek 	}
69743247Sgjelinek 
69753247Sgjelinek 	if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap,
69763247Sgjelinek 	    sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
69773247Sgjelinek 		handle->zone_dh_cur = handle->zone_dh_top;
69783247Sgjelinek 		return (err);
69793247Sgjelinek 	}
69803247Sgjelinek 
69813247Sgjelinek 	handle->zone_dh_cur = cur->next;
69823247Sgjelinek 	return (Z_OK);
69833247Sgjelinek }
69843247Sgjelinek 
69853247Sgjelinek int
zonecfg_getmcapent(zone_dochandle_t handle,struct zone_mcaptab * tabptr)69863247Sgjelinek zonecfg_getmcapent(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
69873247Sgjelinek {
69883247Sgjelinek 	int err;
69893247Sgjelinek 
69903247Sgjelinek 	if ((err = zonecfg_setent(handle)) != Z_OK)
69913247Sgjelinek 		return (err);
69923247Sgjelinek 
69933247Sgjelinek 	err = getmcapent_core(handle, tabptr);
69943247Sgjelinek 
69953247Sgjelinek 	(void) zonecfg_endent(handle);
69963247Sgjelinek 
69973247Sgjelinek 	return (err);
69983247Sgjelinek }
69993247Sgjelinek 
70005829Sgjelinek /*
70015829Sgjelinek  * Get the full tree of pkg/patch metadata in a set of nested AVL trees.
70025829Sgjelinek  * pkgs_avl is an AVL tree of pkgs.  Each pkg element contains a
70035829Sgjelinek  * zpe_patches_avl member which holds an AVL tree of patches for that pkg.
70045829Sgjelinek  * The patch elements have the same zpe_patches_avl member, each of which can
70055829Sgjelinek  * hold an AVL tree of patches that are obsoleted by the patch.
70065829Sgjelinek  *
70075829Sgjelinek  * The zone xml data contains DTD_ELEM_PACKAGE elements, followed by
70085829Sgjelinek  * DTD_ELEM_PATCH elements.  The DTD_ELEM_PATCH patch element applies to the
70095829Sgjelinek  * DTD_ELEM_PACKAGE that precedes it.  The DTD_ELEM_PATCH element may have
70105829Sgjelinek  * child DTD_ELEM_OBSOLETES nodes associated with it.  The DTD_ELEM_PACKAGE
70115829Sgjelinek  * really should have had the DTD_ELEM_PATCH elements as children but it
70125829Sgjelinek  * was not defined that way initially so we are stuck with the DTD definition
70135829Sgjelinek  * now.  However, we can safely assume the ordering for compatibility.
70145829Sgjelinek  */
70155829Sgjelinek int
zonecfg_getpkgdata(zone_dochandle_t handle,uu_avl_pool_t * pkg_pool,uu_avl_t * pkgs_avl)70165829Sgjelinek zonecfg_getpkgdata(zone_dochandle_t handle, uu_avl_pool_t *pkg_pool,
70175829Sgjelinek     uu_avl_t *pkgs_avl)
70181507Sgjelinek {
70191507Sgjelinek 	xmlNodePtr cur;
70205829Sgjelinek 	int res;
70215829Sgjelinek 	zone_pkg_entry_t *pkg;
70225829Sgjelinek 	char name[MAXNAMELEN];
70235829Sgjelinek 	char version[ZONE_PKG_VERSMAX];
70241507Sgjelinek 
70251507Sgjelinek 	if (handle == NULL)
70261507Sgjelinek 		return (Z_INVAL);
70271507Sgjelinek 
70285829Sgjelinek 	if ((res = zonecfg_setent(handle)) != Z_OK)
70295829Sgjelinek 		return (res);
70305829Sgjelinek 
70315829Sgjelinek 	if ((cur = handle->zone_dh_cur) == NULL) {
70325829Sgjelinek 		res = Z_NO_ENTRY;
70335829Sgjelinek 		goto done;
70345829Sgjelinek 	}
70355829Sgjelinek 
70365829Sgjelinek 	for (; cur != NULL; cur = cur->next) {
70375829Sgjelinek 		if (xmlStrcmp(cur->name, DTD_ELEM_PACKAGE) == 0) {
70385829Sgjelinek 			uu_avl_index_t where;
70395829Sgjelinek 
70405829Sgjelinek 			if ((res = fetchprop(cur, DTD_ATTR_NAME, name,
70415829Sgjelinek 			    sizeof (name))) != Z_OK)
70425829Sgjelinek 				goto done;
70435829Sgjelinek 
70445829Sgjelinek 			if ((res = fetchprop(cur, DTD_ATTR_VERSION, version,
70455829Sgjelinek 			    sizeof (version))) != Z_OK)
70465829Sgjelinek 				goto done;
70475829Sgjelinek 
70485829Sgjelinek 			if ((pkg = (zone_pkg_entry_t *)
70495829Sgjelinek 			    malloc(sizeof (zone_pkg_entry_t))) == NULL) {
70505829Sgjelinek 				res = Z_NOMEM;
70515829Sgjelinek 				goto done;
70525829Sgjelinek 			}
70535829Sgjelinek 
70545829Sgjelinek 			if ((pkg->zpe_name = strdup(name)) == NULL) {
70555829Sgjelinek 				free(pkg);
70565829Sgjelinek 				res = Z_NOMEM;
70575829Sgjelinek 				goto done;
70585829Sgjelinek 			}
70595829Sgjelinek 
70605829Sgjelinek 			if ((pkg->zpe_vers = strdup(version)) == NULL) {
70615829Sgjelinek 				free(pkg->zpe_name);
70625829Sgjelinek 				free(pkg);
70635829Sgjelinek 				res = Z_NOMEM;
70645829Sgjelinek 				goto done;
70655829Sgjelinek 			}
70665829Sgjelinek 
70675829Sgjelinek 			pkg->zpe_patches_avl = NULL;
70685829Sgjelinek 
70695829Sgjelinek 			uu_avl_node_init(pkg, &pkg->zpe_entry, pkg_pool);
70705829Sgjelinek 			if (uu_avl_find(pkgs_avl, pkg, NULL, &where) != NULL) {
70715829Sgjelinek 				free(pkg->zpe_name);
70725829Sgjelinek 				free(pkg->zpe_vers);
70735829Sgjelinek 				free(pkg);
70745829Sgjelinek 			} else {
70755829Sgjelinek 				uu_avl_insert(pkgs_avl, pkg, where);
70765829Sgjelinek 			}
70775829Sgjelinek 
70785829Sgjelinek 		} else if (xmlStrcmp(cur->name, DTD_ELEM_PATCH) == 0) {
70795829Sgjelinek 			zone_pkg_entry_t *patch;
70805829Sgjelinek 			uu_avl_index_t where;
70815829Sgjelinek 			char *p;
70825829Sgjelinek 			char *dashp = NULL;
70835829Sgjelinek 			xmlNodePtr child;
70845829Sgjelinek 
70855829Sgjelinek 			if ((res = fetchprop(cur, DTD_ATTR_ID, name,
70865829Sgjelinek 			    sizeof (name))) != Z_OK)
70875829Sgjelinek 				goto done;
70885829Sgjelinek 
70895829Sgjelinek 			if ((patch = (zone_pkg_entry_t *)
70905829Sgjelinek 			    malloc(sizeof (zone_pkg_entry_t))) == NULL) {
70915829Sgjelinek 				res = Z_NOMEM;
70925829Sgjelinek 				goto done;
70935829Sgjelinek 			}
70945829Sgjelinek 
70955829Sgjelinek 			if ((p = strchr(name, '-')) != NULL) {
70965829Sgjelinek 				dashp = p;
70975829Sgjelinek 				*p++ = '\0';
70985829Sgjelinek 			} else {
70995829Sgjelinek 				p = "";
71005829Sgjelinek 			}
71015829Sgjelinek 
71025829Sgjelinek 			if ((patch->zpe_name = strdup(name)) == NULL) {
71035829Sgjelinek 				free(patch);
71045829Sgjelinek 				res = Z_NOMEM;
71055829Sgjelinek 				goto done;
71065829Sgjelinek 			}
71075829Sgjelinek 
71085829Sgjelinek 			if ((patch->zpe_vers = strdup(p)) == NULL) {
71095829Sgjelinek 				free(patch->zpe_name);
71105829Sgjelinek 				free(patch);
71115829Sgjelinek 				res = Z_NOMEM;
71125829Sgjelinek 				goto done;
71135829Sgjelinek 			}
71145829Sgjelinek 
71155829Sgjelinek 			if (dashp != NULL)
71165829Sgjelinek 				*dashp = '-';
71175829Sgjelinek 
71185829Sgjelinek 			patch->zpe_patches_avl = NULL;
71195829Sgjelinek 
71205829Sgjelinek 			if (pkg->zpe_patches_avl == NULL) {
71215829Sgjelinek 				pkg->zpe_patches_avl = uu_avl_create(pkg_pool,
71225829Sgjelinek 				    NULL, UU_DEFAULT);
71235829Sgjelinek 				if (pkg->zpe_patches_avl == NULL) {
71245829Sgjelinek 					free(patch->zpe_name);
71255829Sgjelinek 					free(patch->zpe_vers);
71265829Sgjelinek 					free(patch);
71275829Sgjelinek 					res = Z_NOMEM;
71285829Sgjelinek 					goto done;
71295829Sgjelinek 				}
71305829Sgjelinek 			}
71315829Sgjelinek 
71325829Sgjelinek 			uu_avl_node_init(patch, &patch->zpe_entry, pkg_pool);
71335829Sgjelinek 			if (uu_avl_find(pkg->zpe_patches_avl, patch, NULL,
71345829Sgjelinek 			    &where) != NULL) {
71355829Sgjelinek 				free(patch->zpe_name);
71365829Sgjelinek 				free(patch->zpe_vers);
71375829Sgjelinek 				free(patch);
71385829Sgjelinek 			} else {
71395829Sgjelinek 				uu_avl_insert(pkg->zpe_patches_avl, patch,
71405829Sgjelinek 				    where);
71415829Sgjelinek 			}
71425829Sgjelinek 
71435829Sgjelinek 			/* Add any patches this patch obsoletes. */
71445829Sgjelinek 			for (child = cur->xmlChildrenNode; child != NULL;
71455829Sgjelinek 			    child = child->next) {
71465829Sgjelinek 				zone_pkg_entry_t *obs;
71475829Sgjelinek 
71485829Sgjelinek 				if (xmlStrcmp(child->name, DTD_ELEM_OBSOLETES)
71495829Sgjelinek 				    != 0)
71505829Sgjelinek 					continue;
71515829Sgjelinek 
71525829Sgjelinek 				if ((res = fetchprop(child, DTD_ATTR_ID,
71535829Sgjelinek 				    name, sizeof (name))) != Z_OK)
71545829Sgjelinek 					goto done;
71555829Sgjelinek 
71565829Sgjelinek 				if ((obs = (zone_pkg_entry_t *)malloc(
71575829Sgjelinek 				    sizeof (zone_pkg_entry_t))) == NULL) {
71585829Sgjelinek 					res = Z_NOMEM;
71595829Sgjelinek 					goto done;
71605829Sgjelinek 				}
71615829Sgjelinek 
71625829Sgjelinek 				if ((obs->zpe_name = strdup(name)) == NULL) {
71635829Sgjelinek 					free(obs);
71645829Sgjelinek 					res = Z_NOMEM;
71655829Sgjelinek 					goto done;
71665829Sgjelinek 				}
71675829Sgjelinek 				/*
71685829Sgjelinek 				 * The version doesn't matter for obsoleted
71695829Sgjelinek 				 * patches.
71705829Sgjelinek 				 */
71715829Sgjelinek 				obs->zpe_vers = NULL;
71725829Sgjelinek 				obs->zpe_patches_avl = NULL;
71735829Sgjelinek 
71745829Sgjelinek 				/*
71755829Sgjelinek 				 * If this is the first obsolete patch, add an
71765829Sgjelinek 				 * AVL tree to the parent patch element.
71775829Sgjelinek 				 */
71785829Sgjelinek 				if (patch->zpe_patches_avl == NULL) {
71795829Sgjelinek 					patch->zpe_patches_avl =
71805829Sgjelinek 					    uu_avl_create(pkg_pool, NULL,
71815829Sgjelinek 					    UU_DEFAULT);
71825829Sgjelinek 					if (patch->zpe_patches_avl == NULL) {
71835829Sgjelinek 						free(obs->zpe_name);
71845829Sgjelinek 						free(obs);
71855829Sgjelinek 						res = Z_NOMEM;
71865829Sgjelinek 						goto done;
71875829Sgjelinek 					}
71885829Sgjelinek 				}
71895829Sgjelinek 
71905829Sgjelinek 				/* Insert obsolete patch into the AVL tree. */
71915829Sgjelinek 				uu_avl_node_init(obs, &obs->zpe_entry,
71925829Sgjelinek 				    pkg_pool);
71935829Sgjelinek 				if (uu_avl_find(patch->zpe_patches_avl, obs,
71945829Sgjelinek 				    NULL, &where) != NULL) {
71955829Sgjelinek 					free(obs->zpe_name);
71965829Sgjelinek 					free(obs);
71975829Sgjelinek 				} else {
71985829Sgjelinek 					uu_avl_insert(patch->zpe_patches_avl,
71995829Sgjelinek 					    obs, where);
72005829Sgjelinek 				}
72015829Sgjelinek 			}
72025829Sgjelinek 		}
72035829Sgjelinek 	}
72045829Sgjelinek 
72055829Sgjelinek done:
72065829Sgjelinek 	(void) zonecfg_endent(handle);
72075829Sgjelinek 	return (res);
72081507Sgjelinek }
72091507Sgjelinek 
72101507Sgjelinek int
zonecfg_setdevperment(zone_dochandle_t handle)72111507Sgjelinek zonecfg_setdevperment(zone_dochandle_t handle)
72121507Sgjelinek {
72131507Sgjelinek 	return (zonecfg_setent(handle));
72141507Sgjelinek }
72151507Sgjelinek 
72161507Sgjelinek int
zonecfg_getdevperment(zone_dochandle_t handle,struct zone_devpermtab * tabptr)72171507Sgjelinek zonecfg_getdevperment(zone_dochandle_t handle, struct zone_devpermtab *tabptr)
72181507Sgjelinek {
72191507Sgjelinek 	xmlNodePtr cur;
72201507Sgjelinek 	int err;
72211507Sgjelinek 	char buf[128];
72221507Sgjelinek 
72231507Sgjelinek 	tabptr->zone_devperm_acl = NULL;
72241507Sgjelinek 
72251507Sgjelinek 	if (handle == NULL)
72261507Sgjelinek 		return (Z_INVAL);
72271507Sgjelinek 
72281507Sgjelinek 	if ((cur = handle->zone_dh_cur) == NULL)
72291507Sgjelinek 		return (Z_NO_ENTRY);
72301507Sgjelinek 
72311507Sgjelinek 	for (; cur != NULL; cur = cur->next)
72321507Sgjelinek 		if (!xmlStrcmp(cur->name, DTD_ELEM_DEV_PERM))
72331507Sgjelinek 			break;
72341507Sgjelinek 	if (cur == NULL) {
72351507Sgjelinek 		handle->zone_dh_cur = handle->zone_dh_top;
72361507Sgjelinek 		return (Z_NO_ENTRY);
72371507Sgjelinek 	}
72381507Sgjelinek 
72391507Sgjelinek 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_devperm_name,
72401507Sgjelinek 	    sizeof (tabptr->zone_devperm_name))) != Z_OK) {
72411507Sgjelinek 		handle->zone_dh_cur = handle->zone_dh_top;
72421507Sgjelinek 		return (err);
72431507Sgjelinek 	}
72441507Sgjelinek 
72451507Sgjelinek 	if ((err = fetchprop(cur, DTD_ATTR_UID, buf, sizeof (buf))) != Z_OK) {
72461507Sgjelinek 		handle->zone_dh_cur = handle->zone_dh_top;
72471507Sgjelinek 		return (err);
72481507Sgjelinek 	}
72491507Sgjelinek 	tabptr->zone_devperm_uid = (uid_t)atol(buf);
72501507Sgjelinek 
72511507Sgjelinek 	if ((err = fetchprop(cur, DTD_ATTR_GID, buf, sizeof (buf))) != Z_OK) {
72521507Sgjelinek 		handle->zone_dh_cur = handle->zone_dh_top;
72531507Sgjelinek 		return (err);
72541507Sgjelinek 	}
72551507Sgjelinek 	tabptr->zone_devperm_gid = (gid_t)atol(buf);
72561507Sgjelinek 
72571507Sgjelinek 	if ((err = fetchprop(cur, DTD_ATTR_MODE, buf, sizeof (buf))) != Z_OK) {
72581507Sgjelinek 		handle->zone_dh_cur = handle->zone_dh_top;
72591507Sgjelinek 		return (err);
72601507Sgjelinek 	}
72611507Sgjelinek 	tabptr->zone_devperm_mode = (mode_t)strtol(buf, (char **)NULL, 8);
72621507Sgjelinek 
72631507Sgjelinek 	if ((err = fetch_alloc_prop(cur, DTD_ATTR_ACL,
72641507Sgjelinek 	    &(tabptr->zone_devperm_acl))) != Z_OK) {
72651507Sgjelinek 		handle->zone_dh_cur = handle->zone_dh_top;
72661507Sgjelinek 		return (err);
72671507Sgjelinek 	}
72681507Sgjelinek 
72691507Sgjelinek 	handle->zone_dh_cur = cur->next;
72701507Sgjelinek 	return (Z_OK);
72711507Sgjelinek }
72721507Sgjelinek 
72731507Sgjelinek int
zonecfg_enddevperment(zone_dochandle_t handle)72741507Sgjelinek zonecfg_enddevperment(zone_dochandle_t handle)
72751507Sgjelinek {
72761507Sgjelinek 	return (zonecfg_endent(handle));
72771507Sgjelinek }
72781507Sgjelinek 
72797089Sgjelinek /* PRINTFLIKE1 */
72807089Sgjelinek static void
zerror(const char * zone_name,const char * fmt,...)72817089Sgjelinek zerror(const char *zone_name, const char *fmt, ...)
72827089Sgjelinek {
72837089Sgjelinek 	va_list alist;
72847089Sgjelinek 
72857089Sgjelinek 	va_start(alist, fmt);
72867089Sgjelinek 	(void) fprintf(stderr, "zone '%s': ", zone_name);
72877089Sgjelinek 	(void) vfprintf(stderr, fmt, alist);
72887089Sgjelinek 	(void) fprintf(stderr, "\n");
72897089Sgjelinek 	va_end(alist);
72901507Sgjelinek }
72911507Sgjelinek 
72921507Sgjelinek static void
zperror(const char * str)72937089Sgjelinek zperror(const char *str)
72947089Sgjelinek {
72957089Sgjelinek 	(void) fprintf(stderr, "%s: %s\n", str, strerror(errno));
72961507Sgjelinek }
72971507Sgjelinek 
72981507Sgjelinek /*
72997089Sgjelinek  * The following three routines implement a simple locking mechanism to
73007089Sgjelinek  * ensure that only one instance of zoneadm at a time is able to manipulate
73017089Sgjelinek  * a given zone.  The lock is built on top of an fcntl(2) lock of
73027089Sgjelinek  * [<altroot>]/var/run/zones/<zonename>.zoneadm.lock.  If a zoneadm instance
73037089Sgjelinek  * can grab that lock, it is allowed to manipulate the zone.
73047089Sgjelinek  *
73057089Sgjelinek  * Since zoneadm may call external applications which in turn invoke
73067089Sgjelinek  * zoneadm again, we introduce the notion of "lock inheritance".  Any
73077089Sgjelinek  * instance of zoneadm that has another instance in its ancestry is assumed
73087089Sgjelinek  * to be acting on behalf of the original zoneadm, and is thus allowed to
73097089Sgjelinek  * manipulate its zone.
73107089Sgjelinek  *
73117089Sgjelinek  * This inheritance is implemented via the _ZONEADM_LOCK_HELD environment
73127089Sgjelinek  * variable.  When zoneadm is granted a lock on its zone, this environment
73137089Sgjelinek  * variable is set to 1.  When it releases the lock, the variable is set to
73147089Sgjelinek  * 0.  Since a child process inherits its parent's environment, checking
73157089Sgjelinek  * the state of this variable indicates whether or not any ancestor owns
73167089Sgjelinek  * the lock.
73171507Sgjelinek  */
73187089Sgjelinek void
zonecfg_init_lock_file(const char * zone_name,char ** lock_env)73197089Sgjelinek zonecfg_init_lock_file(const char *zone_name, char **lock_env)
73207089Sgjelinek {
73217089Sgjelinek 	*lock_env = getenv(LOCK_ENV_VAR);
73227089Sgjelinek 	if (*lock_env == NULL) {
73237089Sgjelinek 		if (putenv(zoneadm_lock_not_held) != 0) {
73247089Sgjelinek 			zerror(zone_name, gettext("could not set env: %s"),
73257089Sgjelinek 			    strerror(errno));
73267089Sgjelinek 			exit(1);
73271507Sgjelinek 		}
73281507Sgjelinek 	} else {
73297089Sgjelinek 		if (atoi(*lock_env) == 1)
73307089Sgjelinek 			zone_lock_cnt = 1;
73317089Sgjelinek 	}
73327089Sgjelinek }
73337089Sgjelinek 
73347089Sgjelinek void
zonecfg_release_lock_file(const char * zone_name,int lockfd)73357089Sgjelinek zonecfg_release_lock_file(const char *zone_name, int lockfd)
73367089Sgjelinek {
73377089Sgjelinek 	/*
73387089Sgjelinek 	 * If we are cleaning up from a failed attempt to lock the zone for
73397089Sgjelinek 	 * the first time, we might have a zone_lock_cnt of 0.  In that
73407089Sgjelinek 	 * error case, we don't want to do anything but close the lock
73417089Sgjelinek 	 * file.
73427089Sgjelinek 	 */
73437089Sgjelinek 	assert(zone_lock_cnt >= 0);
73447089Sgjelinek 	if (zone_lock_cnt > 0) {
73457089Sgjelinek 		assert(getenv(LOCK_ENV_VAR) != NULL);
73467089Sgjelinek 		assert(atoi(getenv(LOCK_ENV_VAR)) == 1);
73477089Sgjelinek 		if (--zone_lock_cnt > 0) {
73487089Sgjelinek 			assert(lockfd == -1);
73497089Sgjelinek 			return;
73507089Sgjelinek 		}
73517089Sgjelinek 		if (putenv(zoneadm_lock_not_held) != 0) {
73527089Sgjelinek 			zerror(zone_name, gettext("could not set env: %s"),
73537089Sgjelinek 			    strerror(errno));
73547089Sgjelinek 			exit(1);
73557089Sgjelinek 		}
73567089Sgjelinek 	}
73577089Sgjelinek 	assert(lockfd >= 0);
73587089Sgjelinek 	(void) close(lockfd);
73597089Sgjelinek }
73607089Sgjelinek 
73617089Sgjelinek int
zonecfg_grab_lock_file(const char * zone_name,int * lockfd)73627089Sgjelinek zonecfg_grab_lock_file(const char *zone_name, int *lockfd)
73637089Sgjelinek {
73647089Sgjelinek 	char pathbuf[PATH_MAX];
73657089Sgjelinek 	struct flock flock;
73664229Sgjelinek 
73676831Sgjelinek 	/*
73687089Sgjelinek 	 * If we already have the lock, we can skip this expensive song
73697089Sgjelinek 	 * and dance.
73707089Sgjelinek 	 */
73717089Sgjelinek 	assert(zone_lock_cnt >= 0);
73727089Sgjelinek 	assert(getenv(LOCK_ENV_VAR) != NULL);
73737089Sgjelinek 	if (zone_lock_cnt > 0) {
73747089Sgjelinek 		assert(atoi(getenv(LOCK_ENV_VAR)) == 1);
73757089Sgjelinek 		zone_lock_cnt++;
73767089Sgjelinek 		*lockfd = -1;
73777089Sgjelinek 		return (Z_OK);
73787089Sgjelinek 	}
73797089Sgjelinek 	assert(getenv(LOCK_ENV_VAR) != NULL);
73807089Sgjelinek 	assert(atoi(getenv(LOCK_ENV_VAR)) == 0);
73817089Sgjelinek 
73827089Sgjelinek 	if (snprintf(pathbuf, sizeof (pathbuf), "%s%s", zonecfg_get_root(),
73837089Sgjelinek 	    ZONES_TMPDIR) >= sizeof (pathbuf)) {
73847089Sgjelinek 		zerror(zone_name, gettext("alternate root path is too long"));
73857089Sgjelinek 		return (-1);
73867089Sgjelinek 	}
73877089Sgjelinek 	if (mkdir(pathbuf, S_IRWXU) < 0 && errno != EEXIST) {
73887089Sgjelinek 		zerror(zone_name, gettext("could not mkdir %s: %s"), pathbuf,
73897089Sgjelinek 		    strerror(errno));
73907089Sgjelinek 		return (-1);
73917089Sgjelinek 	}
73927089Sgjelinek 	(void) chmod(pathbuf, S_IRWXU);
73937089Sgjelinek 
73947089Sgjelinek 	/*
73957089Sgjelinek 	 * One of these lock files is created for each zone (when needed).
73967089Sgjelinek 	 * The lock files are not cleaned up (except on system reboot),
73977089Sgjelinek 	 * but since there is only one per zone, there is no resource
73987089Sgjelinek 	 * starvation issue.
73996831Sgjelinek 	 */
74007089Sgjelinek 	if (snprintf(pathbuf, sizeof (pathbuf), "%s%s/%s.zoneadm.lock",
74017089Sgjelinek 	    zonecfg_get_root(), ZONES_TMPDIR, zone_name) >= sizeof (pathbuf)) {
74027089Sgjelinek 		zerror(zone_name, gettext("alternate root path is too long"));
74037089Sgjelinek 		return (-1);
74047089Sgjelinek 	}
74057089Sgjelinek 	if ((*lockfd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
74067089Sgjelinek 		zerror(zone_name, gettext("could not open %s: %s"), pathbuf,
74077089Sgjelinek 		    strerror(errno));
74087089Sgjelinek 		return (-1);
74097089Sgjelinek 	}
74107089Sgjelinek 	/*
74117089Sgjelinek 	 * Lock the file to synchronize with other zoneadmds
74127089Sgjelinek 	 */
74137089Sgjelinek 	flock.l_type = F_WRLCK;
74147089Sgjelinek 	flock.l_whence = SEEK_SET;
74157089Sgjelinek 	flock.l_start = (off_t)0;
74167089Sgjelinek 	flock.l_len = (off_t)0;
74177089Sgjelinek 	if ((fcntl(*lockfd, F_SETLKW, &flock) < 0) ||
74187089Sgjelinek 	    (putenv(zoneadm_lock_held) != 0)) {
74197089Sgjelinek 		zerror(zone_name, gettext("unable to lock %s: %s"), pathbuf,
74207089Sgjelinek 		    strerror(errno));
74217089Sgjelinek 		zonecfg_release_lock_file(zone_name, *lockfd);
74227089Sgjelinek 		return (-1);
74237089Sgjelinek 	}
74247089Sgjelinek 	zone_lock_cnt = 1;
74257089Sgjelinek 	return (Z_OK);
74267089Sgjelinek }
74277089Sgjelinek 
74288759Sgerald.jelinek@sun.com boolean_t
zonecfg_lock_file_held(int * lockfd)74298759Sgerald.jelinek@sun.com zonecfg_lock_file_held(int *lockfd)
74308759Sgerald.jelinek@sun.com {
74318759Sgerald.jelinek@sun.com 	if (*lockfd >= 0 || zone_lock_cnt > 0)
74328759Sgerald.jelinek@sun.com 		return (B_TRUE);
74338759Sgerald.jelinek@sun.com 	return (B_FALSE);
74348759Sgerald.jelinek@sun.com }
74358759Sgerald.jelinek@sun.com 
74364229Sgjelinek static boolean_t
get_doorname(const char * zone_name,char * buffer)74377089Sgjelinek get_doorname(const char *zone_name, char *buffer)
74387089Sgjelinek {
74397089Sgjelinek 	return (snprintf(buffer, PATH_MAX, "%s" ZONE_DOOR_PATH,
74407089Sgjelinek 	    zonecfg_get_root(), zone_name) < PATH_MAX);
74414229Sgjelinek }
74424229Sgjelinek 
74434229Sgjelinek /*
74447089Sgjelinek  * system daemons are not audited.  For the global zone, this occurs
74457089Sgjelinek  * "naturally" since init is started with the default audit
74467089Sgjelinek  * characteristics.  Since zoneadmd is a system daemon and it starts
74477089Sgjelinek  * init for a zone, it is necessary to clear out the audit
74487089Sgjelinek  * characteristics inherited from whomever started zoneadmd.  This is
74497089Sgjelinek  * indicated by the audit id, which is set from the ruid parameter of
74507089Sgjelinek  * adt_set_user(), below.
74514229Sgjelinek  */
74527089Sgjelinek 
74537089Sgjelinek static void
prepare_audit_context(const char * zone_name)74547089Sgjelinek prepare_audit_context(const char *zone_name)
74557089Sgjelinek {
74567089Sgjelinek 	adt_session_data_t	*ah;
74577089Sgjelinek 	char			*failure = gettext("audit failure: %s");
74587089Sgjelinek 
74597089Sgjelinek 	if (adt_start_session(&ah, NULL, 0)) {
74607089Sgjelinek 		zerror(zone_name, failure, strerror(errno));
74617089Sgjelinek 		return;
74627089Sgjelinek 	}
74637089Sgjelinek 	if (adt_set_user(ah, ADT_NO_AUDIT, ADT_NO_AUDIT,
74647089Sgjelinek 	    ADT_NO_AUDIT, ADT_NO_AUDIT, NULL, ADT_NEW)) {
74657089Sgjelinek 		zerror(zone_name, failure, strerror(errno));
74667089Sgjelinek 		(void) adt_end_session(ah);
74677089Sgjelinek 		return;
74687089Sgjelinek 	}
74697089Sgjelinek 	if (adt_set_proc(ah))
74707089Sgjelinek 		zerror(zone_name, failure, strerror(errno));
74717089Sgjelinek 
74727089Sgjelinek 	(void) adt_end_session(ah);
74737089Sgjelinek }
74747089Sgjelinek 
74754229Sgjelinek static int
start_zoneadmd(const char * zone_name,boolean_t lock)74767089Sgjelinek start_zoneadmd(const char *zone_name, boolean_t lock)
74777089Sgjelinek {
74787089Sgjelinek 	char doorpath[PATH_MAX];
74797089Sgjelinek 	pid_t child_pid;
74807089Sgjelinek 	int error = -1;
74817089Sgjelinek 	int doorfd, lockfd;
74827089Sgjelinek 	struct door_info info;
74837089Sgjelinek 
74847089Sgjelinek 	if (!get_doorname(zone_name, doorpath))
74857089Sgjelinek 		return (-1);
74867089Sgjelinek 
74877089Sgjelinek 	if (lock)
74887089Sgjelinek 		if (zonecfg_grab_lock_file(zone_name, &lockfd) != Z_OK)
74897089Sgjelinek 			return (-1);
74907089Sgjelinek 
74917089Sgjelinek 	/*
74927089Sgjelinek 	 * Now that we have the lock, re-confirm that the daemon is
74937089Sgjelinek 	 * *not* up and working fine.  If it is still down, we have a green
74947089Sgjelinek 	 * light to start it.
74957089Sgjelinek 	 */
74967089Sgjelinek 	if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
74977089Sgjelinek 		if (errno != ENOENT) {
74987089Sgjelinek 			zperror(doorpath);
74997089Sgjelinek 			goto out;
75007089Sgjelinek 		}
75017089Sgjelinek 	} else {
75027089Sgjelinek 		if (door_info(doorfd, &info) == 0 &&
75037089Sgjelinek 		    ((info.di_attributes & DOOR_REVOKED) == 0)) {
75047089Sgjelinek 			error = Z_OK;
75057089Sgjelinek 			(void) close(doorfd);
75067089Sgjelinek 			goto out;
75077089Sgjelinek 		}
75087089Sgjelinek 		(void) close(doorfd);
75097089Sgjelinek 	}
75107089Sgjelinek 
75117089Sgjelinek 	if ((child_pid = fork()) == -1) {
75127089Sgjelinek 		zperror(gettext("could not fork"));
75137089Sgjelinek 		goto out;
75147089Sgjelinek 	}
75157089Sgjelinek 
75167089Sgjelinek 	if (child_pid == 0) {
75177089Sgjelinek 		const char *argv[6], **ap;
75187089Sgjelinek 
75197089Sgjelinek 		/* child process */
75207089Sgjelinek 		prepare_audit_context(zone_name);
75217089Sgjelinek 
75227089Sgjelinek 		ap = argv;
75237089Sgjelinek 		*ap++ = "zoneadmd";
75247089Sgjelinek 		*ap++ = "-z";
75257089Sgjelinek 		*ap++ = zone_name;
75267089Sgjelinek 		if (zonecfg_in_alt_root()) {
75277089Sgjelinek 			*ap++ = "-R";
75287089Sgjelinek 			*ap++ = zonecfg_get_root();
75297089Sgjelinek 		}
75307089Sgjelinek 		*ap = NULL;
75317089Sgjelinek 
75327089Sgjelinek 		(void) execv("/usr/lib/zones/zoneadmd", (char * const *)argv);
75337089Sgjelinek 		/*
75347089Sgjelinek 		 * TRANSLATION_NOTE
75357089Sgjelinek 		 * zoneadmd is a literal that should not be translated.
75367089Sgjelinek 		 */
75377089Sgjelinek 		zperror(gettext("could not exec zoneadmd"));
75387089Sgjelinek 		_exit(1);
75397089Sgjelinek 	} else {
75407089Sgjelinek 		/* parent process */
75417089Sgjelinek 		pid_t retval;
75427089Sgjelinek 		int pstatus = 0;
75437089Sgjelinek 
75447089Sgjelinek 		do {
75457089Sgjelinek 			retval = waitpid(child_pid, &pstatus, 0);
75467089Sgjelinek 		} while (retval != child_pid);
75477089Sgjelinek 		if (WIFSIGNALED(pstatus) || (WIFEXITED(pstatus) &&
75487089Sgjelinek 		    WEXITSTATUS(pstatus) != 0)) {
75497089Sgjelinek 			zerror(zone_name, gettext("could not start %s"),
75507089Sgjelinek 			    "zoneadmd");
75517089Sgjelinek 			goto out;
75527089Sgjelinek 		}
75537089Sgjelinek 	}
75547089Sgjelinek 	error = Z_OK;
75557089Sgjelinek out:
75567089Sgjelinek 	if (lock)
75577089Sgjelinek 		zonecfg_release_lock_file(zone_name, lockfd);
75587089Sgjelinek 	return (error);
75597089Sgjelinek }
75607089Sgjelinek 
75617089Sgjelinek int
zonecfg_ping_zoneadmd(const char * zone_name)75627089Sgjelinek zonecfg_ping_zoneadmd(const char *zone_name)
75637089Sgjelinek {
75647089Sgjelinek 	char doorpath[PATH_MAX];
75657089Sgjelinek 	int doorfd;
75667089Sgjelinek 	struct door_info info;
75677089Sgjelinek 
75687089Sgjelinek 	if (!get_doorname(zone_name, doorpath))
75697089Sgjelinek 		return (-1);
75707089Sgjelinek 
75717089Sgjelinek 	if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
75727089Sgjelinek 		return (-1);
75737089Sgjelinek 	}
75747089Sgjelinek 	if (door_info(doorfd, &info) == 0 &&
75757089Sgjelinek 	    ((info.di_attributes & DOOR_REVOKED) == 0)) {
75767089Sgjelinek 		(void) close(doorfd);
75774229Sgjelinek 		return (Z_OK);
75787089Sgjelinek 	}
75797089Sgjelinek 	(void) close(doorfd);
75807089Sgjelinek 	return (-1);
75817089Sgjelinek }
75827089Sgjelinek 
75837089Sgjelinek int
zonecfg_call_zoneadmd(const char * zone_name,zone_cmd_arg_t * arg,char * locale,boolean_t lock)75847089Sgjelinek zonecfg_call_zoneadmd(const char *zone_name, zone_cmd_arg_t *arg, char *locale,
75857089Sgjelinek     boolean_t lock)
75867089Sgjelinek {
75877089Sgjelinek 	char doorpath[PATH_MAX];
75887089Sgjelinek 	int doorfd, result;
75897089Sgjelinek 	door_arg_t darg;
75907089Sgjelinek 
75917089Sgjelinek 	zoneid_t zoneid;
75927089Sgjelinek 	uint64_t uniqid = 0;
75937089Sgjelinek 
75947089Sgjelinek 	zone_cmd_rval_t *rvalp;
75957089Sgjelinek 	size_t rlen;
75967089Sgjelinek 	char *cp, *errbuf;
75977089Sgjelinek 
75987089Sgjelinek 	rlen = getpagesize();
75997089Sgjelinek 	if ((rvalp = malloc(rlen)) == NULL) {
76007089Sgjelinek 		zerror(zone_name, gettext("failed to allocate %lu bytes: %s"),
76017089Sgjelinek 		    rlen, strerror(errno));
76027089Sgjelinek 		return (-1);
76037089Sgjelinek 	}
76047089Sgjelinek 
76057089Sgjelinek 	if ((zoneid = getzoneidbyname(zone_name)) != ZONE_ID_UNDEFINED) {
76067089Sgjelinek 		(void) zone_getattr(zoneid, ZONE_ATTR_UNIQID, &uniqid,
76077089Sgjelinek 		    sizeof (uniqid));
76087089Sgjelinek 	}
76097089Sgjelinek 	arg->uniqid = uniqid;
76107089Sgjelinek 	(void) strlcpy(arg->locale, locale, sizeof (arg->locale));
76117089Sgjelinek 	if (!get_doorname(zone_name, doorpath)) {
76127089Sgjelinek 		zerror(zone_name, gettext("alternate root path is too long"));
76137089Sgjelinek 		free(rvalp);
76147089Sgjelinek 		return (-1);
76157059Sgjelinek 	}
76161507Sgjelinek 
76171507Sgjelinek 	/*
76187089Sgjelinek 	 * Loop trying to start zoneadmd; if something goes seriously
76197089Sgjelinek 	 * wrong we break out and fail.
76201507Sgjelinek 	 */
76217089Sgjelinek 	for (;;) {
76227089Sgjelinek 		if (start_zoneadmd(zone_name, lock) != Z_OK)
76237089Sgjelinek 			break;
76247089Sgjelinek 
76257089Sgjelinek 		if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
76267089Sgjelinek 			zperror(gettext("failed to open zone door"));
76277089Sgjelinek 			break;
76281507Sgjelinek 		}
76294229Sgjelinek 
76307089Sgjelinek 		darg.data_ptr = (char *)arg;
76317089Sgjelinek 		darg.data_size = sizeof (*arg);
76327089Sgjelinek 		darg.desc_ptr = NULL;
76337089Sgjelinek 		darg.desc_num = 0;
76347089Sgjelinek 		darg.rbuf = (char *)rvalp;
76357089Sgjelinek 		darg.rsize = rlen;
76367089Sgjelinek 		if (door_call(doorfd, &darg) != 0) {
76377089Sgjelinek 			(void) close(doorfd);
76387089Sgjelinek 			/*
76397089Sgjelinek 			 * We'll get EBADF if the door has been revoked.
76407089Sgjelinek 			 */
76417089Sgjelinek 			if (errno != EBADF) {
76427089Sgjelinek 				zperror(gettext("door_call failed"));
76431507Sgjelinek 				break;
76441507Sgjelinek 			}
76457089Sgjelinek 			continue;	/* take another lap */
76461507Sgjelinek 		}
76477089Sgjelinek 		(void) close(doorfd);
76487089Sgjelinek 
76497089Sgjelinek 		if (darg.data_size == 0) {
76507089Sgjelinek 			/* Door server is going away; kick it again. */
76515829Sgjelinek 			continue;
76525829Sgjelinek 		}
76535829Sgjelinek 
76547089Sgjelinek 		errbuf = rvalp->errbuf;
76557089Sgjelinek 		while (*errbuf != '\0') {
76567089Sgjelinek 			/*
76577089Sgjelinek 			 * Remove any newlines since zerror()
76587089Sgjelinek 			 * will append one automatically.
76597089Sgjelinek 			 */
76607089Sgjelinek 			cp = strchr(errbuf, '\n');
76617089Sgjelinek 			if (cp != NULL)
76627089Sgjelinek 				*cp = '\0';
76637089Sgjelinek 			zerror(zone_name, "%s", errbuf);
76647089Sgjelinek 			if (cp == NULL)
76657089Sgjelinek 				break;
76667089Sgjelinek 			errbuf = cp + 1;
76675829Sgjelinek 		}
76687089Sgjelinek 		result = rvalp->rval == 0 ? 0 : -1;
76697089Sgjelinek 		free(rvalp);
76707089Sgjelinek 		return (result);
76717089Sgjelinek 	}
76727089Sgjelinek 
76737089Sgjelinek 	free(rvalp);
76747089Sgjelinek 	return (-1);
76757089Sgjelinek }
767612578SGlenn.Faden@Sun.COM 
767712578SGlenn.Faden@Sun.COM boolean_t
zonecfg_valid_auths(const char * auths,const char * zonename)767812578SGlenn.Faden@Sun.COM zonecfg_valid_auths(const char *auths, const char *zonename)
767912578SGlenn.Faden@Sun.COM {
768012578SGlenn.Faden@Sun.COM 	char *right;
768112578SGlenn.Faden@Sun.COM 	char *tmpauths;
768212578SGlenn.Faden@Sun.COM 	char *lasts;
768312578SGlenn.Faden@Sun.COM 	char authname[MAXAUTHS];
768412578SGlenn.Faden@Sun.COM 	boolean_t status = B_TRUE;
768512578SGlenn.Faden@Sun.COM 
768612578SGlenn.Faden@Sun.COM 	tmpauths = strdup(auths);
768712578SGlenn.Faden@Sun.COM 	if (tmpauths == NULL) {
768812578SGlenn.Faden@Sun.COM 		zerror(zonename, gettext("Out of memory"));
768912578SGlenn.Faden@Sun.COM 		return (B_FALSE);
769012578SGlenn.Faden@Sun.COM 	}
769112578SGlenn.Faden@Sun.COM 	right = strtok_r(tmpauths, ",", &lasts);
769212578SGlenn.Faden@Sun.COM 	while (right != NULL) {
769312578SGlenn.Faden@Sun.COM 		(void) snprintf(authname, MAXAUTHS, "%s%s",
769412578SGlenn.Faden@Sun.COM 		    ZONE_AUTH_PREFIX, right);
769512578SGlenn.Faden@Sun.COM 		if (getauthnam(authname) == NULL) {
769612578SGlenn.Faden@Sun.COM 			status = B_FALSE;
769712582SGlenn.Faden@Sun.COM 			zerror(zonename,
769812635SGlenn.Faden@Sun.COM 			    gettext("'%s' is not a valid authorization"),
769912578SGlenn.Faden@Sun.COM 			    right);
770012578SGlenn.Faden@Sun.COM 		}
770112578SGlenn.Faden@Sun.COM 		right = strtok_r(NULL, ",", &lasts);
770212578SGlenn.Faden@Sun.COM 	}
770312578SGlenn.Faden@Sun.COM 	free(tmpauths);
770412578SGlenn.Faden@Sun.COM 	return (status);
770512578SGlenn.Faden@Sun.COM }
770612578SGlenn.Faden@Sun.COM 
770712578SGlenn.Faden@Sun.COM int
zonecfg_delete_admins(zone_dochandle_t handle,char * zonename)770812578SGlenn.Faden@Sun.COM zonecfg_delete_admins(zone_dochandle_t handle, char *zonename)
770912578SGlenn.Faden@Sun.COM {
771012578SGlenn.Faden@Sun.COM 	int err;
771112578SGlenn.Faden@Sun.COM 	struct zone_admintab admintab;
771212578SGlenn.Faden@Sun.COM 	boolean_t changed = B_FALSE;
771312578SGlenn.Faden@Sun.COM 
771412578SGlenn.Faden@Sun.COM 	if ((err = zonecfg_setadminent(handle)) != Z_OK) {
771512578SGlenn.Faden@Sun.COM 		return (err);
771612578SGlenn.Faden@Sun.COM 	}
771712578SGlenn.Faden@Sun.COM 	while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
771812578SGlenn.Faden@Sun.COM 		err = zonecfg_delete_admin(handle, &admintab,
771912578SGlenn.Faden@Sun.COM 		    zonename);
772012578SGlenn.Faden@Sun.COM 		if (err != Z_OK) {
772112578SGlenn.Faden@Sun.COM 			(void) zonecfg_endadminent(handle);
772212578SGlenn.Faden@Sun.COM 			return (err);
772312578SGlenn.Faden@Sun.COM 		} else {
772412578SGlenn.Faden@Sun.COM 			changed = B_TRUE;
772512578SGlenn.Faden@Sun.COM 		}
772612578SGlenn.Faden@Sun.COM 		if ((err = zonecfg_setadminent(handle)) != Z_OK) {
772712578SGlenn.Faden@Sun.COM 			return (err);
772812578SGlenn.Faden@Sun.COM 		}
772912578SGlenn.Faden@Sun.COM 	}
773012578SGlenn.Faden@Sun.COM 	(void) zonecfg_endadminent(handle);
773112578SGlenn.Faden@Sun.COM 	return (changed? Z_OK:Z_NO_ENTRY);
773212578SGlenn.Faden@Sun.COM }
773312578SGlenn.Faden@Sun.COM 
773412578SGlenn.Faden@Sun.COM /*
773512578SGlenn.Faden@Sun.COM  * Checks if a long authorization applies to this zone.
773612578SGlenn.Faden@Sun.COM  * If so, it returns true, after destructively stripping
773712578SGlenn.Faden@Sun.COM  * the authorization of its prefix and zone suffix.
773812578SGlenn.Faden@Sun.COM  */
773912578SGlenn.Faden@Sun.COM static boolean_t
is_zone_auth(char ** auth,char * zonename,char * oldzonename)774012578SGlenn.Faden@Sun.COM is_zone_auth(char **auth, char *zonename, char *oldzonename)
774112578SGlenn.Faden@Sun.COM {
774212578SGlenn.Faden@Sun.COM 	char *suffix;
774312578SGlenn.Faden@Sun.COM 	size_t offset;
774412578SGlenn.Faden@Sun.COM 
774512578SGlenn.Faden@Sun.COM 	offset = strlen(ZONE_AUTH_PREFIX);
774612578SGlenn.Faden@Sun.COM 	if ((strncmp(*auth, ZONE_AUTH_PREFIX, offset) == 0) &&
774712578SGlenn.Faden@Sun.COM 	    ((suffix = strchr(*auth, '/')) != NULL)) {
774812635SGlenn.Faden@Sun.COM 		if (strcmp(suffix + 1, zonename) == 0) {
774912578SGlenn.Faden@Sun.COM 			*auth += offset;
775012578SGlenn.Faden@Sun.COM 			suffix[0] = '\0';
775112578SGlenn.Faden@Sun.COM 			return (B_TRUE);
775212578SGlenn.Faden@Sun.COM 		} else if ((oldzonename != NULL) &&
775312635SGlenn.Faden@Sun.COM 		    (strcmp(suffix + 1, oldzonename) == 0)) {
775412578SGlenn.Faden@Sun.COM 			*auth += offset;
775512578SGlenn.Faden@Sun.COM 			suffix[0] = '\0';
775612578SGlenn.Faden@Sun.COM 			return (B_TRUE);
775712578SGlenn.Faden@Sun.COM 		}
775812578SGlenn.Faden@Sun.COM 	}
775912578SGlenn.Faden@Sun.COM 	return (B_FALSE);
776012578SGlenn.Faden@Sun.COM }
776112578SGlenn.Faden@Sun.COM 
776212578SGlenn.Faden@Sun.COM /*
776312578SGlenn.Faden@Sun.COM  * This function determines whether the zone-specific authorization
776412578SGlenn.Faden@Sun.COM  * assignments in /etc/user_attr have been changed more recently
776512578SGlenn.Faden@Sun.COM  * than the equivalent data stored in the zone's configuration file.
776612578SGlenn.Faden@Sun.COM  * This should only happen if the zone-specific authorizations in
776712578SGlenn.Faden@Sun.COM  * the user_attr file were modified using a tool other than zonecfg.
776812578SGlenn.Faden@Sun.COM  * If the configuration file is out-of-date with respect to these
776912578SGlenn.Faden@Sun.COM  * authorization assignments, it is updated to match those specified
777012578SGlenn.Faden@Sun.COM  * in /etc/user_attr.
777112578SGlenn.Faden@Sun.COM  */
777212578SGlenn.Faden@Sun.COM 
777312578SGlenn.Faden@Sun.COM int
zonecfg_update_userauths(zone_dochandle_t handle,char * zonename)777412578SGlenn.Faden@Sun.COM zonecfg_update_userauths(zone_dochandle_t handle, char *zonename)
777512578SGlenn.Faden@Sun.COM {
777612578SGlenn.Faden@Sun.COM 	userattr_t *ua_ptr;
777712578SGlenn.Faden@Sun.COM 	char *authlist;
777812578SGlenn.Faden@Sun.COM 	char *lasts;
777912578SGlenn.Faden@Sun.COM 	FILE  *uaf;
778012578SGlenn.Faden@Sun.COM 	struct zone_admintab admintab;
778112578SGlenn.Faden@Sun.COM 	struct stat config_st, ua_st;
778212578SGlenn.Faden@Sun.COM 	char config_file[MAXPATHLEN];
778312578SGlenn.Faden@Sun.COM 	boolean_t changed = B_FALSE;
778412578SGlenn.Faden@Sun.COM 	int err;
778512578SGlenn.Faden@Sun.COM 
778612578SGlenn.Faden@Sun.COM 	if ((uaf = fopen(USERATTR_FILENAME, "r")) == NULL) {
778712578SGlenn.Faden@Sun.COM 		zerror(zonename, gettext("could not open file %s: %s"),
778812578SGlenn.Faden@Sun.COM 		    USERATTR_FILENAME, strerror(errno));
778912578SGlenn.Faden@Sun.COM 		if (errno == EACCES)
779012578SGlenn.Faden@Sun.COM 			return (Z_ACCES);
779112578SGlenn.Faden@Sun.COM 		if (errno == ENOENT)
779212578SGlenn.Faden@Sun.COM 			return (Z_NO_ZONE);
779312578SGlenn.Faden@Sun.COM 		return (Z_MISC_FS);
779412578SGlenn.Faden@Sun.COM 	}
779512578SGlenn.Faden@Sun.COM 	if ((err = fstat(fileno(uaf), &ua_st)) != 0) {
779612578SGlenn.Faden@Sun.COM 		zerror(zonename, gettext("could not stat file %s: %s"),
779712578SGlenn.Faden@Sun.COM 		    USERATTR_FILENAME, strerror(errno));
779812578SGlenn.Faden@Sun.COM 		(void) fclose(uaf);
779912578SGlenn.Faden@Sun.COM 		return (Z_MISC_FS);
780012578SGlenn.Faden@Sun.COM 	}
780112578SGlenn.Faden@Sun.COM 	if (!config_file_path(zonename, config_file)) {
780212578SGlenn.Faden@Sun.COM 		(void) fclose(uaf);
780312578SGlenn.Faden@Sun.COM 		return (Z_MISC_FS);
780412578SGlenn.Faden@Sun.COM 	}
780512578SGlenn.Faden@Sun.COM 
780612578SGlenn.Faden@Sun.COM 	if ((err = stat(config_file, &config_st)) != 0) {
780712578SGlenn.Faden@Sun.COM 		zerror(zonename, gettext("could not stat file %s: %s"),
780812578SGlenn.Faden@Sun.COM 		    config_file, strerror(errno));
780912578SGlenn.Faden@Sun.COM 		(void) fclose(uaf);
781012578SGlenn.Faden@Sun.COM 		return (Z_MISC_FS);
781112578SGlenn.Faden@Sun.COM 	}
781212578SGlenn.Faden@Sun.COM 	if (config_st.st_mtime >= ua_st.st_mtime) {
781312578SGlenn.Faden@Sun.COM 		(void) fclose(uaf);
781412578SGlenn.Faden@Sun.COM 		return (Z_NO_ENTRY);
781512578SGlenn.Faden@Sun.COM 	}
781612578SGlenn.Faden@Sun.COM 	if ((err = zonecfg_delete_admins(handle, zonename)) == Z_OK) {
781712578SGlenn.Faden@Sun.COM 		changed = B_TRUE;
781812578SGlenn.Faden@Sun.COM 	} else if (err != Z_NO_ENTRY) {
781912578SGlenn.Faden@Sun.COM 		(void) fclose(uaf);
782012578SGlenn.Faden@Sun.COM 		return (err);
782112578SGlenn.Faden@Sun.COM 	}
782212578SGlenn.Faden@Sun.COM 	while ((ua_ptr = fgetuserattr(uaf)) != NULL) {
782312578SGlenn.Faden@Sun.COM 		if (ua_ptr->name[0] == '#') {
782412578SGlenn.Faden@Sun.COM 			continue;
782512578SGlenn.Faden@Sun.COM 		}
782612578SGlenn.Faden@Sun.COM 		authlist = kva_match(ua_ptr->attr, USERATTR_AUTHS_KW);
782712578SGlenn.Faden@Sun.COM 		if (authlist != NULL) {
782812578SGlenn.Faden@Sun.COM 			char *cur_auth;
782912578SGlenn.Faden@Sun.COM 			boolean_t first;
783012578SGlenn.Faden@Sun.COM 
783112578SGlenn.Faden@Sun.COM 			first = B_TRUE;
783212578SGlenn.Faden@Sun.COM 			bzero(&admintab.zone_admin_auths, MAXAUTHS);
783312578SGlenn.Faden@Sun.COM 			cur_auth = strtok_r(authlist, ",", &lasts);
783412578SGlenn.Faden@Sun.COM 			while (cur_auth != NULL) {
783512578SGlenn.Faden@Sun.COM 				if (is_zone_auth(&cur_auth, zonename,
783612578SGlenn.Faden@Sun.COM 				    NULL)) {
783712578SGlenn.Faden@Sun.COM 					/*
783812578SGlenn.Faden@Sun.COM 					 * Add auths for this zone
783912578SGlenn.Faden@Sun.COM 					 */
784012578SGlenn.Faden@Sun.COM 					if (first) {
784112578SGlenn.Faden@Sun.COM 						first = B_FALSE;
784212578SGlenn.Faden@Sun.COM 					} else {
784312578SGlenn.Faden@Sun.COM 						(void) strlcat(
784412578SGlenn.Faden@Sun.COM 						    admintab.zone_admin_auths,
784512578SGlenn.Faden@Sun.COM 						    ",", MAXAUTHS);
784612578SGlenn.Faden@Sun.COM 					}
784712578SGlenn.Faden@Sun.COM 					(void) strlcat(
784812578SGlenn.Faden@Sun.COM 					    admintab.zone_admin_auths,
784912578SGlenn.Faden@Sun.COM 					    cur_auth, MAXAUTHS);
785012578SGlenn.Faden@Sun.COM 				}
785112578SGlenn.Faden@Sun.COM 				cur_auth = strtok_r(NULL, ",", &lasts);
785212578SGlenn.Faden@Sun.COM 			}
785312578SGlenn.Faden@Sun.COM 			if (!first) {
785412578SGlenn.Faden@Sun.COM 				/*
785512578SGlenn.Faden@Sun.COM 				 * Add this right to config file
785612578SGlenn.Faden@Sun.COM 				 */
785712578SGlenn.Faden@Sun.COM 				(void) strlcpy(admintab.zone_admin_user,
785812578SGlenn.Faden@Sun.COM 				    ua_ptr->name,
785912578SGlenn.Faden@Sun.COM 				    sizeof (admintab.zone_admin_user));
786012578SGlenn.Faden@Sun.COM 				err = zonecfg_add_admin(handle,
786112578SGlenn.Faden@Sun.COM 				    &admintab, zonename);
786212578SGlenn.Faden@Sun.COM 				if (err != Z_OK) {
786312578SGlenn.Faden@Sun.COM 					(void) fclose(uaf);
786412578SGlenn.Faden@Sun.COM 					return (err);
786512578SGlenn.Faden@Sun.COM 				} else {
786612578SGlenn.Faden@Sun.COM 					changed = B_TRUE;
786712578SGlenn.Faden@Sun.COM 				}
786812578SGlenn.Faden@Sun.COM 			}
786912578SGlenn.Faden@Sun.COM 		}
787012578SGlenn.Faden@Sun.COM 	} /* end-of-while-loop */
787112578SGlenn.Faden@Sun.COM 	(void) fclose(uaf);
787212578SGlenn.Faden@Sun.COM 	return (changed? Z_OK: Z_NO_ENTRY);
787312578SGlenn.Faden@Sun.COM }
787412578SGlenn.Faden@Sun.COM 
787512578SGlenn.Faden@Sun.COM static void
update_profiles(char * rbac_profs,boolean_t add)787612578SGlenn.Faden@Sun.COM update_profiles(char *rbac_profs, boolean_t add)
787712578SGlenn.Faden@Sun.COM {
787812578SGlenn.Faden@Sun.COM 	char new_profs[MAXPROFS];
787912578SGlenn.Faden@Sun.COM 	char *cur_prof;
788012578SGlenn.Faden@Sun.COM 	boolean_t first = B_TRUE;
788112578SGlenn.Faden@Sun.COM 	boolean_t found = B_FALSE;
788212578SGlenn.Faden@Sun.COM 	char *lasts;
788312578SGlenn.Faden@Sun.COM 
788412578SGlenn.Faden@Sun.COM 	cur_prof = strtok_r(rbac_profs, ",", &lasts);
788512578SGlenn.Faden@Sun.COM 	while (cur_prof != NULL) {
788612578SGlenn.Faden@Sun.COM 		if (strcmp(cur_prof, ZONE_MGMT_PROF) == 0) {
788712578SGlenn.Faden@Sun.COM 			found = B_TRUE;
788812578SGlenn.Faden@Sun.COM 			if (!add) {
788912578SGlenn.Faden@Sun.COM 				cur_prof = strtok_r(NULL, ",", &lasts);
789012578SGlenn.Faden@Sun.COM 				continue;
789112578SGlenn.Faden@Sun.COM 			}
789212578SGlenn.Faden@Sun.COM 		}
789312578SGlenn.Faden@Sun.COM 		if (first) {
789412578SGlenn.Faden@Sun.COM 			first = B_FALSE;
789512578SGlenn.Faden@Sun.COM 		} else {
789612578SGlenn.Faden@Sun.COM 			(void) strlcat(new_profs, ",",
789712578SGlenn.Faden@Sun.COM 			    MAXPROFS);
789812578SGlenn.Faden@Sun.COM 		}
789912578SGlenn.Faden@Sun.COM 		(void) strlcat(new_profs, cur_prof,
790012578SGlenn.Faden@Sun.COM 		    MAXPROFS);
790112578SGlenn.Faden@Sun.COM 		cur_prof = strtok_r(NULL, ",", &lasts);
790212578SGlenn.Faden@Sun.COM 	}
790312578SGlenn.Faden@Sun.COM 	/*
790412578SGlenn.Faden@Sun.COM 	 * Now prepend the Zone Management profile at the beginning
790512578SGlenn.Faden@Sun.COM 	 * of the list if it is needed, and append the rest.
790612578SGlenn.Faden@Sun.COM 	 * Return the updated list in the original buffer.
790712578SGlenn.Faden@Sun.COM 	 */
790812578SGlenn.Faden@Sun.COM 	if (add && !found) {
790912578SGlenn.Faden@Sun.COM 		first = B_FALSE;
791012578SGlenn.Faden@Sun.COM 		(void) strlcpy(rbac_profs, ZONE_MGMT_PROF, MAXPROFS);
791112578SGlenn.Faden@Sun.COM 	} else {
791212578SGlenn.Faden@Sun.COM 		first = B_TRUE;
791312578SGlenn.Faden@Sun.COM 		rbac_profs[0] = '\0';
791412578SGlenn.Faden@Sun.COM 	}
791512578SGlenn.Faden@Sun.COM 	if (strlen(new_profs) > 0) {
791612578SGlenn.Faden@Sun.COM 		if (!first)
791712578SGlenn.Faden@Sun.COM 			(void) strlcat(rbac_profs, ",", MAXPROFS);
791812578SGlenn.Faden@Sun.COM 		(void) strlcat(rbac_profs, new_profs, MAXPROFS);
791912578SGlenn.Faden@Sun.COM 	}
792012578SGlenn.Faden@Sun.COM }
792112578SGlenn.Faden@Sun.COM 
792212578SGlenn.Faden@Sun.COM #define	MAX_CMD_LEN	1024
792312578SGlenn.Faden@Sun.COM 
792412578SGlenn.Faden@Sun.COM static int
do_subproc(char * zonename,char * cmdbuf)792512578SGlenn.Faden@Sun.COM do_subproc(char *zonename, char *cmdbuf)
792612578SGlenn.Faden@Sun.COM {
792712578SGlenn.Faden@Sun.COM 	char inbuf[MAX_CMD_LEN];
792812578SGlenn.Faden@Sun.COM 	FILE *file;
792912578SGlenn.Faden@Sun.COM 	int status;
793012578SGlenn.Faden@Sun.COM 
793112578SGlenn.Faden@Sun.COM 	file = popen(cmdbuf, "r");
793212578SGlenn.Faden@Sun.COM 	if (file == NULL) {
793312578SGlenn.Faden@Sun.COM 		zerror(zonename, gettext("Could not launch: %s"), cmdbuf);
793412578SGlenn.Faden@Sun.COM 		return (-1);
793512578SGlenn.Faden@Sun.COM 	}
793612578SGlenn.Faden@Sun.COM 
793712578SGlenn.Faden@Sun.COM 	while (fgets(inbuf, sizeof (inbuf), file) != NULL)
793812578SGlenn.Faden@Sun.COM 		(void) fprintf(stderr, "%s", inbuf);
793912578SGlenn.Faden@Sun.COM 	status = pclose(file);
794012578SGlenn.Faden@Sun.COM 
794112578SGlenn.Faden@Sun.COM 	if (WIFSIGNALED(status)) {
794212578SGlenn.Faden@Sun.COM 		zerror(zonename, gettext("%s unexpectedly terminated "
794312578SGlenn.Faden@Sun.COM 		    "due to signal %d"),
794412578SGlenn.Faden@Sun.COM 		    cmdbuf, WTERMSIG(status));
794512578SGlenn.Faden@Sun.COM 		return (-1);
794612578SGlenn.Faden@Sun.COM 	}
794712578SGlenn.Faden@Sun.COM 	assert(WIFEXITED(status));
794812578SGlenn.Faden@Sun.COM 	return (WEXITSTATUS(status));
794912578SGlenn.Faden@Sun.COM }
795012578SGlenn.Faden@Sun.COM 
795112578SGlenn.Faden@Sun.COM /*
795212578SGlenn.Faden@Sun.COM  * This function updates the local /etc/user_attr file to
795312578SGlenn.Faden@Sun.COM  * correspond to the admin settings that are currently being
795412578SGlenn.Faden@Sun.COM  * committed. The updates are done via usermod and/or rolemod
795512578SGlenn.Faden@Sun.COM  * depending on the type of the specified user. It is also
795612578SGlenn.Faden@Sun.COM  * invoked to remove entries from user_attr corresponding to
795712578SGlenn.Faden@Sun.COM  * removed admin assignments, using an empty auths string.
795812578SGlenn.Faden@Sun.COM  *
795912578SGlenn.Faden@Sun.COM  * Because the removed entries are no longer included in the
796012578SGlenn.Faden@Sun.COM  * cofiguration that is being committed, a linked list of
796112578SGlenn.Faden@Sun.COM  * removed admin entries is maintained to keep track of such
796212578SGlenn.Faden@Sun.COM  * transactions. The head of the list is stored in the zone_dh_userauths
796312578SGlenn.Faden@Sun.COM  * element of the handle strcture.
796412578SGlenn.Faden@Sun.COM  */
796512578SGlenn.Faden@Sun.COM static int
zonecfg_authorize_user_impl(zone_dochandle_t handle,char * user,char * auths,char * zonename)796612578SGlenn.Faden@Sun.COM zonecfg_authorize_user_impl(zone_dochandle_t handle, char *user,
796712578SGlenn.Faden@Sun.COM     char *auths, char *zonename)
796812578SGlenn.Faden@Sun.COM {
796912578SGlenn.Faden@Sun.COM 	char *right;
797012578SGlenn.Faden@Sun.COM 	char old_auths[MAXAUTHS];
797112578SGlenn.Faden@Sun.COM 	char new_auths[MAXAUTHS];
797212578SGlenn.Faden@Sun.COM 	char rbac_profs[MAXPROFS];
797312578SGlenn.Faden@Sun.COM 	char *lasts;
797412578SGlenn.Faden@Sun.COM 	userattr_t *u;
797512578SGlenn.Faden@Sun.COM 	boolean_t first = B_TRUE;
797612578SGlenn.Faden@Sun.COM 	boolean_t is_zone_admin = B_FALSE;
797712578SGlenn.Faden@Sun.COM 	char user_cmd[] = "/usr/sbin/usermod";
797812578SGlenn.Faden@Sun.COM 	char role_cmd[] = "/usr/sbin/rolemod";
797912635SGlenn.Faden@Sun.COM 	char *auths_cmd = user_cmd;	/* either usermod or rolemod */
798012635SGlenn.Faden@Sun.COM 	char *new_auth_start;		/* string containing the new auths */
798112635SGlenn.Faden@Sun.COM 	int new_auth_cnt = 0;		/* delta of changed authorizations */
798212578SGlenn.Faden@Sun.COM 
798312578SGlenn.Faden@Sun.COM 	/*
798412578SGlenn.Faden@Sun.COM 	 * First get the existing authorizations for this user
798512578SGlenn.Faden@Sun.COM 	 */
798612578SGlenn.Faden@Sun.COM 
798712578SGlenn.Faden@Sun.COM 	bzero(&old_auths, sizeof (old_auths));
798812578SGlenn.Faden@Sun.COM 	bzero(&new_auths, sizeof (new_auths));
798912578SGlenn.Faden@Sun.COM 	bzero(&rbac_profs, sizeof (rbac_profs));
799012578SGlenn.Faden@Sun.COM 	if ((u = getusernam(user)) != NULL) {
799112578SGlenn.Faden@Sun.COM 		char *current_auths;
799212578SGlenn.Faden@Sun.COM 		char *current_profs;
799312578SGlenn.Faden@Sun.COM 		char *type;
799412578SGlenn.Faden@Sun.COM 
799512578SGlenn.Faden@Sun.COM 		type = kva_match(u->attr, USERATTR_TYPE_KW);
799612578SGlenn.Faden@Sun.COM 		if (type != NULL) {
799712578SGlenn.Faden@Sun.COM 			if (strcmp(type, USERATTR_TYPE_NONADMIN_KW) == 0)
799812578SGlenn.Faden@Sun.COM 				auths_cmd = role_cmd;
799912578SGlenn.Faden@Sun.COM 		}
800012578SGlenn.Faden@Sun.COM 
800112578SGlenn.Faden@Sun.COM 		current_auths = kva_match(u->attr, USERATTR_AUTHS_KW);
800212578SGlenn.Faden@Sun.COM 		if (current_auths != NULL) {
800312578SGlenn.Faden@Sun.COM 			char *cur_auth;
800412578SGlenn.Faden@Sun.COM 			char *delete_name;
800512578SGlenn.Faden@Sun.COM 			size_t offset;
800612578SGlenn.Faden@Sun.COM 
800712578SGlenn.Faden@Sun.COM 			offset = strlen(ZONE_AUTH_PREFIX);
800812578SGlenn.Faden@Sun.COM 
800912578SGlenn.Faden@Sun.COM 			(void) strlcpy(old_auths, current_auths, MAXAUTHS);
801012578SGlenn.Faden@Sun.COM 			cur_auth = strtok_r(current_auths, ",", &lasts);
801112578SGlenn.Faden@Sun.COM 
801212578SGlenn.Faden@Sun.COM 			/*
801312578SGlenn.Faden@Sun.COM 			 * Next, remove any existing authorizations
801412578SGlenn.Faden@Sun.COM 			 * for this zone, and determine if the
801512578SGlenn.Faden@Sun.COM 			 * user still needs the Zone Management Profile.
801612578SGlenn.Faden@Sun.COM 			 */
801712578SGlenn.Faden@Sun.COM 			if (is_renaming(handle))
801812578SGlenn.Faden@Sun.COM 				delete_name = handle->zone_dh_delete_name;
801912578SGlenn.Faden@Sun.COM 			else
802012578SGlenn.Faden@Sun.COM 				delete_name = NULL;
802112578SGlenn.Faden@Sun.COM 			while (cur_auth != NULL) {
802212578SGlenn.Faden@Sun.COM 				if (!is_zone_auth(&cur_auth, zonename,
802312578SGlenn.Faden@Sun.COM 				    delete_name)) {
802412578SGlenn.Faden@Sun.COM 					if (first) {
802512578SGlenn.Faden@Sun.COM 						first = B_FALSE;
802612578SGlenn.Faden@Sun.COM 					} else {
802712578SGlenn.Faden@Sun.COM 						(void) strlcat(new_auths, ",",
802812578SGlenn.Faden@Sun.COM 						    MAXAUTHS);
802912578SGlenn.Faden@Sun.COM 					}
803012578SGlenn.Faden@Sun.COM 					(void) strlcat(new_auths, cur_auth,
803112578SGlenn.Faden@Sun.COM 					    MAXAUTHS);
803212578SGlenn.Faden@Sun.COM 					/*
803312578SGlenn.Faden@Sun.COM 					 * If the user has authorizations
803412578SGlenn.Faden@Sun.COM 					 * for other zones, then set a
803512578SGlenn.Faden@Sun.COM 					 * flag indicate that the Zone
803612578SGlenn.Faden@Sun.COM 					 * Management profile should be
803712578SGlenn.Faden@Sun.COM 					 * preserved in user_attr.
803812578SGlenn.Faden@Sun.COM 					 */
803912578SGlenn.Faden@Sun.COM 					if (strncmp(cur_auth,
804012578SGlenn.Faden@Sun.COM 					    ZONE_AUTH_PREFIX, offset) == 0)
804112578SGlenn.Faden@Sun.COM 						is_zone_admin = B_TRUE;
804212635SGlenn.Faden@Sun.COM 				} else {
804312635SGlenn.Faden@Sun.COM 					new_auth_cnt++;
804412578SGlenn.Faden@Sun.COM 				}
804512578SGlenn.Faden@Sun.COM 				cur_auth = strtok_r(NULL, ",", &lasts);
804612578SGlenn.Faden@Sun.COM 			}
804712578SGlenn.Faden@Sun.COM 		}
804812578SGlenn.Faden@Sun.COM 		current_profs = kva_match(u->attr, USERATTR_PROFILES_KW);
804912578SGlenn.Faden@Sun.COM 		if (current_profs != NULL) {
805012578SGlenn.Faden@Sun.COM 			(void) strlcpy(rbac_profs, current_profs, MAXPROFS);
805112578SGlenn.Faden@Sun.COM 		}
805212578SGlenn.Faden@Sun.COM 		free_userattr(u);
805312578SGlenn.Faden@Sun.COM 	}
805412578SGlenn.Faden@Sun.COM 	/*
805512578SGlenn.Faden@Sun.COM 	 * The following is done to avoid revisiting the
805612578SGlenn.Faden@Sun.COM 	 * user_attr entry for this user
805712578SGlenn.Faden@Sun.COM 	 */
805812578SGlenn.Faden@Sun.COM 	(void) zonecfg_remove_userauths(handle, user, "", B_FALSE);
805912578SGlenn.Faden@Sun.COM 
806012578SGlenn.Faden@Sun.COM 	/*
806112578SGlenn.Faden@Sun.COM 	 * Convert each right into a properly formatted authorization
806212578SGlenn.Faden@Sun.COM 	 */
806312635SGlenn.Faden@Sun.COM 	new_auth_start = new_auths + strlen(new_auths);
806412635SGlenn.Faden@Sun.COM 	if (!first)
806512635SGlenn.Faden@Sun.COM 		new_auth_start++;
806612578SGlenn.Faden@Sun.COM 	right = strtok_r(auths, ",", &lasts);
806712578SGlenn.Faden@Sun.COM 	while (right != NULL) {
806812578SGlenn.Faden@Sun.COM 		char auth[MAXAUTHS];
806912578SGlenn.Faden@Sun.COM 
807012578SGlenn.Faden@Sun.COM 		(void) snprintf(auth, MAXAUTHS, "%s%s/%s",
807112578SGlenn.Faden@Sun.COM 		    ZONE_AUTH_PREFIX, right, zonename);
807212578SGlenn.Faden@Sun.COM 		if (first) {
807312578SGlenn.Faden@Sun.COM 			first = B_FALSE;
807412578SGlenn.Faden@Sun.COM 		} else {
807512578SGlenn.Faden@Sun.COM 			(void) strlcat(new_auths, ",", MAXAUTHS);
807612578SGlenn.Faden@Sun.COM 		}
807712578SGlenn.Faden@Sun.COM 		(void) strlcat(new_auths, auth, MAXAUTHS);
807812578SGlenn.Faden@Sun.COM 		is_zone_admin = B_TRUE;
807912635SGlenn.Faden@Sun.COM 		new_auth_cnt--;
808012578SGlenn.Faden@Sun.COM 		right = strtok_r(NULL, ",", &lasts);
808112578SGlenn.Faden@Sun.COM 	}
808212578SGlenn.Faden@Sun.COM 
808312578SGlenn.Faden@Sun.COM 	/*
808412635SGlenn.Faden@Sun.COM 	 * Need to update the authorizations in user_attr unless
808512635SGlenn.Faden@Sun.COM 	 * the number of old and new authorizations is unchanged
808612635SGlenn.Faden@Sun.COM 	 * and the new auths are a substrings of the old auths.
808712635SGlenn.Faden@Sun.COM 	 *
808812578SGlenn.Faden@Sun.COM 	 * If the user's previous authorizations have changed
808912635SGlenn.Faden@Sun.COM 	 * execute the usermod progam to update them in user_attr.
809012578SGlenn.Faden@Sun.COM 	 */
809112635SGlenn.Faden@Sun.COM 	if ((new_auth_cnt != 0) ||
809212635SGlenn.Faden@Sun.COM 	    (strstr(old_auths, new_auth_start) == NULL)) {
809312578SGlenn.Faden@Sun.COM 		char    *cmdbuf;
809412578SGlenn.Faden@Sun.COM 		size_t  cmd_len;
809512578SGlenn.Faden@Sun.COM 
809612578SGlenn.Faden@Sun.COM 		update_profiles(rbac_profs, is_zone_admin);
809712578SGlenn.Faden@Sun.COM 		cmd_len = snprintf(NULL, 0, "%s -A \"%s\" -P \"%s\" %s",
809812578SGlenn.Faden@Sun.COM 		    auths_cmd, new_auths, rbac_profs, user) + 1;
809912578SGlenn.Faden@Sun.COM 		if ((cmdbuf = malloc(cmd_len)) == NULL) {
810012578SGlenn.Faden@Sun.COM 			return (Z_NOMEM);
810112578SGlenn.Faden@Sun.COM 		}
810212578SGlenn.Faden@Sun.COM 		(void) snprintf(cmdbuf, cmd_len, "%s -A \"%s\" -P \"%s\" %s",
810312578SGlenn.Faden@Sun.COM 		    auths_cmd, new_auths, rbac_profs, user);
810412578SGlenn.Faden@Sun.COM 		if (do_subproc(zonename, cmdbuf) != 0) {
810512578SGlenn.Faden@Sun.COM 			free(cmdbuf);
810612578SGlenn.Faden@Sun.COM 			return (Z_SYSTEM);
810712578SGlenn.Faden@Sun.COM 		}
810812578SGlenn.Faden@Sun.COM 		free(cmdbuf);
810912578SGlenn.Faden@Sun.COM 	}
811012578SGlenn.Faden@Sun.COM 
811112578SGlenn.Faden@Sun.COM 	return (Z_OK);
811212578SGlenn.Faden@Sun.COM }
811312578SGlenn.Faden@Sun.COM 
811412578SGlenn.Faden@Sun.COM int
zonecfg_authorize_users(zone_dochandle_t handle,char * zonename)811512578SGlenn.Faden@Sun.COM zonecfg_authorize_users(zone_dochandle_t handle, char *zonename)
811612578SGlenn.Faden@Sun.COM {
811712578SGlenn.Faden@Sun.COM 	xmlNodePtr cur;
811812578SGlenn.Faden@Sun.COM 	int err;
811912578SGlenn.Faden@Sun.COM 	char user[MAXUSERNAME];
812012578SGlenn.Faden@Sun.COM 	char auths[MAXAUTHS];
812112578SGlenn.Faden@Sun.COM 
812212578SGlenn.Faden@Sun.COM 	if ((err = operation_prep(handle)) != Z_OK)
812312578SGlenn.Faden@Sun.COM 		return (err);
812412578SGlenn.Faden@Sun.COM 
812512578SGlenn.Faden@Sun.COM 	cur = handle->zone_dh_cur;
812612578SGlenn.Faden@Sun.COM 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
812712578SGlenn.Faden@Sun.COM 		if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
812812578SGlenn.Faden@Sun.COM 			continue;
812912578SGlenn.Faden@Sun.COM 		if (fetchprop(cur, DTD_ATTR_USER, user,
813012578SGlenn.Faden@Sun.COM 		    sizeof (user)) != Z_OK)
813112578SGlenn.Faden@Sun.COM 			continue;
813212578SGlenn.Faden@Sun.COM 		if (fetchprop(cur, DTD_ATTR_AUTHS, auths,
813312578SGlenn.Faden@Sun.COM 		    sizeof (auths)) != Z_OK)
813412578SGlenn.Faden@Sun.COM 			continue;
813512578SGlenn.Faden@Sun.COM 		if (zonecfg_authorize_user_impl(handle, user, auths, zonename)
813612578SGlenn.Faden@Sun.COM 		    != Z_OK)
813712578SGlenn.Faden@Sun.COM 			return (Z_SYSTEM);
813812578SGlenn.Faden@Sun.COM 	}
813912578SGlenn.Faden@Sun.COM 	(void) zonecfg_remove_userauths(handle, "", "", B_TRUE);
814012578SGlenn.Faden@Sun.COM 
814112578SGlenn.Faden@Sun.COM 	return (Z_OK);
814212578SGlenn.Faden@Sun.COM }
814312578SGlenn.Faden@Sun.COM 
814412578SGlenn.Faden@Sun.COM int
zonecfg_deauthorize_user(zone_dochandle_t handle,char * user,char * zonename)814512578SGlenn.Faden@Sun.COM zonecfg_deauthorize_user(zone_dochandle_t handle, char *user, char *zonename)
814612578SGlenn.Faden@Sun.COM {
814712578SGlenn.Faden@Sun.COM 	return (zonecfg_authorize_user_impl(handle, user, "", zonename));
814812578SGlenn.Faden@Sun.COM }
814912578SGlenn.Faden@Sun.COM 
815012578SGlenn.Faden@Sun.COM int
zonecfg_deauthorize_users(zone_dochandle_t handle,char * zonename)815112578SGlenn.Faden@Sun.COM zonecfg_deauthorize_users(zone_dochandle_t handle, char *zonename)
815212578SGlenn.Faden@Sun.COM {
815312578SGlenn.Faden@Sun.COM 	xmlNodePtr cur;
815412578SGlenn.Faden@Sun.COM 	int err;
815512578SGlenn.Faden@Sun.COM 	char user[MAXUSERNAME];
815612578SGlenn.Faden@Sun.COM 
815712578SGlenn.Faden@Sun.COM 	if ((err = operation_prep(handle)) != Z_OK)
815812578SGlenn.Faden@Sun.COM 		return (err);
815912578SGlenn.Faden@Sun.COM 
816012578SGlenn.Faden@Sun.COM 	cur = handle->zone_dh_cur;
816112578SGlenn.Faden@Sun.COM 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
816212578SGlenn.Faden@Sun.COM 		if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
816312578SGlenn.Faden@Sun.COM 			continue;
816412578SGlenn.Faden@Sun.COM 		if (fetchprop(cur, DTD_ATTR_USER, user,
816512578SGlenn.Faden@Sun.COM 		    sizeof (user)) != Z_OK)
816612578SGlenn.Faden@Sun.COM 			continue;
816712578SGlenn.Faden@Sun.COM 		if ((err = zonecfg_deauthorize_user(handle, user,
816812578SGlenn.Faden@Sun.COM 		    zonename)) != Z_OK)
816912578SGlenn.Faden@Sun.COM 			return (err);
817012578SGlenn.Faden@Sun.COM 	}
817112578SGlenn.Faden@Sun.COM 	return (Z_OK);
817212578SGlenn.Faden@Sun.COM }
817312578SGlenn.Faden@Sun.COM 
817412578SGlenn.Faden@Sun.COM int
zonecfg_insert_userauths(zone_dochandle_t handle,char * user,char * zonename)817512578SGlenn.Faden@Sun.COM zonecfg_insert_userauths(zone_dochandle_t handle, char *user, char *zonename)
817612578SGlenn.Faden@Sun.COM {
817712578SGlenn.Faden@Sun.COM 	zone_userauths_t *new, **prev, *next;
817812578SGlenn.Faden@Sun.COM 
817912578SGlenn.Faden@Sun.COM 	prev = &handle->zone_dh_userauths;
818012578SGlenn.Faden@Sun.COM 	next = *prev;
818112578SGlenn.Faden@Sun.COM 	while (next) {
818212578SGlenn.Faden@Sun.COM 		if ((strncmp(next->user, user, MAXUSERNAME) == 0) &&
818312578SGlenn.Faden@Sun.COM 		    (strncmp(next->zonename, zonename,
818412578SGlenn.Faden@Sun.COM 		    ZONENAME_MAX) == 0)) {
818512578SGlenn.Faden@Sun.COM 			/*
818612578SGlenn.Faden@Sun.COM 			 * user is already in list
818712578SGlenn.Faden@Sun.COM 			 * which isn't supposed to happen!
818812578SGlenn.Faden@Sun.COM 			 */
818912578SGlenn.Faden@Sun.COM 			return (Z_OK);
819012578SGlenn.Faden@Sun.COM 		}
819112578SGlenn.Faden@Sun.COM 		prev = &next->next;
819212578SGlenn.Faden@Sun.COM 		next = *prev;
819312578SGlenn.Faden@Sun.COM 	}
819412578SGlenn.Faden@Sun.COM 	new = (zone_userauths_t *)malloc(sizeof (zone_userauths_t));
819512578SGlenn.Faden@Sun.COM 	if (new == NULL)
819612578SGlenn.Faden@Sun.COM 		return (Z_NOMEM);
819712578SGlenn.Faden@Sun.COM 
819812578SGlenn.Faden@Sun.COM 	(void) strlcpy(new->user, user, sizeof (new->user));
819912578SGlenn.Faden@Sun.COM 	(void) strlcpy(new->zonename, zonename, sizeof (new->zonename));
820012578SGlenn.Faden@Sun.COM 	new->next = NULL;
820112578SGlenn.Faden@Sun.COM 	*prev = new;
820212578SGlenn.Faden@Sun.COM 	return (Z_OK);
820312578SGlenn.Faden@Sun.COM }
820412578SGlenn.Faden@Sun.COM 
820512578SGlenn.Faden@Sun.COM int
zonecfg_remove_userauths(zone_dochandle_t handle,char * user,char * zonename,boolean_t deauthorize)820612578SGlenn.Faden@Sun.COM zonecfg_remove_userauths(zone_dochandle_t handle, char *user, char *zonename,
820712578SGlenn.Faden@Sun.COM 	boolean_t deauthorize)
820812578SGlenn.Faden@Sun.COM {
820912578SGlenn.Faden@Sun.COM 	zone_userauths_t *new, **prev, *next;
821012578SGlenn.Faden@Sun.COM 
821112578SGlenn.Faden@Sun.COM 	prev = &handle->zone_dh_userauths;
821212578SGlenn.Faden@Sun.COM 	next = *prev;
821312578SGlenn.Faden@Sun.COM 
821412578SGlenn.Faden@Sun.COM 	while (next) {
821512578SGlenn.Faden@Sun.COM 		if ((strlen(user) == 0 ||
821612578SGlenn.Faden@Sun.COM 		    strncmp(next->user, user, MAXUSERNAME) == 0) &&
821712578SGlenn.Faden@Sun.COM 		    (strlen(zonename) == 0 ||
821812578SGlenn.Faden@Sun.COM 		    (strncmp(next->zonename, zonename, ZONENAME_MAX) == 0))) {
821912578SGlenn.Faden@Sun.COM 			new = next;
822012578SGlenn.Faden@Sun.COM 			*prev = next->next;
822112578SGlenn.Faden@Sun.COM 			next =  *prev;
822212578SGlenn.Faden@Sun.COM 			if (deauthorize)
822312578SGlenn.Faden@Sun.COM 				(void) zonecfg_deauthorize_user(handle,
822412578SGlenn.Faden@Sun.COM 				    new->user, new->zonename);
822512578SGlenn.Faden@Sun.COM 			free(new);
822612578SGlenn.Faden@Sun.COM 			continue;
822712578SGlenn.Faden@Sun.COM 		}
822812578SGlenn.Faden@Sun.COM 		prev = &next->next;
822912578SGlenn.Faden@Sun.COM 		next = *prev;
823012578SGlenn.Faden@Sun.COM 	}
823112578SGlenn.Faden@Sun.COM 	return (Z_OK);
823212578SGlenn.Faden@Sun.COM }
8233