1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2014 Gary Mills
24  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
25  * Copyright (c) 2018, Joyent, Inc.
26  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
27  * Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
28  */
29 
30 #include <libsysevent.h>
31 #include <pthread.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <fnmatch.h>
35 #include <strings.h>
36 #include <unistd.h>
37 #include <assert.h>
38 #include <libgen.h>
39 #include <libintl.h>
40 #include <alloca.h>
41 #include <ctype.h>
42 #include <sys/acl.h>
43 #include <sys/stat.h>
44 #include <sys/brand.h>
45 #include <sys/mntio.h>
46 #include <sys/mnttab.h>
47 #include <sys/nvpair.h>
48 #include <sys/types.h>
49 #include <sys/sockio.h>
50 #include <sys/systeminfo.h>
51 #include <ftw.h>
52 #include <pool.h>
53 #include <libscf.h>
54 #include <libproc.h>
55 #include <sys/priocntl.h>
56 #include <libuutil.h>
57 #include <wait.h>
58 #include <bsm/adt.h>
59 #include <auth_attr.h>
60 #include <auth_list.h>
61 #include <secdb.h>
62 #include <user_attr.h>
63 #include <prof_attr.h>
64 #include <definit.h>
65 
66 #include <arpa/inet.h>
67 #include <netdb.h>
68 
69 #include <libxml/xmlmemory.h>
70 #include <libxml/parser.h>
71 
72 #include <libdevinfo.h>
73 #include <uuid/uuid.h>
74 #include <dirent.h>
75 #include <libbrand.h>
76 
77 #include <libzonecfg.h>
78 #include "zonecfg_impl.h"
79 
80 #define	_PATH_TMPFILE	"/zonecfg.XXXXXX"
81 #define	ZONE_CB_RETRY_COUNT		10
82 #define	ZONE_EVENT_PING_SUBCLASS	"ping"
83 #define	ZONE_EVENT_PING_PUBLISHER	"solaris"
84 
85 /* Hard-code the DTD element/attribute/entity names just once, here. */
86 #define	DTD_ELEM_ATTR		(const xmlChar *) "attr"
87 #define	DTD_ELEM_COMMENT	(const xmlChar *) "comment"
88 #define	DTD_ELEM_DEVICE		(const xmlChar *) "device"
89 #define	DTD_ELEM_FS		(const xmlChar *) "filesystem"
90 #define	DTD_ELEM_FSOPTION	(const xmlChar *) "fsoption"
91 #define	DTD_ELEM_NET		(const xmlChar *) "network"
92 #define	DTD_ELEM_RCTL		(const xmlChar *) "rctl"
93 #define	DTD_ELEM_RCTLVALUE	(const xmlChar *) "rctl-value"
94 #define	DTD_ELEM_ZONE		(const xmlChar *) "zone"
95 #define	DTD_ELEM_DATASET	(const xmlChar *) "dataset"
96 #define	DTD_ELEM_TMPPOOL	(const xmlChar *) "tmp_pool"
97 #define	DTD_ELEM_PSET		(const xmlChar *) "pset"
98 #define	DTD_ELEM_MCAP		(const xmlChar *) "mcap"
99 #define	DTD_ELEM_PACKAGE	(const xmlChar *) "package"
100 #define	DTD_ELEM_OBSOLETES	(const xmlChar *) "obsoletes"
101 #define	DTD_ELEM_DEV_PERM	(const xmlChar *) "dev-perm"
102 #define	DTD_ELEM_ADMIN		(const xmlChar *) "admin"
103 #define	DTD_ELEM_SECFLAGS	(const xmlChar *) "security-flags"
104 
105 #define	DTD_ATTR_ACTION		(const xmlChar *) "action"
106 #define	DTD_ATTR_ADDRESS	(const xmlChar *) "address"
107 #define	DTD_ATTR_ALLOWED_ADDRESS	(const xmlChar *) "allowed-address"
108 #define	DTD_ATTR_AUTOBOOT	(const xmlChar *) "autoboot"
109 #define	DTD_ATTR_IPTYPE		(const xmlChar *) "ip-type"
110 #define	DTD_ATTR_DEFROUTER	(const xmlChar *) "defrouter"
111 #define	DTD_ATTR_DIR		(const xmlChar *) "directory"
112 #define	DTD_ATTR_LIMIT		(const xmlChar *) "limit"
113 #define	DTD_ATTR_LIMITPRIV	(const xmlChar *) "limitpriv"
114 #define	DTD_ATTR_BOOTARGS	(const xmlChar *) "bootargs"
115 #define	DTD_ATTR_SCHED		(const xmlChar *) "scheduling-class"
116 #define	DTD_ATTR_MATCH		(const xmlChar *) "match"
117 #define	DTD_ATTR_NAME		(const xmlChar *) "name"
118 #define	DTD_ATTR_PHYSICAL	(const xmlChar *) "physical"
119 #define	DTD_ATTR_POOL		(const xmlChar *) "pool"
120 #define	DTD_ATTR_PRIV		(const xmlChar *) "priv"
121 #define	DTD_ATTR_RAW		(const xmlChar *) "raw"
122 #define	DTD_ATTR_SPECIAL	(const xmlChar *) "special"
123 #define	DTD_ATTR_TYPE		(const xmlChar *) "type"
124 #define	DTD_ATTR_VALUE		(const xmlChar *) "value"
125 #define	DTD_ATTR_ZONEPATH	(const xmlChar *) "zonepath"
126 #define	DTD_ATTR_NCPU_MIN	(const xmlChar *) "ncpu_min"
127 #define	DTD_ATTR_NCPU_MAX	(const xmlChar *) "ncpu_max"
128 #define	DTD_ATTR_IMPORTANCE	(const xmlChar *) "importance"
129 #define	DTD_ATTR_PHYSCAP	(const xmlChar *) "physcap"
130 #define	DTD_ATTR_VERSION	(const xmlChar *) "version"
131 #define	DTD_ATTR_ID		(const xmlChar *) "id"
132 #define	DTD_ATTR_UID		(const xmlChar *) "uid"
133 #define	DTD_ATTR_GID		(const xmlChar *) "gid"
134 #define	DTD_ATTR_MODE		(const xmlChar *) "mode"
135 #define	DTD_ATTR_ACL		(const xmlChar *) "acl"
136 #define	DTD_ATTR_BRAND		(const xmlChar *) "brand"
137 #define	DTD_ATTR_HOSTID		(const xmlChar *) "hostid"
138 #define	DTD_ATTR_USER		(const xmlChar *) "user"
139 #define	DTD_ATTR_AUTHS		(const xmlChar *) "auths"
140 #define	DTD_ATTR_FS_ALLOWED	(const xmlChar *) "fs-allowed"
141 #define	DTD_ATTR_DEFAULT	(const xmlChar *) "default"
142 #define	DTD_ATTR_LOWER		(const xmlChar *) "lower"
143 #define	DTD_ATTR_UPPER		(const xmlChar *) "upper"
144 
145 
146 #define	DTD_ENTITY_BOOLEAN	"boolean"
147 #define	DTD_ENTITY_DEVPATH	"devpath"
148 #define	DTD_ENTITY_DRIVER	"driver"
149 #define	DTD_ENTITY_DRVMIN	"drv_min"
150 #define	DTD_ENTITY_FALSE	"false"
151 #define	DTD_ENTITY_INT		"int"
152 #define	DTD_ENTITY_STRING	"string"
153 #define	DTD_ENTITY_TRUE		"true"
154 #define	DTD_ENTITY_UINT		"uint"
155 
156 #define	DTD_ENTITY_BOOL_LEN	6	/* "false" */
157 
158 #define	ATTACH_FORCED	"SUNWattached.xml"
159 
160 #define	TMP_POOL_NAME	"SUNWtmp_%s"
161 #define	MAX_TMP_POOL_NAME	(ZONENAME_MAX + 9)
162 #define	RCAP_SERVICE	"system/rcap:default"
163 #define	POOLD_SERVICE	"system/pools/dynamic:default"
164 
165 /*
166  * rctl alias definitions
167  *
168  * This holds the alias, the full rctl name, the default priv value, action
169  * and lower limit.  The functions that handle rctl aliases step through
170  * this table, matching on the alias, and using the full values for setting
171  * the rctl entry as well the limit for validation.
172  */
173 static struct alias {
174 	char *shortname;
175 	char *realname;
176 	char *priv;
177 	char *action;
178 	uint64_t low_limit;
179 } aliases[] = {
180 	{ALIAS_MAXLWPS, "zone.max-lwps", "privileged", "deny", 100},
181 	{ALIAS_MAXSHMMEM, "zone.max-shm-memory", "privileged", "deny", 0},
182 	{ALIAS_MAXSHMIDS, "zone.max-shm-ids", "privileged", "deny", 0},
183 	{ALIAS_MAXMSGIDS, "zone.max-msg-ids", "privileged", "deny", 0},
184 	{ALIAS_MAXSEMIDS, "zone.max-sem-ids", "privileged", "deny", 0},
185 	{ALIAS_MAXLOCKEDMEM, "zone.max-locked-memory", "privileged", "deny", 0},
186 	{ALIAS_MAXSWAP, "zone.max-swap", "privileged", "deny", 0},
187 	{ALIAS_SHARES, "zone.cpu-shares", "privileged", "none", 0},
188 	{ALIAS_CPUCAP, "zone.cpu-cap", "privileged", "deny", 0},
189 	{ALIAS_MAXPROCS, "zone.max-processes", "privileged", "deny", 100},
190 	{NULL, NULL, NULL, NULL, 0}
191 };
192 
193 /*
194  * Structure for applying rctls to a running zone.  It allows important
195  * process values to be passed together easily.
196  */
197 typedef struct pr_info_handle {
198 	struct ps_prochandle *pr;
199 	pid_t pid;
200 } pr_info_handle_t;
201 
202 struct zone_dochandle {
203 	char		*zone_dh_rootdir;
204 	xmlDocPtr	zone_dh_doc;
205 	xmlNodePtr	zone_dh_cur;
206 	xmlNodePtr	zone_dh_top;
207 	boolean_t	zone_dh_newzone;
208 	boolean_t	zone_dh_snapshot;
209 	boolean_t	zone_dh_sw_inv;
210 	zone_userauths_t	*zone_dh_userauths;
211 	char		zone_dh_delete_name[ZONENAME_MAX];
212 };
213 
214 struct znotify {
215 	void * zn_private;
216 	evchan_t *zn_eventchan;
217 	int (*zn_callback)(const  char *zonename, zoneid_t zid,
218 	    const char *newstate, const char *oldstate, hrtime_t when, void *p);
219 	pthread_mutex_t zn_mutex;
220 	pthread_cond_t zn_cond;
221 	pthread_mutex_t zn_bigmutex;
222 	volatile enum {ZN_UNLOCKED, ZN_LOCKED, ZN_PING_INFLIGHT,
223 	    ZN_PING_RECEIVED} zn_state;
224 	char zn_subscriber_id[MAX_SUBID_LEN];
225 	volatile boolean_t zn_failed;
226 	int zn_failure_count;
227 };
228 
229 /* used to track nested zone-lock operations */
230 static int zone_lock_cnt = 0;
231 
232 /* used to communicate lock status to children */
233 #define	LOCK_ENV_VAR	"_ZONEADM_LOCK_HELD"
234 static char zoneadm_lock_held[] = LOCK_ENV_VAR"=1";
235 static char zoneadm_lock_not_held[] = LOCK_ENV_VAR"=0";
236 
237 char *zonecfg_root = "";
238 
239 /*
240  * For functions which return int, which is most of the functions herein,
241  * the return values should be from the Z_foo set defined in <libzonecfg.h>.
242  * In some instances, we take pains mapping some libc errno values to Z_foo
243  * values from this set.
244  */
245 
246 /*
247  * Set the root (/) path for all zonecfg configuration files.  This is a
248  * private interface used by Live Upgrade extensions to access zone
249  * configuration inside mounted alternate boot environments.
250  * This interface is also used by zoneadm mount and unmount subcommands.
251  */
252 void
253 zonecfg_set_root(const char *rootpath)
254 {
255 	if (*zonecfg_root != '\0')
256 		free(zonecfg_root);
257 	if (rootpath == NULL || rootpath[0] == '\0' || rootpath[1] == '\0' ||
258 	    (zonecfg_root = strdup(rootpath)) == NULL)
259 		zonecfg_root = "";
260 }
261 
262 const char *
263 zonecfg_get_root(void)
264 {
265 	return (zonecfg_root);
266 }
267 
268 boolean_t
269 zonecfg_in_alt_root(void)
270 {
271 	return (*zonecfg_root != '\0');
272 }
273 
274 /*
275  * Callers of the _file_path() functions are expected to have the second
276  * parameter be a (char foo[MAXPATHLEN]).
277  */
278 
279 static boolean_t
280 config_file_path(const char *zonename, char *answer)
281 {
282 	return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root,
283 	    ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN);
284 }
285 
286 static boolean_t
287 snap_file_path(const char *zonename, char *answer)
288 {
289 	return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml",
290 	    zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN);
291 }
292 
293 /*ARGSUSED*/
294 static void
295 zonecfg_error_func(void *ctx, const char *msg, ...)
296 {
297 	/*
298 	 * This function does nothing by design.  Its purpose is to prevent
299 	 * libxml from dumping unwanted messages to stdout/stderr.
300 	 */
301 }
302 
303 zone_dochandle_t
304 zonecfg_init_handle(void)
305 {
306 	zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle));
307 	if (handle == NULL) {
308 		errno = Z_NOMEM;
309 		return (NULL);
310 	}
311 
312 	/* generic libxml initialization */
313 	(void) xmlLineNumbersDefault(1);
314 	xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
315 	xmlDoValidityCheckingDefaultValue = 1;
316 	(void) xmlKeepBlanksDefault(0);
317 	xmlGetWarningsDefaultValue = 0;
318 	xmlSetGenericErrorFunc(NULL, zonecfg_error_func);
319 
320 	return (handle);
321 }
322 
323 int
324 zonecfg_check_handle(zone_dochandle_t handle)
325 {
326 	if (handle == NULL || handle->zone_dh_doc == NULL)
327 		return (Z_BAD_HANDLE);
328 	return (Z_OK);
329 }
330 
331 void
332 zonecfg_fini_handle(zone_dochandle_t handle)
333 {
334 	if (zonecfg_check_handle(handle) == Z_OK)
335 		xmlFreeDoc(handle->zone_dh_doc);
336 	if (handle != NULL)
337 		free(handle);
338 }
339 
340 static int
341 zonecfg_destroy_impl(char *filename)
342 {
343 	if (unlink(filename) == -1) {
344 		if (errno == EACCES)
345 			return (Z_ACCES);
346 		if (errno == ENOENT)
347 			return (Z_NO_ZONE);
348 		return (Z_MISC_FS);
349 	}
350 	return (Z_OK);
351 }
352 
353 int
354 zonecfg_destroy(const char *zonename, boolean_t force)
355 {
356 	char path[MAXPATHLEN];
357 	struct zoneent ze;
358 	int err, state_err;
359 	zone_state_t state;
360 
361 	if (!config_file_path(zonename, path))
362 		return (Z_MISC_FS);
363 
364 	state_err = zone_get_state((char *)zonename, &state);
365 	err = access(path, W_OK);
366 
367 	/*
368 	 * If there is no file, and no index entry, reliably indicate that no
369 	 * such zone exists.
370 	 */
371 	if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT))
372 		return (Z_NO_ZONE);
373 
374 	/*
375 	 * Handle any other filesystem related errors (except if the XML
376 	 * file is missing, which we treat silently), unless we're forcing,
377 	 * in which case we plow on.
378 	 */
379 	if (err == -1 && errno != ENOENT) {
380 		if (errno == EACCES)
381 			return (Z_ACCES);
382 		else if (!force)
383 			return (Z_MISC_FS);
384 	}
385 
386 	if (state > ZONE_STATE_INSTALLED)
387 		return (Z_BAD_ZONE_STATE);
388 
389 	if (!force && state > ZONE_STATE_CONFIGURED)
390 		return (Z_BAD_ZONE_STATE);
391 
392 	/*
393 	 * Index deletion succeeds even if the entry doesn't exist.  So this
394 	 * will fail only if we've had some more severe problem.
395 	 */
396 	bzero(&ze, sizeof (ze));
397 	(void) strlcpy(ze.zone_name, zonename, sizeof (ze.zone_name));
398 	if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK)
399 		if (!force)
400 			return (err);
401 
402 	err = zonecfg_destroy_impl(path);
403 
404 	/*
405 	 * Treat failure to find the XML file silently, since, well, it's
406 	 * gone, and with the index file cleaned up, we're done.
407 	 */
408 	if (err == Z_OK || err == Z_NO_ZONE)
409 		return (Z_OK);
410 	return (err);
411 }
412 
413 int
414 zonecfg_destroy_snapshot(const char *zonename)
415 {
416 	char path[MAXPATHLEN];
417 
418 	if (!snap_file_path(zonename, path))
419 		return (Z_MISC_FS);
420 	return (zonecfg_destroy_impl(path));
421 }
422 
423 static int
424 getroot(zone_dochandle_t handle, xmlNodePtr *root)
425 {
426 	if (zonecfg_check_handle(handle) == Z_BAD_HANDLE)
427 		return (Z_BAD_HANDLE);
428 
429 	*root = xmlDocGetRootElement(handle->zone_dh_doc);
430 
431 	if (*root == NULL)
432 		return (Z_EMPTY_DOCUMENT);
433 
434 	if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE))
435 		return (Z_WRONG_DOC_TYPE);
436 
437 	return (Z_OK);
438 }
439 
440 static int
441 operation_prep(zone_dochandle_t handle)
442 {
443 	xmlNodePtr root;
444 	int err;
445 
446 	if ((err = getroot(handle, &root)) != 0)
447 		return (err);
448 
449 	handle->zone_dh_cur = root;
450 	handle->zone_dh_top = root;
451 	return (Z_OK);
452 }
453 
454 static int
455 fetchprop(xmlNodePtr cur, const xmlChar *propname, char *dst, size_t dstsize)
456 {
457 	xmlChar *property;
458 	size_t srcsize;
459 
460 	if ((property = xmlGetProp(cur, propname)) == NULL)
461 		return (Z_BAD_PROPERTY);
462 	srcsize = strlcpy(dst, (char *)property, dstsize);
463 	xmlFree(property);
464 	if (srcsize >= dstsize)
465 		return (Z_TOO_BIG);
466 	return (Z_OK);
467 }
468 
469 static int
470 fetch_alloc_prop(xmlNodePtr cur, const xmlChar *propname, char **dst)
471 {
472 	xmlChar *property;
473 
474 	if ((property = xmlGetProp(cur, propname)) == NULL)
475 		return (Z_BAD_PROPERTY);
476 	if ((*dst = strdup((char *)property)) == NULL) {
477 		xmlFree(property);
478 		return (Z_NOMEM);
479 	}
480 	xmlFree(property);
481 	return (Z_OK);
482 }
483 
484 static int
485 getrootattr(zone_dochandle_t handle, const xmlChar *propname,
486     char *propval, size_t propsize)
487 {
488 	xmlNodePtr root;
489 	int err;
490 
491 	if ((err = getroot(handle, &root)) != 0)
492 		return (err);
493 
494 	return (fetchprop(root, propname, propval, propsize));
495 }
496 
497 static int
498 get_alloc_rootattr(zone_dochandle_t handle, const xmlChar *propname,
499     char **propval)
500 {
501 	xmlNodePtr root;
502 	int err;
503 
504 	if ((err = getroot(handle, &root)) != 0)
505 		return (err);
506 
507 	return (fetch_alloc_prop(root, propname, propval));
508 }
509 
510 static int
511 setrootattr(zone_dochandle_t handle, const xmlChar *propname,
512     const char *propval)
513 {
514 	int err;
515 	xmlNodePtr root;
516 
517 	if ((err = getroot(handle, &root)) != Z_OK)
518 		return (err);
519 
520 	/*
521 	 * If we get a null propval remove the property (ignore return since it
522 	 * may not be set to begin with).
523 	 */
524 	if (propval == NULL) {
525 		(void) xmlUnsetProp(root, propname);
526 	} else {
527 		if (xmlSetProp(root, propname, (const xmlChar *) propval)
528 		    == NULL)
529 			return (Z_INVAL);
530 	}
531 	return (Z_OK);
532 }
533 
534 static void
535 addcomment(zone_dochandle_t handle, const char *comment)
536 {
537 	xmlNodePtr node;
538 	node = xmlNewComment((xmlChar *) comment);
539 
540 	if (node != NULL)
541 		(void) xmlAddPrevSibling(handle->zone_dh_top, node);
542 }
543 
544 static void
545 stripcomments(zone_dochandle_t handle)
546 {
547 	xmlDocPtr top;
548 	xmlNodePtr child, next;
549 
550 	top = handle->zone_dh_doc;
551 	for (child = top->xmlChildrenNode; child != NULL; child = next) {
552 		next = child->next;
553 		if (child->name == NULL)
554 			continue;
555 		if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) {
556 			next = child->next;
557 			xmlUnlinkNode(child);
558 			xmlFreeNode(child);
559 		}
560 	}
561 }
562 
563 static void
564 strip_sw_inv(zone_dochandle_t handle)
565 {
566 	xmlNodePtr root, child, next;
567 
568 	root = xmlDocGetRootElement(handle->zone_dh_doc);
569 	for (child = root->xmlChildrenNode; child != NULL; child = next) {
570 		next = child->next;
571 		if (child->name == NULL)
572 			continue;
573 		if (xmlStrcmp(child->name, DTD_ELEM_PACKAGE) == 0) {
574 			next = child->next;
575 			xmlUnlinkNode(child);
576 			xmlFreeNode(child);
577 		}
578 	}
579 }
580 
581 static int
582 zonecfg_get_handle_impl(const char *zonename, const char *filename,
583     zone_dochandle_t handle)
584 {
585 	xmlValidCtxtPtr cvp;
586 	struct stat statbuf;
587 	int valid;
588 
589 	if (zonename == NULL)
590 		return (Z_NO_ZONE);
591 
592 	if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) {
593 		/* distinguish file not found vs. found but not parsed */
594 		if (stat(filename, &statbuf) == 0)
595 			return (Z_INVALID_DOCUMENT);
596 		return (Z_NO_ZONE);
597 	}
598 	if ((cvp = xmlNewValidCtxt()) == NULL)
599 		return (Z_NOMEM);
600 	cvp->error = zonecfg_error_func;
601 	cvp->warning = zonecfg_error_func;
602 	valid = xmlValidateDocument(cvp, handle->zone_dh_doc);
603 	xmlFreeValidCtxt(cvp);
604 	if (valid == 0)
605 		return (Z_INVALID_DOCUMENT);
606 
607 	/* delete any comments such as inherited Sun copyright / ident str */
608 	stripcomments(handle);
609 	return (Z_OK);
610 }
611 
612 int
613 zonecfg_get_handle(const char *zonename, zone_dochandle_t handle)
614 {
615 	char path[MAXPATHLEN];
616 
617 	if (!config_file_path(zonename, path))
618 		return (Z_MISC_FS);
619 	handle->zone_dh_newzone = B_FALSE;
620 
621 	return (zonecfg_get_handle_impl(zonename, path, handle));
622 }
623 
624 int
625 zonecfg_get_attach_handle(const char *path, const char *fname,
626     const char *zonename, boolean_t preserve_sw, zone_dochandle_t handle)
627 {
628 	char		migpath[MAXPATHLEN];
629 	int		err;
630 	struct stat	buf;
631 
632 	if (snprintf(migpath, sizeof (migpath), "%s/root", path) >=
633 	    sizeof (migpath))
634 		return (Z_NOMEM);
635 
636 	if (stat(migpath, &buf) == -1 || !S_ISDIR(buf.st_mode))
637 		return (Z_NO_ZONE);
638 
639 	if (snprintf(migpath, sizeof (migpath), "%s/%s", path, fname) >=
640 	    sizeof (migpath))
641 		return (Z_NOMEM);
642 
643 	if ((err = zonecfg_get_handle_impl(zonename, migpath, handle)) != Z_OK)
644 		return (err);
645 
646 	if (!preserve_sw)
647 		strip_sw_inv(handle);
648 
649 	handle->zone_dh_newzone = B_TRUE;
650 	if ((err = setrootattr(handle, DTD_ATTR_ZONEPATH, path)) != Z_OK)
651 		return (err);
652 
653 	return (setrootattr(handle, DTD_ATTR_NAME, zonename));
654 }
655 
656 int
657 zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle)
658 {
659 	char path[MAXPATHLEN];
660 
661 	if (!snap_file_path(zonename, path))
662 		return (Z_MISC_FS);
663 	handle->zone_dh_newzone = B_FALSE;
664 	return (zonecfg_get_handle_impl(zonename, path, handle));
665 }
666 
667 int
668 zonecfg_get_template_handle(const char *template, const char *zonename,
669     zone_dochandle_t handle)
670 {
671 	char path[MAXPATHLEN];
672 	int err;
673 
674 	if (!config_file_path(template, path))
675 		return (Z_MISC_FS);
676 
677 	if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK)
678 		return (err);
679 	handle->zone_dh_newzone = B_TRUE;
680 	return (setrootattr(handle, DTD_ATTR_NAME, zonename));
681 }
682 
683 int
684 zonecfg_get_xml_handle(const char *path, zone_dochandle_t handle)
685 {
686 	struct stat buf;
687 	int err;
688 
689 	if (stat(path, &buf) == -1)
690 		return (Z_MISC_FS);
691 
692 	if ((err = zonecfg_get_handle_impl("xml", path, handle)) != Z_OK)
693 		return (err);
694 	handle->zone_dh_newzone = B_TRUE;
695 	return (Z_OK);
696 }
697 
698 /*
699  * Initialize two handles from the manifest read on fd.  The rem_handle
700  * is initialized from the input file, including the sw inventory.  The
701  * local_handle is initialized with the same zone configuration but with
702  * no sw inventory.
703  */
704 int
705 zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle,
706     zone_dochandle_t rem_handle)
707 {
708 	xmlValidCtxtPtr cvp;
709 	int valid;
710 
711 	/* load the manifest into the handle for the remote system */
712 	if ((rem_handle->zone_dh_doc = xmlReadFd(fd, NULL, NULL, 0)) == NULL) {
713 		return (Z_INVALID_DOCUMENT);
714 	}
715 	if ((cvp = xmlNewValidCtxt()) == NULL)
716 		return (Z_NOMEM);
717 	cvp->error = zonecfg_error_func;
718 	cvp->warning = zonecfg_error_func;
719 	valid = xmlValidateDocument(cvp, rem_handle->zone_dh_doc);
720 	xmlFreeValidCtxt(cvp);
721 	if (valid == 0)
722 		return (Z_INVALID_DOCUMENT);
723 
724 	/* delete any comments such as inherited Sun copyright / ident str */
725 	stripcomments(rem_handle);
726 
727 	rem_handle->zone_dh_newzone = B_TRUE;
728 	rem_handle->zone_dh_sw_inv = B_TRUE;
729 
730 	/*
731 	 * Now use the remote system handle to generate a local system handle
732 	 * with an identical zones configuration but no sw inventory.
733 	 */
734 	if ((local_handle->zone_dh_doc = xmlCopyDoc(rem_handle->zone_dh_doc,
735 	    1)) == NULL) {
736 		return (Z_INVALID_DOCUMENT);
737 	}
738 
739 	/*
740 	 * We need to re-run xmlValidateDocument on local_handle to properly
741 	 * update the in-core representation of the configuration.
742 	 */
743 	if ((cvp = xmlNewValidCtxt()) == NULL)
744 		return (Z_NOMEM);
745 	cvp->error = zonecfg_error_func;
746 	cvp->warning = zonecfg_error_func;
747 	valid = xmlValidateDocument(cvp, local_handle->zone_dh_doc);
748 	xmlFreeValidCtxt(cvp);
749 	if (valid == 0)
750 		return (Z_INVALID_DOCUMENT);
751 
752 	strip_sw_inv(local_handle);
753 
754 	local_handle->zone_dh_newzone = B_TRUE;
755 	local_handle->zone_dh_sw_inv = B_FALSE;
756 
757 	return (Z_OK);
758 }
759 
760 static boolean_t
761 is_renaming(zone_dochandle_t handle)
762 {
763 	if (handle->zone_dh_newzone)
764 		return (B_FALSE);
765 	if (strlen(handle->zone_dh_delete_name) > 0)
766 		return (B_TRUE);
767 	return (B_FALSE);
768 }
769 
770 static boolean_t
771 is_new(zone_dochandle_t handle)
772 {
773 	return (handle->zone_dh_newzone || handle->zone_dh_snapshot);
774 }
775 
776 static boolean_t
777 is_snapshot(zone_dochandle_t handle)
778 {
779 	return (handle->zone_dh_snapshot);
780 }
781 
782 /*
783  * It would be great to be able to use libc's ctype(3c) macros, but we
784  * can't, as they are locale sensitive, and it would break our limited thread
785  * safety if this routine had to change the app locale on the fly.
786  */
787 int
788 zonecfg_validate_zonename(const char *zone)
789 {
790 	int i;
791 
792 	if (strcmp(zone, GLOBAL_ZONENAME) == 0)
793 		return (Z_BOGUS_ZONE_NAME);
794 
795 	if (strlen(zone) >= ZONENAME_MAX)
796 		return (Z_BOGUS_ZONE_NAME);
797 
798 	if (!((zone[0] >= 'a' && zone[0] <= 'z') ||
799 	    (zone[0] >= 'A' && zone[0] <= 'Z') ||
800 	    (zone[0] >= '0' && zone[0] <= '9')))
801 		return (Z_BOGUS_ZONE_NAME);
802 
803 	for (i = 1; zone[i] != '\0'; i++) {
804 		if (!((zone[i] >= 'a' && zone[i] <= 'z') ||
805 		    (zone[i] >= 'A' && zone[i] <= 'Z') ||
806 		    (zone[i] >= '0' && zone[i] <= '9') ||
807 		    (zone[i] == '-') || (zone[i] == '_') || (zone[i] == '.')))
808 			return (Z_BOGUS_ZONE_NAME);
809 	}
810 
811 	return (Z_OK);
812 }
813 
814 /*
815  * Changing the zone name requires us to track both the old and new
816  * name of the zone until commit time.
817  */
818 int
819 zonecfg_get_name(zone_dochandle_t handle, char *name, size_t namesize)
820 {
821 	return (getrootattr(handle, DTD_ATTR_NAME, name, namesize));
822 }
823 
824 static int
825 insert_admins(zone_dochandle_t handle, char *zonename)
826 {
827 	int err;
828 	struct zone_admintab admintab;
829 
830 	if ((err = zonecfg_setadminent(handle)) != Z_OK) {
831 		return (err);
832 	}
833 	while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
834 		err = zonecfg_insert_userauths(handle,
835 		    admintab.zone_admin_user, zonename);
836 		if (err != Z_OK) {
837 			(void) zonecfg_endadminent(handle);
838 			return (err);
839 		}
840 	}
841 	(void) zonecfg_endadminent(handle);
842 	return (Z_OK);
843 }
844 
845 int
846 zonecfg_set_name(zone_dochandle_t handle, char *name)
847 {
848 	zone_state_t state;
849 	char curname[ZONENAME_MAX], old_delname[ZONENAME_MAX];
850 	int err;
851 
852 	if ((err = getrootattr(handle, DTD_ATTR_NAME, curname,
853 	    sizeof (curname))) != Z_OK)
854 		return (err);
855 
856 	if (strcmp(name, curname) == 0)
857 		return (Z_OK);
858 
859 	/*
860 	 * Switching zone names to one beginning with SUNW is not permitted.
861 	 */
862 	if (strncmp(name, "SUNW", 4) == 0)
863 		return (Z_BOGUS_ZONE_NAME);
864 
865 	if ((err = zonecfg_validate_zonename(name)) != Z_OK)
866 		return (err);
867 
868 	/*
869 	 * Setting the name back to the original name (effectively a revert of
870 	 * the name) is fine.  But if we carry on, we'll falsely identify the
871 	 * name as "in use," so special case here.
872 	 */
873 	if (strcmp(name, handle->zone_dh_delete_name) == 0) {
874 		err = setrootattr(handle, DTD_ATTR_NAME, name);
875 		handle->zone_dh_delete_name[0] = '\0';
876 		return (err);
877 	}
878 
879 	/* Check to see if new name chosen is already in use */
880 	if (zone_get_state(name, &state) != Z_NO_ZONE)
881 		return (Z_NAME_IN_USE);
882 
883 	/*
884 	 * If this isn't already "new" or in a renaming transition, then
885 	 * we're initiating a rename here; so stash the "delete name"
886 	 * (i.e. the name of the zone we'll be removing) for the rename.
887 	 */
888 	(void) strlcpy(old_delname, handle->zone_dh_delete_name,
889 	    sizeof (old_delname));
890 	if (!is_new(handle) && !is_renaming(handle)) {
891 		/*
892 		 * Name change is allowed only when the zone we're altering
893 		 * is not ready or running.
894 		 */
895 		err = zone_get_state(curname, &state);
896 		if (err == Z_OK) {
897 			if (state > ZONE_STATE_INSTALLED)
898 				return (Z_BAD_ZONE_STATE);
899 		} else if (err != Z_NO_ZONE) {
900 			return (err);
901 		}
902 
903 		(void) strlcpy(handle->zone_dh_delete_name, curname,
904 		    sizeof (handle->zone_dh_delete_name));
905 		assert(is_renaming(handle));
906 	} else if (is_renaming(handle)) {
907 		err = zone_get_state(handle->zone_dh_delete_name, &state);
908 		if (err == Z_OK) {
909 			if (state > ZONE_STATE_INSTALLED)
910 				return (Z_BAD_ZONE_STATE);
911 		} else if (err != Z_NO_ZONE) {
912 			return (err);
913 		}
914 	}
915 
916 	if ((err = setrootattr(handle, DTD_ATTR_NAME, name)) != Z_OK) {
917 		/*
918 		 * Restore the deletename to whatever it was at the
919 		 * top of the routine, since we've had a failure.
920 		 */
921 		(void) strlcpy(handle->zone_dh_delete_name, old_delname,
922 		    sizeof (handle->zone_dh_delete_name));
923 		return (err);
924 	}
925 
926 	/*
927 	 * Record the old admins from the old zonename
928 	 * so that they can be deleted when the operation is committed.
929 	 */
930 	if ((err = insert_admins(handle, curname)) != Z_OK)
931 		return (err);
932 	else
933 		return (Z_OK);
934 }
935 
936 int
937 zonecfg_get_zonepath(zone_dochandle_t handle, char *path, size_t pathsize)
938 {
939 	size_t len;
940 
941 	if ((len = strlcpy(path, zonecfg_root, pathsize)) >= pathsize)
942 		return (Z_TOO_BIG);
943 	return (getrootattr(handle, DTD_ATTR_ZONEPATH, path + len,
944 	    pathsize - len));
945 }
946 
947 int
948 zonecfg_set_zonepath(zone_dochandle_t handle, char *zonepath)
949 {
950 	size_t len;
951 	char *modpath, *copy_mp, *curr_mp;	/* modified path ptrs */
952 	char last_copied;
953 	int ret;
954 
955 	/*
956 	 * Collapse multiple contiguous slashes and remove trailing slash.
957 	 */
958 	modpath = strdup(zonepath);
959 	if (modpath == NULL)
960 		return (Z_NOMEM);
961 	last_copied = '\0';
962 	for (copy_mp = curr_mp = modpath; *curr_mp != '\0'; curr_mp++) {
963 		if (*curr_mp != '/' || last_copied != '/') {
964 			last_copied = *copy_mp = *curr_mp;
965 			copy_mp++;
966 		}
967 	}
968 	if (last_copied == '/')
969 		copy_mp--;
970 	*copy_mp = '\0';
971 
972 	/*
973 	 * The user deals in absolute paths in the running global zone, but the
974 	 * internal configuration files deal with boot environment relative
975 	 * paths.  Strip out the alternate root when specified.
976 	 */
977 	len = strlen(zonecfg_root);
978 	if (strncmp(modpath, zonecfg_root, len) != 0 || modpath[len] != '/') {
979 		free(modpath);
980 		return (Z_BAD_PROPERTY);
981 	}
982 	curr_mp = modpath + len;
983 	ret = setrootattr(handle, DTD_ATTR_ZONEPATH, curr_mp);
984 	free(modpath);
985 	return (ret);
986 }
987 
988 static int
989 i_zonecfg_get_brand(zone_dochandle_t handle, char *brand, size_t brandsize,
990     boolean_t default_query)
991 {
992 	int ret, sz;
993 
994 	ret = getrootattr(handle, DTD_ATTR_BRAND, brand, brandsize);
995 
996 	/*
997 	 * If the lookup failed, or succeeded in finding a non-null brand
998 	 * string then return.
999 	 */
1000 	if (ret != Z_OK || brand[0] != '\0')
1001 		return (ret);
1002 
1003 	if (!default_query) {
1004 		/* If the zone has no brand, it is the default brand. */
1005 		return (zonecfg_default_brand(brand, brandsize));
1006 	}
1007 
1008 	/* if SUNWdefault didn't specify a brand, fallback to "native" */
1009 	sz = strlcpy(brand, NATIVE_BRAND_NAME, brandsize);
1010 	if (sz >= brandsize)
1011 		return (Z_TOO_BIG);
1012 	return (Z_OK);
1013 }
1014 
1015 int
1016 zonecfg_get_brand(zone_dochandle_t handle, char *brand, size_t brandsize)
1017 {
1018 	return (i_zonecfg_get_brand(handle, brand, brandsize, B_FALSE));
1019 }
1020 
1021 int
1022 zonecfg_set_brand(zone_dochandle_t handle, char *brand)
1023 {
1024 	return (setrootattr(handle, DTD_ATTR_BRAND, brand));
1025 }
1026 
1027 int
1028 zonecfg_get_autoboot(zone_dochandle_t handle, boolean_t *autoboot)
1029 {
1030 	char autobootstr[DTD_ENTITY_BOOL_LEN];
1031 	int ret;
1032 
1033 	if ((ret = getrootattr(handle, DTD_ATTR_AUTOBOOT, autobootstr,
1034 	    sizeof (autobootstr))) != Z_OK)
1035 		return (ret);
1036 
1037 	if (strcmp(autobootstr, DTD_ENTITY_TRUE) == 0)
1038 		*autoboot = B_TRUE;
1039 	else if (strcmp(autobootstr, DTD_ENTITY_FALSE) == 0)
1040 		*autoboot = B_FALSE;
1041 	else
1042 		ret = Z_BAD_PROPERTY;
1043 	return (ret);
1044 }
1045 
1046 int
1047 zonecfg_set_autoboot(zone_dochandle_t handle, boolean_t autoboot)
1048 {
1049 	return (setrootattr(handle, DTD_ATTR_AUTOBOOT,
1050 	    autoboot ? DTD_ENTITY_TRUE : DTD_ENTITY_FALSE));
1051 }
1052 
1053 int
1054 zonecfg_get_pool(zone_dochandle_t handle, char *pool, size_t poolsize)
1055 {
1056 	return (getrootattr(handle, DTD_ATTR_POOL, pool, poolsize));
1057 }
1058 
1059 int
1060 zonecfg_set_pool(zone_dochandle_t handle, char *pool)
1061 {
1062 	return (setrootattr(handle, DTD_ATTR_POOL, pool));
1063 }
1064 
1065 int
1066 zonecfg_get_limitpriv(zone_dochandle_t handle, char **limitpriv)
1067 {
1068 	return (get_alloc_rootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv));
1069 }
1070 
1071 int
1072 zonecfg_set_limitpriv(zone_dochandle_t handle, char *limitpriv)
1073 {
1074 	return (setrootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv));
1075 }
1076 
1077 int
1078 zonecfg_get_bootargs(zone_dochandle_t handle, char *bargs, size_t bargssize)
1079 {
1080 	return (getrootattr(handle, DTD_ATTR_BOOTARGS, bargs, bargssize));
1081 }
1082 
1083 int
1084 zonecfg_set_bootargs(zone_dochandle_t handle, char *bargs)
1085 {
1086 	return (setrootattr(handle, DTD_ATTR_BOOTARGS, bargs));
1087 }
1088 
1089 int
1090 zonecfg_get_sched_class(zone_dochandle_t handle, char *sched, size_t schedsize)
1091 {
1092 	return (getrootattr(handle, DTD_ATTR_SCHED, sched, schedsize));
1093 }
1094 
1095 int
1096 zonecfg_set_sched(zone_dochandle_t handle, char *sched)
1097 {
1098 	return (setrootattr(handle, DTD_ATTR_SCHED, sched));
1099 }
1100 
1101 /*
1102  * /etc/zones/index caches a vital piece of information which is also
1103  * in the <zonename>.xml file: the path to the zone.  This is for performance,
1104  * since we need to walk all zonepath's in order to be able to detect conflicts
1105  * (see crosscheck_zonepaths() in the zoneadm command).
1106  *
1107  * An additional complexity is that when doing a rename, we'd like the entire
1108  * index update operation (rename, and potential state changes) to be atomic.
1109  * In general, the operation of this function should succeed or fail as
1110  * a unit.
1111  */
1112 int
1113 zonecfg_refresh_index_file(zone_dochandle_t handle)
1114 {
1115 	char name[ZONENAME_MAX], zonepath[MAXPATHLEN];
1116 	struct zoneent ze;
1117 	int err;
1118 	int opcode;
1119 	char *zn;
1120 
1121 	bzero(&ze, sizeof (ze));
1122 	ze.zone_state = -1;	/* Preserve existing state in index */
1123 
1124 	if ((err = zonecfg_get_name(handle, name, sizeof (name))) != Z_OK)
1125 		return (err);
1126 	(void) strlcpy(ze.zone_name, name, sizeof (ze.zone_name));
1127 
1128 	if ((err = zonecfg_get_zonepath(handle, zonepath,
1129 	    sizeof (zonepath))) != Z_OK)
1130 		return (err);
1131 	(void) strlcpy(ze.zone_path, zonepath + strlen(zonecfg_root),
1132 	    sizeof (ze.zone_path));
1133 
1134 	if (is_renaming(handle)) {
1135 		opcode = PZE_MODIFY;
1136 		(void) strlcpy(ze.zone_name, handle->zone_dh_delete_name,
1137 		    sizeof (ze.zone_name));
1138 		(void) strlcpy(ze.zone_newname, name, sizeof (ze.zone_newname));
1139 	} else if (is_new(handle)) {
1140 		FILE *cookie;
1141 		/*
1142 		 * Be tolerant of the zone already existing in the index file,
1143 		 * since we might be forcibly overwriting an existing
1144 		 * configuration with a new one (for example 'create -F'
1145 		 * in zonecfg).
1146 		 */
1147 		opcode = PZE_ADD;
1148 		cookie = setzoneent();
1149 		while ((zn = getzoneent(cookie)) != NULL) {
1150 			if (strcmp(zn, name) == 0) {
1151 				opcode = PZE_MODIFY;
1152 				free(zn);
1153 				break;
1154 			}
1155 			free(zn);
1156 		}
1157 		endzoneent(cookie);
1158 		ze.zone_state = ZONE_STATE_CONFIGURED;
1159 	} else {
1160 		opcode = PZE_MODIFY;
1161 	}
1162 
1163 	if ((err = putzoneent(&ze, opcode)) != Z_OK)
1164 		return (err);
1165 
1166 	return (Z_OK);
1167 }
1168 
1169 /*
1170  * The goal of this routine is to cause the index file update and the
1171  * document save to happen as an atomic operation.  We do the document
1172  * first, saving a backup copy using a hard link; if that succeeds, we go
1173  * on to the index.  If that fails, we roll the document back into place.
1174  *
1175  * Strategy:
1176  *
1177  * New zone 'foo' configuration:
1178  *	Create tmpfile (zonecfg.xxxxxx)
1179  *	Write XML to tmpfile
1180  *	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
1181  *	Add entry to index file
1182  *	If it fails, delete foo.xml, leaving nothing behind.
1183  *
1184  * Save existing zone 'foo':
1185  *	Make backup of foo.xml -> .backup
1186  *	Create tmpfile (zonecfg.xxxxxx)
1187  *	Write XML to tmpfile
1188  *	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
1189  *	Modify index file as needed
1190  *	If it fails, recover from .backup -> foo.xml
1191  *
1192  * Rename 'foo' to 'bar':
1193  *	Create tmpfile (zonecfg.xxxxxx)
1194  *	Write XML to tmpfile
1195  *	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml)
1196  *	Add entry for 'bar' to index file, Remove entry for 'foo' (refresh)
1197  *	If it fails, delete bar.xml; foo.xml is left behind.
1198  */
1199 static int
1200 zonecfg_save_impl(zone_dochandle_t handle, char *filename)
1201 {
1202 	char tmpfile[MAXPATHLEN];
1203 	char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN];
1204 	int tmpfd, err, valid;
1205 	xmlValidCtxt cvp = { NULL };
1206 	boolean_t backup;
1207 
1208 	(void) strlcpy(tmpfile, filename, sizeof (tmpfile));
1209 	(void) dirname(tmpfile);
1210 	(void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile));
1211 
1212 	tmpfd = mkstemp(tmpfile);
1213 	if (tmpfd == -1) {
1214 		(void) unlink(tmpfile);
1215 		return (Z_TEMP_FILE);
1216 	}
1217 	(void) close(tmpfd);
1218 
1219 	cvp.error = zonecfg_error_func;
1220 	cvp.warning = zonecfg_error_func;
1221 
1222 	/*
1223 	 * We do a final validation of the document.  Since the library has
1224 	 * malfunctioned if it fails to validate, we follow-up with an
1225 	 * assert() that the doc is valid.
1226 	 */
1227 	valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1228 	assert(valid != 0);
1229 
1230 	if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0)
1231 		goto err;
1232 
1233 	(void) chmod(tmpfile, 0644);
1234 
1235 	/*
1236 	 * In the event we are doing a standard save, hard link a copy of the
1237 	 * original file in .backup.<pid>.filename so we can restore it if
1238 	 * something goes wrong.
1239 	 */
1240 	if (!is_new(handle) && !is_renaming(handle)) {
1241 		backup = B_TRUE;
1242 
1243 		(void) strlcpy(bakdir, filename, sizeof (bakdir));
1244 		(void) strlcpy(bakbase, filename, sizeof (bakbase));
1245 		(void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s",
1246 		    dirname(bakdir), getpid(), basename(bakbase));
1247 
1248 		if (link(filename, bakfile) == -1) {
1249 			err = errno;
1250 			(void) unlink(tmpfile);
1251 			if (errno == EACCES)
1252 				return (Z_ACCES);
1253 			return (Z_MISC_FS);
1254 		}
1255 	}
1256 
1257 	/*
1258 	 * Move the new document over top of the old.
1259 	 * i.e.:   zonecfg.XXXXXX  ->  myzone.xml
1260 	 */
1261 	if (rename(tmpfile, filename) == -1) {
1262 		err = errno;
1263 		(void) unlink(tmpfile);
1264 		if (backup)
1265 			(void) unlink(bakfile);
1266 		if (err == EACCES)
1267 			return (Z_ACCES);
1268 		return (Z_MISC_FS);
1269 	}
1270 
1271 	/*
1272 	 * If this is a snapshot, we're done-- don't add an index entry.
1273 	 */
1274 	if (is_snapshot(handle))
1275 		return (Z_OK);
1276 
1277 	/* now update the index file to reflect whatever we just did */
1278 	if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) {
1279 		if (backup) {
1280 			/*
1281 			 * Try to restore from our backup.
1282 			 */
1283 			(void) unlink(filename);
1284 			(void) rename(bakfile, filename);
1285 		} else {
1286 			/*
1287 			 * Either the zone is new, in which case we can delete
1288 			 * new.xml, or we're doing a rename, so ditto.
1289 			 */
1290 			assert(is_new(handle) || is_renaming(handle));
1291 			(void) unlink(filename);
1292 		}
1293 		return (Z_UPDATING_INDEX);
1294 	}
1295 
1296 	if (backup)
1297 		(void) unlink(bakfile);
1298 
1299 	return (Z_OK);
1300 
1301 err:
1302 	(void) unlink(tmpfile);
1303 	return (Z_SAVING_FILE);
1304 }
1305 
1306 int
1307 zonecfg_save(zone_dochandle_t handle)
1308 {
1309 	char zname[ZONENAME_MAX], path[MAXPATHLEN];
1310 	char delpath[MAXPATHLEN];
1311 	int err = Z_SAVING_FILE;
1312 
1313 	if (zonecfg_check_handle(handle) != Z_OK)
1314 		return (Z_BAD_HANDLE);
1315 
1316 	/*
1317 	 * We don't support saving snapshots or a tree containing a sw
1318 	 * inventory at this time.
1319 	 */
1320 	if (handle->zone_dh_snapshot || handle->zone_dh_sw_inv)
1321 		return (Z_INVAL);
1322 
1323 	if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK)
1324 		return (err);
1325 
1326 	if (!config_file_path(zname, path))
1327 		return (Z_MISC_FS);
1328 
1329 	addcomment(handle, "\n    DO NOT EDIT THIS "
1330 	    "FILE.  Use zonecfg(1M) instead.\n");
1331 
1332 	/*
1333 	 * Update user_attr first so that it will be older
1334 	 * than the config file.
1335 	 */
1336 	(void) zonecfg_authorize_users(handle, zname);
1337 	err = zonecfg_save_impl(handle, path);
1338 
1339 	stripcomments(handle);
1340 
1341 	if (err != Z_OK)
1342 		return (err);
1343 
1344 	handle->zone_dh_newzone = B_FALSE;
1345 
1346 	if (is_renaming(handle)) {
1347 		if (config_file_path(handle->zone_dh_delete_name, delpath))
1348 			(void) unlink(delpath);
1349 		handle->zone_dh_delete_name[0] = '\0';
1350 	}
1351 
1352 	return (Z_OK);
1353 }
1354 
1355 int
1356 zonecfg_verify_save(zone_dochandle_t handle, char *filename)
1357 {
1358 	int valid;
1359 
1360 	xmlValidCtxt cvp = { NULL };
1361 
1362 	if (zonecfg_check_handle(handle) != Z_OK)
1363 		return (Z_BAD_HANDLE);
1364 
1365 	cvp.error = zonecfg_error_func;
1366 	cvp.warning = zonecfg_error_func;
1367 
1368 	/*
1369 	 * We do a final validation of the document.  Since the library has
1370 	 * malfunctioned if it fails to validate, we follow-up with an
1371 	 * assert() that the doc is valid.
1372 	 */
1373 	valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1374 	assert(valid != 0);
1375 
1376 	if (xmlSaveFormatFile(filename, handle->zone_dh_doc, 1) <= 0)
1377 		return (Z_SAVING_FILE);
1378 
1379 	return (Z_OK);
1380 }
1381 
1382 int
1383 zonecfg_detach_save(zone_dochandle_t handle, uint_t flags)
1384 {
1385 	char zname[ZONENAME_MAX];
1386 	char path[MAXPATHLEN];
1387 	char migpath[MAXPATHLEN];
1388 	xmlValidCtxt cvp = { NULL };
1389 	int err = Z_SAVING_FILE;
1390 	int valid;
1391 
1392 	if (zonecfg_check_handle(handle) != Z_OK)
1393 		return (Z_BAD_HANDLE);
1394 
1395 	if (flags & ZONE_DRY_RUN) {
1396 		(void) strlcpy(migpath, "-", sizeof (migpath));
1397 	} else {
1398 		if ((err = zonecfg_get_name(handle, zname, sizeof (zname)))
1399 		    != Z_OK)
1400 			return (err);
1401 
1402 		if ((err = zone_get_zonepath(zname, path, sizeof (path)))
1403 		    != Z_OK)
1404 			return (err);
1405 
1406 		if (snprintf(migpath, sizeof (migpath), "%s/%s", path,
1407 		    ZONE_DETACHED) >= sizeof (migpath))
1408 			return (Z_NOMEM);
1409 	}
1410 
1411 	if ((err = operation_prep(handle)) != Z_OK)
1412 		return (err);
1413 
1414 	addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
1415 	    "Use zonecfg(1M) and zoneadm(1M) attach.\n");
1416 
1417 	cvp.error = zonecfg_error_func;
1418 	cvp.warning = zonecfg_error_func;
1419 
1420 	/*
1421 	 * We do a final validation of the document.  Since the library has
1422 	 * malfunctioned if it fails to validate, we follow-up with an
1423 	 * assert() that the doc is valid.
1424 	 */
1425 	valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1426 	assert(valid != 0);
1427 
1428 	if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0)
1429 		return (Z_SAVING_FILE);
1430 
1431 	if (!(flags & ZONE_DRY_RUN))
1432 		(void) chmod(migpath, 0644);
1433 
1434 	stripcomments(handle);
1435 
1436 	handle->zone_dh_newzone = B_FALSE;
1437 
1438 	return (Z_OK);
1439 }
1440 
1441 boolean_t
1442 zonecfg_detached(const char *path)
1443 {
1444 	char		migpath[MAXPATHLEN];
1445 	struct stat	buf;
1446 
1447 	if (snprintf(migpath, sizeof (migpath), "%s/%s", path, ZONE_DETACHED) >=
1448 	    sizeof (migpath))
1449 		return (B_FALSE);
1450 
1451 	if (stat(migpath, &buf) != -1)
1452 		return (B_TRUE);
1453 
1454 	return (B_FALSE);
1455 }
1456 
1457 void
1458 zonecfg_rm_detached(zone_dochandle_t handle, boolean_t forced)
1459 {
1460 	char zname[ZONENAME_MAX];
1461 	char path[MAXPATHLEN];
1462 	char detached[MAXPATHLEN];
1463 	char attached[MAXPATHLEN];
1464 
1465 	if (zonecfg_check_handle(handle) != Z_OK)
1466 		return;
1467 
1468 	if (zonecfg_get_name(handle, zname, sizeof (zname)) != Z_OK)
1469 		return;
1470 
1471 	if (zone_get_zonepath(zname, path, sizeof (path)) != Z_OK)
1472 		return;
1473 
1474 	(void) snprintf(detached, sizeof (detached), "%s/%s", path,
1475 	    ZONE_DETACHED);
1476 	(void) snprintf(attached, sizeof (attached), "%s/%s", path,
1477 	    ATTACH_FORCED);
1478 
1479 	if (forced) {
1480 		(void) rename(detached, attached);
1481 	} else {
1482 		(void) unlink(attached);
1483 		(void) unlink(detached);
1484 	}
1485 }
1486 
1487 /*
1488  * Special case: if access(2) fails with ENOENT, then try again using
1489  * ZONE_CONFIG_ROOT instead of config_file_path(zonename).  This is how we
1490  * work around the case of a config file which has not been created yet:
1491  * the user will need access to the directory so use that as a heuristic.
1492  */
1493 
1494 int
1495 zonecfg_access(const char *zonename, int amode)
1496 {
1497 	char path[MAXPATHLEN];
1498 
1499 	if (!config_file_path(zonename, path))
1500 		return (Z_INVAL);
1501 	if (access(path, amode) == 0)
1502 		return (Z_OK);
1503 	if (errno == ENOENT) {
1504 		if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1505 		    ZONE_CONFIG_ROOT) >= sizeof (path))
1506 			return (Z_INVAL);
1507 		if (access(path, amode) == 0)
1508 			return (Z_OK);
1509 	}
1510 	if (errno == EACCES)
1511 		return (Z_ACCES);
1512 	if (errno == EINVAL)
1513 		return (Z_INVAL);
1514 	return (Z_MISC_FS);
1515 }
1516 
1517 int
1518 zonecfg_create_snapshot(const char *zonename)
1519 {
1520 	zone_dochandle_t handle;
1521 	char path[MAXPATHLEN], zonepath[MAXPATHLEN], rpath[MAXPATHLEN];
1522 	int error = Z_OK, res;
1523 
1524 	if ((handle = zonecfg_init_handle()) == NULL) {
1525 		return (Z_NOMEM);
1526 	}
1527 
1528 	handle->zone_dh_newzone = B_TRUE;
1529 	handle->zone_dh_snapshot = B_TRUE;
1530 
1531 	if ((error = zonecfg_get_handle(zonename, handle)) != Z_OK)
1532 		goto out;
1533 	if ((error = operation_prep(handle)) != Z_OK)
1534 		goto out;
1535 	error = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath));
1536 	if (error != Z_OK)
1537 		goto out;
1538 	if ((res = resolvepath(zonepath, rpath, sizeof (rpath))) == -1) {
1539 		error = Z_RESOLVED_PATH;
1540 		goto out;
1541 	}
1542 	/*
1543 	 * If the resolved path is not the same as the original path, then
1544 	 * save the resolved path in the snapshot, thus preventing any
1545 	 * potential problems down the line when zoneadmd goes to unmount
1546 	 * file systems and depends on initial string matches with resolved
1547 	 * paths.
1548 	 */
1549 	rpath[res] = '\0';
1550 	if (strcmp(zonepath, rpath) != 0) {
1551 		if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK)
1552 			goto out;
1553 	}
1554 	if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1555 	    ZONE_SNAPSHOT_ROOT) >= sizeof (path)) {
1556 		error = Z_MISC_FS;
1557 		goto out;
1558 	}
1559 	if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) {
1560 		error = Z_MISC_FS;
1561 		goto out;
1562 	}
1563 
1564 	if (!snap_file_path(zonename, path)) {
1565 		error = Z_MISC_FS;
1566 		goto out;
1567 	}
1568 
1569 	addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
1570 	    "It is a snapshot of running zone state.\n");
1571 
1572 	error = zonecfg_save_impl(handle, path);
1573 
1574 	stripcomments(handle);
1575 
1576 out:
1577 	zonecfg_fini_handle(handle);
1578 	return (error);
1579 }
1580 
1581 int
1582 zonecfg_get_iptype(zone_dochandle_t handle, zone_iptype_t *iptypep)
1583 {
1584 	char property[10]; /* 10 is big enough for "shared"/"exclusive" */
1585 	int err;
1586 
1587 	err = getrootattr(handle, DTD_ATTR_IPTYPE, property, sizeof (property));
1588 	if (err == Z_BAD_PROPERTY) {
1589 		/* Return default value */
1590 		*iptypep = ZS_SHARED;
1591 		return (Z_OK);
1592 	} else if (err != Z_OK) {
1593 		return (err);
1594 	}
1595 
1596 	if (strlen(property) == 0 ||
1597 	    strcmp(property, "shared") == 0)
1598 		*iptypep = ZS_SHARED;
1599 	else if (strcmp(property, "exclusive") == 0)
1600 		*iptypep = ZS_EXCLUSIVE;
1601 	else
1602 		return (Z_INVAL);
1603 
1604 	return (Z_OK);
1605 }
1606 
1607 int
1608 zonecfg_set_iptype(zone_dochandle_t handle, zone_iptype_t iptype)
1609 {
1610 	xmlNodePtr cur;
1611 
1612 	if (handle == NULL)
1613 		return (Z_INVAL);
1614 
1615 	cur = xmlDocGetRootElement(handle->zone_dh_doc);
1616 	if (cur == NULL) {
1617 		return (Z_EMPTY_DOCUMENT);
1618 	}
1619 
1620 	if (xmlStrcmp(cur->name, DTD_ELEM_ZONE) != 0) {
1621 		return (Z_WRONG_DOC_TYPE);
1622 	}
1623 	switch (iptype) {
1624 	case ZS_SHARED:
1625 		/*
1626 		 * Since "shared" is the default, we don't write it to the
1627 		 * configuration file, so that it's easier to migrate those
1628 		 * zones elsewhere, eg., to systems which are not IP-Instances
1629 		 * aware.
1630 		 * xmlUnsetProp only fails when the attribute doesn't exist,
1631 		 * which we don't care.
1632 		 */
1633 		(void) xmlUnsetProp(cur, DTD_ATTR_IPTYPE);
1634 		break;
1635 	case ZS_EXCLUSIVE:
1636 		if (xmlSetProp(cur, DTD_ATTR_IPTYPE,
1637 		    (const xmlChar *) "exclusive") == NULL)
1638 			return (Z_INVAL);
1639 		break;
1640 	}
1641 	return (Z_OK);
1642 }
1643 
1644 static int
1645 newprop(xmlNodePtr node, const xmlChar *attrname, char *src)
1646 {
1647 	xmlAttrPtr newattr;
1648 
1649 	newattr = xmlNewProp(node, attrname, (xmlChar *)src);
1650 	if (newattr == NULL) {
1651 		xmlUnlinkNode(node);
1652 		xmlFreeNode(node);
1653 		return (Z_BAD_PROPERTY);
1654 	}
1655 	return (Z_OK);
1656 }
1657 
1658 static int
1659 zonecfg_add_filesystem_core(zone_dochandle_t handle, struct zone_fstab *tabptr)
1660 {
1661 	xmlNodePtr newnode, cur = handle->zone_dh_cur, options_node;
1662 	zone_fsopt_t *ptr;
1663 	int err;
1664 
1665 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_FS, NULL);
1666 	if ((err = newprop(newnode, DTD_ATTR_SPECIAL,
1667 	    tabptr->zone_fs_special)) != Z_OK)
1668 		return (err);
1669 	if (tabptr->zone_fs_raw[0] != '\0' &&
1670 	    (err = newprop(newnode, DTD_ATTR_RAW, tabptr->zone_fs_raw)) != Z_OK)
1671 		return (err);
1672 	if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK)
1673 		return (err);
1674 	if ((err = newprop(newnode, DTD_ATTR_TYPE,
1675 	    tabptr->zone_fs_type)) != Z_OK)
1676 		return (err);
1677 	if (tabptr->zone_fs_options != NULL) {
1678 		for (ptr = tabptr->zone_fs_options; ptr != NULL;
1679 		    ptr = ptr->zone_fsopt_next) {
1680 			options_node = xmlNewTextChild(newnode, NULL,
1681 			    DTD_ELEM_FSOPTION, NULL);
1682 			if ((err = newprop(options_node, DTD_ATTR_NAME,
1683 			    ptr->zone_fsopt_opt)) != Z_OK)
1684 				return (err);
1685 		}
1686 	}
1687 	return (Z_OK);
1688 }
1689 
1690 int
1691 zonecfg_add_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
1692 {
1693 	int err;
1694 
1695 	if (tabptr == NULL)
1696 		return (Z_INVAL);
1697 
1698 	if ((err = operation_prep(handle)) != Z_OK)
1699 		return (err);
1700 
1701 	if ((err = zonecfg_add_filesystem_core(handle, tabptr)) != Z_OK)
1702 		return (err);
1703 
1704 	return (Z_OK);
1705 }
1706 
1707 int
1708 zonecfg_add_fs_option(struct zone_fstab *tabptr, char *option)
1709 {
1710 	zone_fsopt_t *last, *old, *new;
1711 
1712 	last = tabptr->zone_fs_options;
1713 	for (old = last; old != NULL; old = old->zone_fsopt_next)
1714 		last = old;	/* walk to the end of the list */
1715 	new = (zone_fsopt_t *)malloc(sizeof (zone_fsopt_t));
1716 	if (new == NULL)
1717 		return (Z_NOMEM);
1718 	(void) strlcpy(new->zone_fsopt_opt, option,
1719 	    sizeof (new->zone_fsopt_opt));
1720 	new->zone_fsopt_next = NULL;
1721 	if (last == NULL)
1722 		tabptr->zone_fs_options = new;
1723 	else
1724 		last->zone_fsopt_next = new;
1725 	return (Z_OK);
1726 }
1727 
1728 int
1729 zonecfg_remove_fs_option(struct zone_fstab *tabptr, char *option)
1730 {
1731 	zone_fsopt_t *last, *this, *next;
1732 
1733 	last = tabptr->zone_fs_options;
1734 	for (this = last; this != NULL; this = this->zone_fsopt_next) {
1735 		if (strcmp(this->zone_fsopt_opt, option) == 0) {
1736 			next = this->zone_fsopt_next;
1737 			if (this == tabptr->zone_fs_options)
1738 				tabptr->zone_fs_options = next;
1739 			else
1740 				last->zone_fsopt_next = next;
1741 			free(this);
1742 			return (Z_OK);
1743 		} else
1744 			last = this;
1745 	}
1746 	return (Z_NO_PROPERTY_ID);
1747 }
1748 
1749 void
1750 zonecfg_free_fs_option_list(zone_fsopt_t *list)
1751 {
1752 	zone_fsopt_t *this, *next;
1753 
1754 	for (this = list; this != NULL; this = next) {
1755 		next = this->zone_fsopt_next;
1756 		free(this);
1757 	}
1758 }
1759 
1760 void
1761 zonecfg_free_rctl_value_list(struct zone_rctlvaltab *valtab)
1762 {
1763 	if (valtab == NULL)
1764 		return;
1765 	zonecfg_free_rctl_value_list(valtab->zone_rctlval_next);
1766 	free(valtab);
1767 }
1768 
1769 static boolean_t
1770 match_prop(xmlNodePtr cur, const xmlChar *attr, char *user_prop)
1771 {
1772 	xmlChar *gotten_prop;
1773 	int prop_result;
1774 
1775 	gotten_prop = xmlGetProp(cur, attr);
1776 	if (gotten_prop == NULL)	/* shouldn't happen */
1777 		return (B_FALSE);
1778 	prop_result = xmlStrcmp(gotten_prop, (const xmlChar *) user_prop);
1779 	xmlFree(gotten_prop);
1780 	return ((prop_result == 0));	/* empty strings will match */
1781 }
1782 
1783 static int
1784 zonecfg_delete_filesystem_core(zone_dochandle_t handle,
1785     struct zone_fstab *tabptr)
1786 {
1787 	xmlNodePtr cur = handle->zone_dh_cur;
1788 	boolean_t dir_match, spec_match, raw_match, type_match;
1789 
1790 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1791 		if (xmlStrcmp(cur->name, DTD_ELEM_FS))
1792 			continue;
1793 		dir_match = match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir);
1794 		spec_match = match_prop(cur, DTD_ATTR_SPECIAL,
1795 		    tabptr->zone_fs_special);
1796 		raw_match = match_prop(cur, DTD_ATTR_RAW,
1797 		    tabptr->zone_fs_raw);
1798 		type_match = match_prop(cur, DTD_ATTR_TYPE,
1799 		    tabptr->zone_fs_type);
1800 		if (dir_match && spec_match && raw_match && type_match) {
1801 			xmlUnlinkNode(cur);
1802 			xmlFreeNode(cur);
1803 			return (Z_OK);
1804 		}
1805 	}
1806 	return (Z_NO_RESOURCE_ID);
1807 }
1808 
1809 int
1810 zonecfg_delete_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
1811 {
1812 	int err;
1813 
1814 	if (tabptr == NULL)
1815 		return (Z_INVAL);
1816 
1817 	if ((err = operation_prep(handle)) != Z_OK)
1818 		return (err);
1819 
1820 	if ((err = zonecfg_delete_filesystem_core(handle, tabptr)) != Z_OK)
1821 		return (err);
1822 
1823 	return (Z_OK);
1824 }
1825 
1826 int
1827 zonecfg_modify_filesystem(
1828 	zone_dochandle_t handle,
1829 	struct zone_fstab *oldtabptr,
1830 	struct zone_fstab *newtabptr)
1831 {
1832 	int err;
1833 
1834 	if (oldtabptr == NULL || newtabptr == NULL)
1835 		return (Z_INVAL);
1836 
1837 	if ((err = operation_prep(handle)) != Z_OK)
1838 		return (err);
1839 
1840 	if ((err = zonecfg_delete_filesystem_core(handle, oldtabptr)) != Z_OK)
1841 		return (err);
1842 
1843 	if ((err = zonecfg_add_filesystem_core(handle, newtabptr)) != Z_OK)
1844 		return (err);
1845 
1846 	return (Z_OK);
1847 }
1848 
1849 int
1850 zonecfg_lookup_filesystem(
1851 	zone_dochandle_t handle,
1852 	struct zone_fstab *tabptr)
1853 {
1854 	xmlNodePtr cur, options, firstmatch;
1855 	int err;
1856 	char dirname[MAXPATHLEN], special[MAXPATHLEN], raw[MAXPATHLEN];
1857 	char type[FSTYPSZ];
1858 	char options_str[MAX_MNTOPT_STR];
1859 
1860 	if (tabptr == NULL)
1861 		return (Z_INVAL);
1862 
1863 	if ((err = operation_prep(handle)) != Z_OK)
1864 		return (err);
1865 
1866 	/*
1867 	 * Walk the list of children looking for matches on any properties
1868 	 * specified in the fstab parameter.  If more than one resource
1869 	 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return
1870 	 * Z_NO_RESOURCE_ID.
1871 	 */
1872 	cur = handle->zone_dh_cur;
1873 	firstmatch = NULL;
1874 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1875 		if (xmlStrcmp(cur->name, DTD_ELEM_FS))
1876 			continue;
1877 		if (strlen(tabptr->zone_fs_dir) > 0) {
1878 			if ((fetchprop(cur, DTD_ATTR_DIR, dirname,
1879 			    sizeof (dirname)) == Z_OK) &&
1880 			    (strcmp(tabptr->zone_fs_dir, dirname) == 0)) {
1881 				if (firstmatch == NULL)
1882 					firstmatch = cur;
1883 				else
1884 					return (Z_INSUFFICIENT_SPEC);
1885 			}
1886 		}
1887 		if (strlen(tabptr->zone_fs_special) > 0) {
1888 			if ((fetchprop(cur, DTD_ATTR_SPECIAL, special,
1889 			    sizeof (special)) == Z_OK)) {
1890 				if (strcmp(tabptr->zone_fs_special,
1891 				    special) == 0) {
1892 					if (firstmatch == NULL)
1893 						firstmatch = cur;
1894 					else if (firstmatch != cur)
1895 						return (Z_INSUFFICIENT_SPEC);
1896 				} else {
1897 					/*
1898 					 * If another property matched but this
1899 					 * one doesn't then reset firstmatch.
1900 					 */
1901 					if (firstmatch == cur)
1902 						firstmatch = NULL;
1903 				}
1904 			}
1905 		}
1906 		if (strlen(tabptr->zone_fs_raw) > 0) {
1907 			if ((fetchprop(cur, DTD_ATTR_RAW, raw,
1908 			    sizeof (raw)) == Z_OK)) {
1909 				if (strcmp(tabptr->zone_fs_raw, raw) == 0) {
1910 					if (firstmatch == NULL)
1911 						firstmatch = cur;
1912 					else if (firstmatch != cur)
1913 						return (Z_INSUFFICIENT_SPEC);
1914 				} else {
1915 					/*
1916 					 * If another property matched but this
1917 					 * one doesn't then reset firstmatch.
1918 					 */
1919 					if (firstmatch == cur)
1920 						firstmatch = NULL;
1921 				}
1922 			}
1923 		}
1924 		if (strlen(tabptr->zone_fs_type) > 0) {
1925 			if ((fetchprop(cur, DTD_ATTR_TYPE, type,
1926 			    sizeof (type)) == Z_OK)) {
1927 				if (strcmp(tabptr->zone_fs_type, type) == 0) {
1928 					if (firstmatch == NULL)
1929 						firstmatch = cur;
1930 					else if (firstmatch != cur)
1931 						return (Z_INSUFFICIENT_SPEC);
1932 				} else {
1933 					/*
1934 					 * If another property matched but this
1935 					 * one doesn't then reset firstmatch.
1936 					 */
1937 					if (firstmatch == cur)
1938 						firstmatch = NULL;
1939 				}
1940 			}
1941 		}
1942 	}
1943 
1944 	if (firstmatch == NULL)
1945 		return (Z_NO_RESOURCE_ID);
1946 
1947 	cur = firstmatch;
1948 
1949 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
1950 	    sizeof (tabptr->zone_fs_dir))) != Z_OK)
1951 		return (err);
1952 
1953 	if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
1954 	    sizeof (tabptr->zone_fs_special))) != Z_OK)
1955 		return (err);
1956 
1957 	if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
1958 	    sizeof (tabptr->zone_fs_raw))) != Z_OK)
1959 		return (err);
1960 
1961 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
1962 	    sizeof (tabptr->zone_fs_type))) != Z_OK)
1963 		return (err);
1964 
1965 	/* options are optional */
1966 	tabptr->zone_fs_options = NULL;
1967 	for (options = cur->xmlChildrenNode; options != NULL;
1968 	    options = options->next) {
1969 		if ((fetchprop(options, DTD_ATTR_NAME, options_str,
1970 		    sizeof (options_str)) != Z_OK))
1971 			break;
1972 		if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
1973 			break;
1974 	}
1975 	return (Z_OK);
1976 }
1977 
1978 /*
1979  * Compare two IP addresses in string form.  Allow for the possibility that
1980  * one might have "/<prefix-length>" at the end: allow a match on just the
1981  * IP address (or host name) part.
1982  */
1983 
1984 boolean_t
1985 zonecfg_same_net_address(char *a1, char *a2)
1986 {
1987 	char *slashp, *slashp1, *slashp2;
1988 	int result;
1989 
1990 	if (strcmp(a1, a2) == 0)
1991 		return (B_TRUE);
1992 
1993 	/*
1994 	 * If neither has a slash or both do, they need to match to be
1995 	 * considered the same, but they did not match above, so fail.
1996 	 */
1997 	slashp1 = strchr(a1, '/');
1998 	slashp2 = strchr(a2, '/');
1999 	if ((slashp1 == NULL && slashp2 == NULL) ||
2000 	    (slashp1 != NULL && slashp2 != NULL))
2001 		return (B_FALSE);
2002 
2003 	/*
2004 	 * Only one had a slash: pick that one, zero out the slash, compare
2005 	 * the "address only" strings, restore the slash, and return the
2006 	 * result of the comparison.
2007 	 */
2008 	slashp = (slashp1 == NULL) ? slashp2 : slashp1;
2009 	*slashp = '\0';
2010 	result = strcmp(a1, a2);
2011 	*slashp = '/';
2012 	return ((result == 0));
2013 }
2014 
2015 int
2016 zonecfg_valid_net_address(char *address, struct lifreq *lifr)
2017 {
2018 	struct sockaddr_in *sin4;
2019 	struct sockaddr_in6 *sin6;
2020 	struct addrinfo hints, *result;
2021 	char *slashp = strchr(address, '/');
2022 
2023 	bzero(lifr, sizeof (struct lifreq));
2024 	sin4 = (struct sockaddr_in *)&lifr->lifr_addr;
2025 	sin6 = (struct sockaddr_in6 *)&lifr->lifr_addr;
2026 	if (slashp != NULL)
2027 		*slashp = '\0';
2028 	if (inet_pton(AF_INET, address, &sin4->sin_addr) == 1) {
2029 		sin4->sin_family = AF_INET;
2030 	} else if (inet_pton(AF_INET6, address, &sin6->sin6_addr) == 1) {
2031 		if (slashp == NULL)
2032 			return (Z_IPV6_ADDR_PREFIX_LEN);
2033 		sin6->sin6_family = AF_INET6;
2034 	} else {
2035 		/* "address" may be a host name */
2036 		(void) memset(&hints, 0, sizeof (hints));
2037 		hints.ai_family = PF_INET;
2038 		if (getaddrinfo(address, NULL, &hints, &result) != 0)
2039 			return (Z_BOGUS_ADDRESS);
2040 		sin4->sin_family = result->ai_family;
2041 
2042 		(void) memcpy(&sin4->sin_addr,
2043 		    /* LINTED E_BAD_PTR_CAST_ALIGN */
2044 		    &((struct sockaddr_in *)result->ai_addr)->sin_addr,
2045 		    sizeof (struct in_addr));
2046 
2047 		freeaddrinfo(result);
2048 	}
2049 	return (Z_OK);
2050 }
2051 
2052 boolean_t
2053 zonecfg_ifname_exists(sa_family_t af, char *ifname)
2054 {
2055 	struct lifreq lifr;
2056 	int so;
2057 	int save_errno;
2058 
2059 	(void) memset(&lifr, 0, sizeof (lifr));
2060 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
2061 	lifr.lifr_addr.ss_family = af;
2062 	if ((so = socket(af, SOCK_DGRAM, 0)) < 0) {
2063 		/* Odd - can't tell if the ifname exists */
2064 		return (B_FALSE);
2065 	}
2066 	if (ioctl(so, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
2067 		save_errno = errno;
2068 		(void) close(so);
2069 		errno = save_errno;
2070 		return (B_FALSE);
2071 	}
2072 	(void) close(so);
2073 	return (B_TRUE);
2074 }
2075 
2076 /*
2077  * Determines whether there is a net resource with the physical interface, IP
2078  * address, and default router specified by 'tabptr' in the zone configuration
2079  * to which 'handle' refers.  'tabptr' must have an interface, an address, a
2080  * default router, or a combination of the three.  This function returns Z_OK
2081  * iff there is exactly one net resource matching the query specified by
2082  * 'tabptr'.  The function returns Z_INSUFFICIENT_SPEC if there are multiple
2083  * matches or 'tabptr' does not specify a physical interface, address, or
2084  * default router.  The function returns Z_NO_RESOURCE_ID if are no matches.
2085  *
2086  * Errors might also be returned if the entry that exactly matches the
2087  * query lacks critical network resource information.
2088  *
2089  * If there is a single match, then the matching entry's physical interface, IP
2090  * address, and default router information are stored in 'tabptr'.
2091  */
2092 int
2093 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2094 {
2095 	xmlNodePtr cur;
2096 	xmlNodePtr firstmatch;
2097 	int err;
2098 	char address[INET6_ADDRSTRLEN];
2099 	char physical[LIFNAMSIZ];
2100 	size_t addrspec;		/* nonzero if tabptr has IP addr */
2101 	size_t physspec;		/* nonzero if tabptr has interface */
2102 	size_t defrouterspec;		/* nonzero if tabptr has def. router */
2103 	size_t allowed_addrspec;
2104 	zone_iptype_t iptype;
2105 
2106 	if (tabptr == NULL)
2107 		return (Z_INVAL);
2108 
2109 	/*
2110 	 * Determine the fields that will be searched.  There must be at least
2111 	 * one.
2112 	 *
2113 	 * zone_nwif_address, zone_nwif_physical, and zone_nwif_defrouter are
2114 	 * arrays, so no NULL checks are necessary.
2115 	 */
2116 	addrspec = strlen(tabptr->zone_nwif_address);
2117 	physspec = strlen(tabptr->zone_nwif_physical);
2118 	defrouterspec = strlen(tabptr->zone_nwif_defrouter);
2119 	allowed_addrspec = strlen(tabptr->zone_nwif_allowed_address);
2120 	if (addrspec != 0 && allowed_addrspec != 0)
2121 		return (Z_INVAL); /* can't specify both */
2122 	if (addrspec == 0 && physspec == 0 && defrouterspec == 0 &&
2123 	    allowed_addrspec == 0)
2124 		return (Z_INSUFFICIENT_SPEC);
2125 
2126 	if ((err = operation_prep(handle)) != Z_OK)
2127 		return (err);
2128 
2129 	if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK)
2130 		return (err);
2131 	/*
2132 	 * Iterate over the configuration's elements and look for net elements
2133 	 * that match the query.
2134 	 */
2135 	firstmatch = NULL;
2136 	cur = handle->zone_dh_cur;
2137 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2138 		/* Skip non-net elements */
2139 		if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2140 			continue;
2141 
2142 		/*
2143 		 * If any relevant fields don't match the query, then skip
2144 		 * the current net element.
2145 		 */
2146 		if (physspec != 0 && (fetchprop(cur, DTD_ATTR_PHYSICAL,
2147 		    physical, sizeof (physical)) != Z_OK ||
2148 		    strcmp(tabptr->zone_nwif_physical, physical) != 0))
2149 			continue;
2150 		if (iptype == ZS_SHARED && addrspec != 0 &&
2151 		    (fetchprop(cur, DTD_ATTR_ADDRESS, address,
2152 		    sizeof (address)) != Z_OK ||
2153 		    !zonecfg_same_net_address(tabptr->zone_nwif_address,
2154 		    address)))
2155 			continue;
2156 		if (iptype == ZS_EXCLUSIVE && allowed_addrspec != 0 &&
2157 		    (fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS, address,
2158 		    sizeof (address)) != Z_OK ||
2159 		    !zonecfg_same_net_address(tabptr->zone_nwif_allowed_address,
2160 		    address)))
2161 			continue;
2162 		if (defrouterspec != 0 && (fetchprop(cur, DTD_ATTR_DEFROUTER,
2163 		    address, sizeof (address)) != Z_OK ||
2164 		    !zonecfg_same_net_address(tabptr->zone_nwif_defrouter,
2165 		    address)))
2166 			continue;
2167 
2168 		/*
2169 		 * The current net element matches the query.  Select it if
2170 		 * it's the first match; otherwise, abort the search.
2171 		 */
2172 		if (firstmatch == NULL)
2173 			firstmatch = cur;
2174 		else
2175 			return (Z_INSUFFICIENT_SPEC);
2176 	}
2177 	if (firstmatch == NULL)
2178 		return (Z_NO_RESOURCE_ID);
2179 
2180 	cur = firstmatch;
2181 
2182 	if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
2183 	    sizeof (tabptr->zone_nwif_physical))) != Z_OK)
2184 		return (err);
2185 
2186 	if (iptype == ZS_SHARED &&
2187 	    (err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
2188 	    sizeof (tabptr->zone_nwif_address))) != Z_OK)
2189 		return (err);
2190 
2191 	if (iptype == ZS_EXCLUSIVE &&
2192 	    (err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
2193 	    tabptr->zone_nwif_allowed_address,
2194 	    sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK)
2195 		return (err);
2196 
2197 	if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
2198 	    tabptr->zone_nwif_defrouter,
2199 	    sizeof (tabptr->zone_nwif_defrouter))) != Z_OK)
2200 		return (err);
2201 
2202 	return (Z_OK);
2203 }
2204 
2205 static int
2206 zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2207 {
2208 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
2209 	int err;
2210 
2211 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL);
2212 	if (strlen(tabptr->zone_nwif_address) > 0 &&
2213 	    (err = newprop(newnode, DTD_ATTR_ADDRESS,
2214 	    tabptr->zone_nwif_address)) != Z_OK)
2215 		return (err);
2216 	if (strlen(tabptr->zone_nwif_allowed_address) > 0 &&
2217 	    (err = newprop(newnode, DTD_ATTR_ALLOWED_ADDRESS,
2218 	    tabptr->zone_nwif_allowed_address)) != Z_OK)
2219 		return (err);
2220 	if ((err = newprop(newnode, DTD_ATTR_PHYSICAL,
2221 	    tabptr->zone_nwif_physical)) != Z_OK)
2222 		return (err);
2223 	/*
2224 	 * Do not add this property when it is not set, for backwards
2225 	 * compatibility and because it is optional.
2226 	 */
2227 	if ((strlen(tabptr->zone_nwif_defrouter) > 0) &&
2228 	    ((err = newprop(newnode, DTD_ATTR_DEFROUTER,
2229 	    tabptr->zone_nwif_defrouter)) != Z_OK))
2230 		return (err);
2231 	return (Z_OK);
2232 }
2233 
2234 int
2235 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2236 {
2237 	int err;
2238 
2239 	if (tabptr == NULL)
2240 		return (Z_INVAL);
2241 
2242 	if ((err = operation_prep(handle)) != Z_OK)
2243 		return (err);
2244 
2245 	if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK)
2246 		return (err);
2247 
2248 	return (Z_OK);
2249 }
2250 
2251 static int
2252 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2253 {
2254 	xmlNodePtr cur = handle->zone_dh_cur;
2255 	boolean_t addr_match, phys_match, allowed_addr_match;
2256 
2257 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2258 		if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2259 			continue;
2260 
2261 		addr_match = match_prop(cur, DTD_ATTR_ADDRESS,
2262 		    tabptr->zone_nwif_address);
2263 		allowed_addr_match = match_prop(cur, DTD_ATTR_ALLOWED_ADDRESS,
2264 		    tabptr->zone_nwif_allowed_address);
2265 		phys_match = match_prop(cur, DTD_ATTR_PHYSICAL,
2266 		    tabptr->zone_nwif_physical);
2267 
2268 		if (addr_match && allowed_addr_match && phys_match) {
2269 			xmlUnlinkNode(cur);
2270 			xmlFreeNode(cur);
2271 			return (Z_OK);
2272 		}
2273 	}
2274 	return (Z_NO_RESOURCE_ID);
2275 }
2276 
2277 int
2278 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2279 {
2280 	int err;
2281 
2282 	if (tabptr == NULL)
2283 		return (Z_INVAL);
2284 
2285 	if ((err = operation_prep(handle)) != Z_OK)
2286 		return (err);
2287 
2288 	if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK)
2289 		return (err);
2290 
2291 	return (Z_OK);
2292 }
2293 
2294 int
2295 zonecfg_modify_nwif(
2296 	zone_dochandle_t handle,
2297 	struct zone_nwiftab *oldtabptr,
2298 	struct zone_nwiftab *newtabptr)
2299 {
2300 	int err;
2301 
2302 	if (oldtabptr == NULL || newtabptr == NULL)
2303 		return (Z_INVAL);
2304 
2305 	if ((err = operation_prep(handle)) != Z_OK)
2306 		return (err);
2307 
2308 	if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK)
2309 		return (err);
2310 
2311 	if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK)
2312 		return (err);
2313 
2314 	return (Z_OK);
2315 }
2316 
2317 /*
2318  * Must be a comma-separated list of alpha-numeric file system names.
2319  */
2320 static int
2321 zonecfg_valid_fs_allowed(const char *fsallowedp)
2322 {
2323 	char tmp[ZONE_FS_ALLOWED_MAX];
2324 	char *cp = tmp;
2325 	char *p;
2326 
2327 	if (strlen(fsallowedp) > ZONE_FS_ALLOWED_MAX)
2328 		return (Z_TOO_BIG);
2329 
2330 	(void) strlcpy(tmp, fsallowedp, sizeof (tmp));
2331 
2332 	while (*cp != '\0') {
2333 		p = cp;
2334 		while (*p != '\0' && *p != ',') {
2335 			if (!isalnum(*p) && *p != '-')
2336 				return (Z_INVALID_PROPERTY);
2337 			p++;
2338 		}
2339 
2340 		if (*p == ',') {
2341 			if (p == cp)
2342 				return (Z_INVALID_PROPERTY);
2343 
2344 			p++;
2345 
2346 			if (*p == '\0')
2347 				return (Z_INVALID_PROPERTY);
2348 		}
2349 
2350 		cp = p;
2351 	}
2352 
2353 	return (Z_OK);
2354 }
2355 
2356 int
2357 zonecfg_get_fs_allowed(zone_dochandle_t handle, char *bufp, size_t buflen)
2358 {
2359 	int err;
2360 
2361 	if ((err = getrootattr(handle, DTD_ATTR_FS_ALLOWED,
2362 	    bufp, buflen)) != Z_OK)
2363 		return (err);
2364 	if (bufp[0] == '\0')
2365 		return (Z_BAD_PROPERTY);
2366 	return (zonecfg_valid_fs_allowed(bufp));
2367 }
2368 
2369 int
2370 zonecfg_set_fs_allowed(zone_dochandle_t handle, const char *bufp)
2371 {
2372 	int err;
2373 
2374 	if (bufp == NULL || (err = zonecfg_valid_fs_allowed(bufp)) == Z_OK)
2375 		return (setrootattr(handle, DTD_ATTR_FS_ALLOWED, bufp));
2376 	return (err);
2377 }
2378 
2379 /*
2380  * Determines if the specified string is a valid hostid string.  This function
2381  * returns Z_OK if the string is a valid hostid string.  It returns Z_INVAL if
2382  * 'hostidp' is NULL, Z_TOO_BIG if 'hostidp' refers to a string buffer
2383  * containing a hex string with more than 8 digits, and Z_INVALID_PROPERTY if
2384  * the string has an invalid format.
2385  */
2386 static int
2387 zonecfg_valid_hostid(const char *hostidp)
2388 {
2389 	char *currentp;
2390 	u_longlong_t hostidval;
2391 	size_t len;
2392 
2393 	if (hostidp == NULL)
2394 		return (Z_INVAL);
2395 
2396 	/* Empty strings and strings with whitespace are invalid. */
2397 	if (*hostidp == '\0')
2398 		return (Z_INVALID_PROPERTY);
2399 	for (currentp = (char *)hostidp; *currentp != '\0'; ++currentp) {
2400 		if (isspace(*currentp))
2401 			return (Z_INVALID_PROPERTY);
2402 	}
2403 	len = (size_t)(currentp - hostidp);
2404 
2405 	/*
2406 	 * The caller might pass a hostid that is larger than the maximum
2407 	 * unsigned 32-bit integral value.  Check for this!  Also, make sure
2408 	 * that the whole string is converted (this helps us find illegal
2409 	 * characters) and that the whole string fits within a buffer of size
2410 	 * HW_HOSTID_LEN.
2411 	 */
2412 	currentp = (char *)hostidp;
2413 	if (strncmp(hostidp, "0x", 2) == 0 || strncmp(hostidp, "0X", 2) == 0)
2414 		currentp += 2;
2415 	hostidval = strtoull(currentp, &currentp, 16);
2416 	if ((size_t)(currentp - hostidp) >= HW_HOSTID_LEN)
2417 		return (Z_TOO_BIG);
2418 	if (hostidval > UINT_MAX || hostidval == HW_INVALID_HOSTID ||
2419 	    currentp != hostidp + len)
2420 		return (Z_INVALID_PROPERTY);
2421 	return (Z_OK);
2422 }
2423 
2424 /*
2425  * Gets the zone hostid string stored in the specified zone configuration
2426  * document.  This function returns Z_OK on success.  Z_BAD_PROPERTY is returned
2427  * if the config file doesn't specify a hostid or if the hostid is blank.
2428  *
2429  * Note that buflen should be at least HW_HOSTID_LEN.
2430  */
2431 int
2432 zonecfg_get_hostid(zone_dochandle_t handle, char *bufp, size_t buflen)
2433 {
2434 	int err;
2435 
2436 	if ((err = getrootattr(handle, DTD_ATTR_HOSTID, bufp, buflen)) != Z_OK)
2437 		return (err);
2438 	if (bufp[0] == '\0')
2439 		return (Z_BAD_PROPERTY);
2440 	return (zonecfg_valid_hostid(bufp));
2441 }
2442 
2443 /*
2444  * Sets the hostid string in the specified zone config document to the given
2445  * string value.  If 'hostidp' is NULL, then the config document's hostid
2446  * attribute is cleared.  Non-NULL hostids are validated.  This function returns
2447  * Z_OK on success.  Any other return value indicates failure.
2448  */
2449 int
2450 zonecfg_set_hostid(zone_dochandle_t handle, const char *hostidp)
2451 {
2452 	int err;
2453 
2454 	/*
2455 	 * A NULL hostid string is interpreted as a request to clear the
2456 	 * hostid.
2457 	 */
2458 	if (hostidp == NULL || (err = zonecfg_valid_hostid(hostidp)) == Z_OK)
2459 		return (setrootattr(handle, DTD_ATTR_HOSTID, hostidp));
2460 	return (err);
2461 }
2462 
2463 int
2464 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2465 {
2466 	xmlNodePtr cur, firstmatch;
2467 	int err;
2468 	char match[MAXPATHLEN];
2469 
2470 	if (tabptr == NULL)
2471 		return (Z_INVAL);
2472 
2473 	if ((err = operation_prep(handle)) != Z_OK)
2474 		return (err);
2475 
2476 	cur = handle->zone_dh_cur;
2477 	firstmatch = NULL;
2478 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2479 		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2480 			continue;
2481 		if (strlen(tabptr->zone_dev_match) == 0)
2482 			continue;
2483 
2484 		if ((fetchprop(cur, DTD_ATTR_MATCH, match,
2485 		    sizeof (match)) == Z_OK)) {
2486 			if (strcmp(tabptr->zone_dev_match,
2487 			    match) == 0) {
2488 				if (firstmatch == NULL)
2489 					firstmatch = cur;
2490 				else if (firstmatch != cur)
2491 					return (Z_INSUFFICIENT_SPEC);
2492 			} else {
2493 				/*
2494 				 * If another property matched but this
2495 				 * one doesn't then reset firstmatch.
2496 				 */
2497 				if (firstmatch == cur)
2498 					firstmatch = NULL;
2499 			}
2500 		}
2501 	}
2502 	if (firstmatch == NULL)
2503 		return (Z_NO_RESOURCE_ID);
2504 
2505 	cur = firstmatch;
2506 
2507 	if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
2508 	    sizeof (tabptr->zone_dev_match))) != Z_OK)
2509 		return (err);
2510 
2511 	return (Z_OK);
2512 }
2513 
2514 static int
2515 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
2516 {
2517 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
2518 	int err;
2519 
2520 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL);
2521 
2522 	if ((err = newprop(newnode, DTD_ATTR_MATCH,
2523 	    tabptr->zone_dev_match)) != Z_OK)
2524 		return (err);
2525 
2526 	return (Z_OK);
2527 }
2528 
2529 int
2530 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2531 {
2532 	int err;
2533 
2534 	if (tabptr == NULL)
2535 		return (Z_INVAL);
2536 
2537 	if ((err = operation_prep(handle)) != Z_OK)
2538 		return (err);
2539 
2540 	if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK)
2541 		return (err);
2542 
2543 	return (Z_OK);
2544 }
2545 
2546 static int
2547 zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
2548 {
2549 	xmlNodePtr cur = handle->zone_dh_cur;
2550 	int match_match;
2551 
2552 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2553 		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2554 			continue;
2555 
2556 		match_match = match_prop(cur, DTD_ATTR_MATCH,
2557 		    tabptr->zone_dev_match);
2558 
2559 		if (match_match) {
2560 			xmlUnlinkNode(cur);
2561 			xmlFreeNode(cur);
2562 			return (Z_OK);
2563 		}
2564 	}
2565 	return (Z_NO_RESOURCE_ID);
2566 }
2567 
2568 int
2569 zonecfg_delete_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2570 {
2571 	int err;
2572 
2573 	if (tabptr == NULL)
2574 		return (Z_INVAL);
2575 
2576 	if ((err = operation_prep(handle)) != Z_OK)
2577 		return (err);
2578 
2579 	if ((err = zonecfg_delete_dev_core(handle, tabptr)) != Z_OK)
2580 		return (err);
2581 
2582 	return (Z_OK);
2583 }
2584 
2585 int
2586 zonecfg_modify_dev(
2587 	zone_dochandle_t handle,
2588 	struct zone_devtab *oldtabptr,
2589 	struct zone_devtab *newtabptr)
2590 {
2591 	int err;
2592 
2593 	if (oldtabptr == NULL || newtabptr == NULL)
2594 		return (Z_INVAL);
2595 
2596 	if ((err = operation_prep(handle)) != Z_OK)
2597 		return (err);
2598 
2599 	if ((err = zonecfg_delete_dev_core(handle, oldtabptr)) != Z_OK)
2600 		return (err);
2601 
2602 	if ((err = zonecfg_add_dev_core(handle, newtabptr)) != Z_OK)
2603 		return (err);
2604 
2605 	return (Z_OK);
2606 }
2607 
2608 static int
2609 zonecfg_add_auth_core(zone_dochandle_t handle, struct zone_admintab *tabptr,
2610     char *zonename)
2611 {
2612 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
2613 	int err;
2614 
2615 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ADMIN, NULL);
2616 	err = newprop(newnode, DTD_ATTR_USER, tabptr->zone_admin_user);
2617 	if (err != Z_OK)
2618 		return (err);
2619 	err = newprop(newnode, DTD_ATTR_AUTHS, tabptr->zone_admin_auths);
2620 	if (err != Z_OK)
2621 		return (err);
2622 	if ((err = zonecfg_remove_userauths(
2623 	    handle, tabptr->zone_admin_user, zonename, B_FALSE)) != Z_OK)
2624 		return (err);
2625 	return (Z_OK);
2626 }
2627 
2628 int
2629 zonecfg_add_admin(zone_dochandle_t handle, struct zone_admintab *tabptr,
2630     char *zonename)
2631 {
2632 	int err;
2633 
2634 	if (tabptr == NULL)
2635 		return (Z_INVAL);
2636 
2637 	if ((err = operation_prep(handle)) != Z_OK)
2638 		return (err);
2639 
2640 	if ((err = zonecfg_add_auth_core(handle, tabptr,
2641 	    zonename)) != Z_OK)
2642 		return (err);
2643 
2644 	return (Z_OK);
2645 }
2646 
2647 static int
2648 zonecfg_delete_auth_core(zone_dochandle_t handle, struct zone_admintab *tabptr,
2649     char *zonename)
2650 {
2651 	xmlNodePtr cur = handle->zone_dh_cur;
2652 	boolean_t auth_match;
2653 	int err;
2654 
2655 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2656 		if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
2657 			continue;
2658 		auth_match = match_prop(cur, DTD_ATTR_USER,
2659 		    tabptr->zone_admin_user);
2660 		if (auth_match) {
2661 			if ((err = zonecfg_insert_userauths(
2662 			    handle, tabptr->zone_admin_user,
2663 			    zonename)) != Z_OK)
2664 				return (err);
2665 			xmlUnlinkNode(cur);
2666 			xmlFreeNode(cur);
2667 			return (Z_OK);
2668 		}
2669 	}
2670 	return (Z_NO_RESOURCE_ID);
2671 }
2672 
2673 int
2674 zonecfg_delete_admin(zone_dochandle_t handle, struct zone_admintab *tabptr,
2675     char *zonename)
2676 {
2677 	int err;
2678 
2679 	if (tabptr == NULL)
2680 		return (Z_INVAL);
2681 
2682 	if ((err = operation_prep(handle)) != Z_OK)
2683 		return (err);
2684 
2685 	if ((err = zonecfg_delete_auth_core(handle, tabptr, zonename)) != Z_OK)
2686 		return (err);
2687 
2688 	return (Z_OK);
2689 }
2690 
2691 int
2692 zonecfg_modify_admin(zone_dochandle_t handle, struct zone_admintab *oldtabptr,
2693     struct zone_admintab *newtabptr, char *zonename)
2694 {
2695 	int err;
2696 
2697 	if (oldtabptr == NULL || newtabptr == NULL)
2698 		return (Z_INVAL);
2699 
2700 	if ((err = operation_prep(handle)) != Z_OK)
2701 		return (err);
2702 
2703 	if ((err = zonecfg_delete_auth_core(handle, oldtabptr, zonename))
2704 	    != Z_OK)
2705 		return (err);
2706 
2707 	if ((err = zonecfg_add_auth_core(handle, newtabptr,
2708 	    zonename)) != Z_OK)
2709 		return (err);
2710 
2711 	return (Z_OK);
2712 }
2713 
2714 int
2715 zonecfg_lookup_admin(zone_dochandle_t handle, struct zone_admintab *tabptr)
2716 {
2717 	xmlNodePtr cur, firstmatch;
2718 	int err;
2719 	char user[MAXUSERNAME];
2720 
2721 	if (tabptr == NULL)
2722 		return (Z_INVAL);
2723 
2724 	if ((err = operation_prep(handle)) != Z_OK)
2725 		return (err);
2726 
2727 	cur = handle->zone_dh_cur;
2728 	firstmatch = NULL;
2729 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2730 		if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
2731 			continue;
2732 		if (strlen(tabptr->zone_admin_user) > 0) {
2733 			if ((fetchprop(cur, DTD_ATTR_USER, user,
2734 			    sizeof (user)) == Z_OK) &&
2735 			    (strcmp(tabptr->zone_admin_user, user) == 0)) {
2736 				if (firstmatch == NULL)
2737 					firstmatch = cur;
2738 				else
2739 					return (Z_INSUFFICIENT_SPEC);
2740 			}
2741 		}
2742 	}
2743 	if (firstmatch == NULL)
2744 		return (Z_NO_RESOURCE_ID);
2745 
2746 	cur = firstmatch;
2747 
2748 	if ((err = fetchprop(cur, DTD_ATTR_USER, tabptr->zone_admin_user,
2749 	    sizeof (tabptr->zone_admin_user))) != Z_OK)
2750 		return (err);
2751 
2752 	if ((err = fetchprop(cur, DTD_ATTR_AUTHS, tabptr->zone_admin_auths,
2753 	    sizeof (tabptr->zone_admin_auths))) != Z_OK)
2754 		return (err);
2755 
2756 	return (Z_OK);
2757 }
2758 
2759 static int
2760 zonecfg_add_secflags_core(zone_dochandle_t handle,
2761     struct zone_secflagstab *tabptr)
2762 {
2763 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
2764 	int err;
2765 
2766 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_SECFLAGS, NULL);
2767 	err = newprop(newnode, DTD_ATTR_DEFAULT, tabptr->zone_secflags_default);
2768 	if (err != Z_OK)
2769 		return (err);
2770 	err = newprop(newnode, DTD_ATTR_LOWER, tabptr->zone_secflags_lower);
2771 	if (err != Z_OK)
2772 		return (err);
2773 	err = newprop(newnode, DTD_ATTR_UPPER, tabptr->zone_secflags_upper);
2774 	if (err != Z_OK)
2775 		return (err);
2776 
2777 	return (Z_OK);
2778 }
2779 
2780 int
2781 zonecfg_add_secflags(zone_dochandle_t handle, struct zone_secflagstab *tabptr)
2782 {
2783 	int err;
2784 
2785 
2786 	if (tabptr == NULL)
2787 		return (Z_INVAL);
2788 
2789 	if ((err = operation_prep(handle)) != Z_OK)
2790 		return (err);
2791 
2792 	if ((err = zonecfg_add_secflags_core(handle, tabptr)) != Z_OK)
2793 		return (err);
2794 
2795 	return (Z_OK);
2796 }
2797 
2798 static int
2799 zonecfg_delete_secflags_core(zone_dochandle_t handle,
2800     struct zone_secflagstab *tabptr)
2801 {
2802 	xmlNodePtr cur = handle->zone_dh_cur;
2803 	boolean_t def_match, low_match, up_match;
2804 
2805 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2806 		if (xmlStrcmp(cur->name, DTD_ELEM_SECFLAGS) != 0)
2807 			continue;
2808 
2809 		def_match = match_prop(cur, DTD_ATTR_DEFAULT,
2810 		    tabptr->zone_secflags_default);
2811 		low_match = match_prop(cur, DTD_ATTR_LOWER,
2812 		    tabptr->zone_secflags_lower);
2813 		up_match = match_prop(cur, DTD_ATTR_UPPER,
2814 		    tabptr->zone_secflags_upper);
2815 
2816 		if (def_match && low_match && up_match) {
2817 			xmlUnlinkNode(cur);
2818 			xmlFreeNode(cur);
2819 			return (Z_OK);
2820 		}
2821 
2822 	}
2823 	return (Z_NO_RESOURCE_ID);
2824 }
2825 
2826 int
2827 zonecfg_delete_secflags(zone_dochandle_t handle,
2828     struct zone_secflagstab *tabptr)
2829 {
2830 	int err;
2831 
2832 	if (tabptr == NULL)
2833 		return (Z_INVAL);
2834 
2835 	if ((err = operation_prep(handle)) != Z_OK)
2836 		return (err);
2837 
2838 	if ((err = zonecfg_delete_secflags_core(handle, tabptr)) != Z_OK)
2839 		return (err);
2840 
2841 	return (Z_OK);
2842 }
2843 
2844 int
2845 zonecfg_modify_secflags(zone_dochandle_t handle,
2846     struct zone_secflagstab *oldtabptr,
2847     struct zone_secflagstab *newtabptr)
2848 {
2849 	int err;
2850 
2851 	if (oldtabptr == NULL || newtabptr == NULL)
2852 		return (Z_INVAL);
2853 
2854 	if ((err = operation_prep(handle)) != Z_OK)
2855 		return (err);
2856 
2857 	if ((err = zonecfg_delete_secflags_core(handle, oldtabptr))
2858 	    != Z_OK)
2859 		return (err);
2860 
2861 	if ((err = zonecfg_add_secflags_core(handle, newtabptr)) != Z_OK)
2862 		return (err);
2863 
2864 	return (Z_OK);
2865 }
2866 
2867 int
2868 zonecfg_lookup_secflags(zone_dochandle_t handle,
2869     struct zone_secflagstab *tabptr)
2870 {
2871 	xmlNodePtr cur;
2872 	int err;
2873 
2874 	if (tabptr == NULL)
2875 		return (Z_INVAL);
2876 
2877 	if ((err = operation_prep(handle)) != Z_OK)
2878 		return (err);
2879 
2880 	cur = handle->zone_dh_cur;
2881 
2882 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2883 		if (xmlStrcmp(cur->name, DTD_ELEM_SECFLAGS) != 0)
2884 			continue;
2885 
2886 		if ((err = fetchprop(cur, DTD_ATTR_DEFAULT,
2887 		    tabptr->zone_secflags_default,
2888 		    sizeof (tabptr->zone_secflags_default))) != Z_OK) {
2889 			handle->zone_dh_cur = handle->zone_dh_top;
2890 			return (err);
2891 		}
2892 
2893 		if ((err = fetchprop(cur, DTD_ATTR_LOWER,
2894 		    tabptr->zone_secflags_lower,
2895 		    sizeof (tabptr->zone_secflags_lower))) != Z_OK) {
2896 			handle->zone_dh_cur = handle->zone_dh_top;
2897 			return (err);
2898 		}
2899 
2900 		if ((err = fetchprop(cur, DTD_ATTR_UPPER,
2901 		    tabptr->zone_secflags_upper,
2902 		    sizeof (tabptr->zone_secflags_upper))) != Z_OK) {
2903 			handle->zone_dh_cur = handle->zone_dh_top;
2904 			return (err);
2905 		}
2906 
2907 		return (Z_OK);
2908 	}
2909 
2910 	return (Z_NO_ENTRY);
2911 }
2912 
2913 /* Lock to serialize all devwalks */
2914 static pthread_mutex_t zonecfg_devwalk_lock = PTHREAD_MUTEX_INITIALIZER;
2915 /*
2916  * Global variables used to pass data from zonecfg_dev_manifest to the nftw
2917  * call-back (zonecfg_devwalk_cb).  g_devwalk_data is really the void*
2918  * parameter and g_devwalk_cb is really the *cb parameter from
2919  * zonecfg_dev_manifest.
2920  */
2921 typedef struct __g_devwalk_data *g_devwalk_data_t;
2922 static g_devwalk_data_t g_devwalk_data;
2923 static int (*g_devwalk_cb)(const char *, uid_t, gid_t, mode_t, const char *,
2924     void *);
2925 static size_t g_devwalk_skip_prefix;
2926 
2927 /*
2928  * zonecfg_dev_manifest call-back function used during detach to generate the
2929  * dev info in the manifest.
2930  */
2931 static int
2932 get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode,
2933     const char *acl, void *hdl)
2934 {
2935 	zone_dochandle_t handle = (zone_dochandle_t)hdl;
2936 	xmlNodePtr newnode;
2937 	xmlNodePtr cur;
2938 	int err;
2939 	char buf[128];
2940 
2941 	if ((err = operation_prep(handle)) != Z_OK)
2942 		return (err);
2943 
2944 	cur = handle->zone_dh_cur;
2945 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL);
2946 	if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK)
2947 		return (err);
2948 	(void) snprintf(buf, sizeof (buf), "%lu", uid);
2949 	if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK)
2950 		return (err);
2951 	(void) snprintf(buf, sizeof (buf), "%lu", gid);
2952 	if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK)
2953 		return (err);
2954 	(void) snprintf(buf, sizeof (buf), "%o", mode);
2955 	if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK)
2956 		return (err);
2957 	if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK)
2958 		return (err);
2959 	return (Z_OK);
2960 }
2961 
2962 /*
2963  * This is the nftw call-back function used by zonecfg_dev_manifest.  It is
2964  * responsible for calling the actual call-back.
2965  */
2966 /* ARGSUSED2 */
2967 static int
2968 zonecfg_devwalk_cb(const char *path, const struct stat *st, int f,
2969     struct FTW *ftw)
2970 {
2971 	acl_t *acl;
2972 	char *acl_txt = NULL;
2973 
2974 	/* skip all but character and block devices */
2975 	if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode))
2976 		return (0);
2977 
2978 	if ((acl_get(path, ACL_NO_TRIVIAL, &acl) == 0) &&
2979 	    acl != NULL) {
2980 		acl_txt = acl_totext(acl, ACL_NORESOLVE);
2981 		acl_free(acl);
2982 	}
2983 
2984 	if (strlen(path) <= g_devwalk_skip_prefix)
2985 		return (0);
2986 
2987 	(void) g_devwalk_cb(path + g_devwalk_skip_prefix, st->st_uid,
2988 	    st->st_gid, st->st_mode & S_IAMB, acl_txt != NULL ? acl_txt : "",
2989 	    g_devwalk_data);
2990 	free(acl_txt);
2991 	return (0);
2992 }
2993 
2994 /*
2995  * Walk the dev tree for the zone specified by hdl and call the
2996  * get_detach_dev_entry call-back function for each entry in the tree.  The
2997  * call-back will be passed the name, uid, gid, mode, acl string and the
2998  * handle input parameter for each dev entry.
2999  *
3000  * Data is passed to get_detach_dev_entry through the global variables
3001  * g_devwalk_data, *g_devwalk_cb, and g_devwalk_skip_prefix.  The
3002  * zonecfg_devwalk_cb function will actually call get_detach_dev_entry.
3003  */
3004 int
3005 zonecfg_dev_manifest(zone_dochandle_t hdl)
3006 {
3007 	char path[MAXPATHLEN];
3008 	int ret;
3009 
3010 	if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK)
3011 		return (ret);
3012 
3013 	if (strlcat(path, "/dev", sizeof (path)) >= sizeof (path))
3014 		return (Z_TOO_BIG);
3015 
3016 	/*
3017 	 * We have to serialize all devwalks in the same process
3018 	 * (which should be fine), since nftw() is so badly designed.
3019 	 */
3020 	(void) pthread_mutex_lock(&zonecfg_devwalk_lock);
3021 
3022 	g_devwalk_skip_prefix = strlen(path) + 1;
3023 	g_devwalk_data = (g_devwalk_data_t)hdl;
3024 	g_devwalk_cb = get_detach_dev_entry;
3025 	(void) nftw(path, zonecfg_devwalk_cb, 0, FTW_PHYS);
3026 
3027 	(void) pthread_mutex_unlock(&zonecfg_devwalk_lock);
3028 	return (Z_OK);
3029 }
3030 
3031 /*
3032  * Update the owner, group, mode and acl on the specified dev (inpath) for
3033  * the zone (hdl).  This function can be used to fix up the dev tree after
3034  * attaching a migrated zone.
3035  */
3036 int
3037 zonecfg_devperms_apply(zone_dochandle_t hdl, const char *inpath, uid_t owner,
3038     gid_t group, mode_t mode, const char *acltxt)
3039 {
3040 	int ret;
3041 	char path[MAXPATHLEN];
3042 	struct stat st;
3043 	acl_t *aclp;
3044 
3045 	if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK)
3046 		return (ret);
3047 
3048 	if (strlcat(path, "/dev/", sizeof (path)) >= sizeof (path))
3049 		return (Z_TOO_BIG);
3050 	if (strlcat(path, inpath, sizeof (path)) >= sizeof (path))
3051 		return (Z_TOO_BIG);
3052 
3053 	if (stat(path, &st) == -1)
3054 		return (Z_INVAL);
3055 
3056 	/* make sure we're only touching device nodes */
3057 	if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode))
3058 		return (Z_INVAL);
3059 
3060 	if (chown(path, owner, group) == -1)
3061 		return (Z_SYSTEM);
3062 
3063 	if (chmod(path, mode) == -1)
3064 		return (Z_SYSTEM);
3065 
3066 	if ((acltxt == NULL) || (strcmp(acltxt, "") == 0))
3067 		return (Z_OK);
3068 
3069 	if (acl_fromtext(acltxt, &aclp) != 0) {
3070 		errno = EINVAL;
3071 		return (Z_SYSTEM);
3072 	}
3073 
3074 	errno = 0;
3075 	if (acl_set(path, aclp) == -1) {
3076 		free(aclp);
3077 		return (Z_SYSTEM);
3078 	}
3079 
3080 	free(aclp);
3081 	return (Z_OK);
3082 }
3083 
3084 /*
3085  * This function finds everything mounted under a zone's rootpath.
3086  * This returns the number of mounts under rootpath, or -1 on error.
3087  * callback is called once per mount found with the first argument
3088  * pointing to a mnttab structure containing the mount's information.
3089  *
3090  * If the callback function returns non-zero zonecfg_find_mounts
3091  * aborts with an error.
3092  */
3093 int
3094 zonecfg_find_mounts(char *rootpath, int (*callback)(const struct mnttab *,
3095     void *), void *priv)
3096 {
3097 	FILE *mnttab;
3098 	struct mnttab m;
3099 	size_t l;
3100 	int zfsl;
3101 	int rv = 0;
3102 	char zfs_path[MAXPATHLEN];
3103 
3104 	assert(rootpath != NULL);
3105 
3106 	if ((zfsl = snprintf(zfs_path, sizeof (zfs_path), "%s/.zfs/", rootpath))
3107 	    >= sizeof (zfs_path))
3108 		return (-1);
3109 
3110 	l = strlen(rootpath);
3111 
3112 	mnttab = fopen("/etc/mnttab", "r");
3113 
3114 	if (mnttab == NULL)
3115 		return (-1);
3116 
3117 	if (ioctl(fileno(mnttab), MNTIOC_SHOWHIDDEN, NULL) < 0)  {
3118 		rv = -1;
3119 		goto out;
3120 	}
3121 
3122 	while (!getmntent(mnttab, &m)) {
3123 		if ((strncmp(rootpath, m.mnt_mountp, l) == 0) &&
3124 		    (m.mnt_mountp[l] == '/') &&
3125 		    (strncmp(zfs_path, m.mnt_mountp, zfsl) != 0)) {
3126 			rv++;
3127 			if (callback == NULL)
3128 				continue;
3129 			if (callback(&m, priv)) {
3130 				rv = -1;
3131 				goto out;
3132 
3133 			}
3134 		}
3135 	}
3136 
3137 out:
3138 	(void) fclose(mnttab);
3139 	return (rv);
3140 }
3141 
3142 int
3143 zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3144 {
3145 	xmlNodePtr cur, firstmatch;
3146 	int err;
3147 	char name[MAXNAMELEN], type[MAXNAMELEN], value[MAXNAMELEN];
3148 
3149 	if (tabptr == NULL)
3150 		return (Z_INVAL);
3151 
3152 	if ((err = operation_prep(handle)) != Z_OK)
3153 		return (err);
3154 
3155 	cur = handle->zone_dh_cur;
3156 	firstmatch = NULL;
3157 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
3158 		if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
3159 			continue;
3160 		if (strlen(tabptr->zone_attr_name) > 0) {
3161 			if ((fetchprop(cur, DTD_ATTR_NAME, name,
3162 			    sizeof (name)) == Z_OK) &&
3163 			    (strcmp(tabptr->zone_attr_name, name) == 0)) {
3164 				if (firstmatch == NULL)
3165 					firstmatch = cur;
3166 				else
3167 					return (Z_INSUFFICIENT_SPEC);
3168 			}
3169 		}
3170 		if (strlen(tabptr->zone_attr_type) > 0) {
3171 			if ((fetchprop(cur, DTD_ATTR_TYPE, type,
3172 			    sizeof (type)) == Z_OK)) {
3173 				if (strcmp(tabptr->zone_attr_type, type) == 0) {
3174 					if (firstmatch == NULL)
3175 						firstmatch = cur;
3176 					else if (firstmatch != cur)
3177 						return (Z_INSUFFICIENT_SPEC);
3178 				} else {
3179 					/*
3180 					 * If another property matched but this
3181 					 * one doesn't then reset firstmatch.
3182 					 */
3183 					if (firstmatch == cur)
3184 						firstmatch = NULL;
3185 				}
3186 			}
3187 		}
3188 		if (strlen(tabptr->zone_attr_value) > 0) {
3189 			if ((fetchprop(cur, DTD_ATTR_VALUE, value,
3190 			    sizeof (value)) == Z_OK)) {
3191 				if (strcmp(tabptr->zone_attr_value, value) ==
3192 				    0) {
3193 					if (firstmatch == NULL)
3194 						firstmatch = cur;
3195 					else if (firstmatch != cur)
3196 						return (Z_INSUFFICIENT_SPEC);
3197 				} else {
3198 					/*
3199 					 * If another property matched but this
3200 					 * one doesn't then reset firstmatch.
3201 					 */
3202 					if (firstmatch == cur)
3203 						firstmatch = NULL;
3204 				}
3205 			}
3206 		}
3207 	}
3208 	if (firstmatch == NULL)
3209 		return (Z_NO_RESOURCE_ID);
3210 
3211 	cur = firstmatch;
3212 
3213 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
3214 	    sizeof (tabptr->zone_attr_name))) != Z_OK)
3215 		return (err);
3216 
3217 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
3218 	    sizeof (tabptr->zone_attr_type))) != Z_OK)
3219 		return (err);
3220 
3221 	if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
3222 	    sizeof (tabptr->zone_attr_value))) != Z_OK)
3223 		return (err);
3224 
3225 	return (Z_OK);
3226 }
3227 
3228 static int
3229 zonecfg_add_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3230 {
3231 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
3232 	int err;
3233 
3234 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ATTR, NULL);
3235 	err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_attr_name);
3236 	if (err != Z_OK)
3237 		return (err);
3238 	err = newprop(newnode, DTD_ATTR_TYPE, tabptr->zone_attr_type);
3239 	if (err != Z_OK)
3240 		return (err);
3241 	err = newprop(newnode, DTD_ATTR_VALUE, tabptr->zone_attr_value);
3242 	if (err != Z_OK)
3243 		return (err);
3244 	return (Z_OK);
3245 }
3246 
3247 int
3248 zonecfg_add_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3249 {
3250 	int err;
3251 
3252 	if (tabptr == NULL)
3253 		return (Z_INVAL);
3254 
3255 	if ((err = operation_prep(handle)) != Z_OK)
3256 		return (err);
3257 
3258 	if ((err = zonecfg_add_attr_core(handle, tabptr)) != Z_OK)
3259 		return (err);
3260 
3261 	return (Z_OK);
3262 }
3263 
3264 static int
3265 zonecfg_delete_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3266 {
3267 	xmlNodePtr cur = handle->zone_dh_cur;
3268 	int name_match, type_match, value_match;
3269 
3270 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
3271 		if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
3272 			continue;
3273 
3274 		name_match = match_prop(cur, DTD_ATTR_NAME,
3275 		    tabptr->zone_attr_name);
3276 		type_match = match_prop(cur, DTD_ATTR_TYPE,
3277 		    tabptr->zone_attr_type);
3278 		value_match = match_prop(cur, DTD_ATTR_VALUE,
3279 		    tabptr->zone_attr_value);
3280 
3281 		if (name_match && type_match && value_match) {
3282 			xmlUnlinkNode(cur);
3283 			xmlFreeNode(cur);
3284 			return (Z_OK);
3285 		}
3286 	}
3287 	return (Z_NO_RESOURCE_ID);
3288 }
3289 
3290 int
3291 zonecfg_delete_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3292 {
3293 	int err;
3294 
3295 	if (tabptr == NULL)
3296 		return (Z_INVAL);
3297 
3298 	if ((err = operation_prep(handle)) != Z_OK)
3299 		return (err);
3300 
3301 	if ((err = zonecfg_delete_attr_core(handle, tabptr)) != Z_OK)
3302 		return (err);
3303 
3304 	return (Z_OK);
3305 }
3306 
3307 int
3308 zonecfg_modify_attr(
3309 	zone_dochandle_t handle,
3310 	struct zone_attrtab *oldtabptr,
3311 	struct zone_attrtab *newtabptr)
3312 {
3313 	int err;
3314 
3315 	if (oldtabptr == NULL || newtabptr == NULL)
3316 		return (Z_INVAL);
3317 
3318 	if ((err = operation_prep(handle)) != Z_OK)
3319 		return (err);
3320 
3321 	if ((err = zonecfg_delete_attr_core(handle, oldtabptr)) != Z_OK)
3322 		return (err);
3323 
3324 	if ((err = zonecfg_add_attr_core(handle, newtabptr)) != Z_OK)
3325 		return (err);
3326 
3327 	return (Z_OK);
3328 }
3329 
3330 int
3331 zonecfg_get_attr_boolean(const struct zone_attrtab *attr, boolean_t *value)
3332 {
3333 	if (attr == NULL)
3334 		return (Z_INVAL);
3335 
3336 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_BOOLEAN) != 0)
3337 		return (Z_INVAL);
3338 
3339 	if (strcmp(attr->zone_attr_value, DTD_ENTITY_TRUE) == 0) {
3340 		*value = B_TRUE;
3341 		return (Z_OK);
3342 	}
3343 	if (strcmp(attr->zone_attr_value, DTD_ENTITY_FALSE) == 0) {
3344 		*value = B_FALSE;
3345 		return (Z_OK);
3346 	}
3347 	return (Z_INVAL);
3348 }
3349 
3350 int
3351 zonecfg_get_attr_int(const struct zone_attrtab *attr, int64_t *value)
3352 {
3353 	long long result;
3354 	char *endptr;
3355 
3356 	if (attr == NULL)
3357 		return (Z_INVAL);
3358 
3359 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_INT) != 0)
3360 		return (Z_INVAL);
3361 
3362 	errno = 0;
3363 	result = strtoll(attr->zone_attr_value, &endptr, 10);
3364 	if (errno != 0 || *endptr != '\0')
3365 		return (Z_INVAL);
3366 	*value = result;
3367 	return (Z_OK);
3368 }
3369 
3370 int
3371 zonecfg_get_attr_string(const struct zone_attrtab *attr, char *value,
3372     size_t val_sz)
3373 {
3374 	if (attr == NULL)
3375 		return (Z_INVAL);
3376 
3377 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_STRING) != 0)
3378 		return (Z_INVAL);
3379 
3380 	if (strlcpy(value, attr->zone_attr_value, val_sz) >= val_sz)
3381 		return (Z_TOO_BIG);
3382 	return (Z_OK);
3383 }
3384 
3385 int
3386 zonecfg_get_attr_uint(const struct zone_attrtab *attr, uint64_t *value)
3387 {
3388 	unsigned long long result;
3389 	long long neg_result;
3390 	char *endptr;
3391 
3392 	if (attr == NULL)
3393 		return (Z_INVAL);
3394 
3395 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_UINT) != 0)
3396 		return (Z_INVAL);
3397 
3398 	errno = 0;
3399 	result = strtoull(attr->zone_attr_value, &endptr, 10);
3400 	if (errno != 0 || *endptr != '\0')
3401 		return (Z_INVAL);
3402 	errno = 0;
3403 	neg_result = strtoll(attr->zone_attr_value, &endptr, 10);
3404 	/*
3405 	 * Incredibly, strtoull("<negative number>", ...) will not fail but
3406 	 * return whatever (negative) number cast as a u_longlong_t, so we
3407 	 * need to look for this here.
3408 	 */
3409 	if (errno == 0 && neg_result < 0)
3410 		return (Z_INVAL);
3411 	*value = result;
3412 	return (Z_OK);
3413 }
3414 
3415 int
3416 zonecfg_lookup_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3417 {
3418 	xmlNodePtr cur, val;
3419 	char savedname[MAXNAMELEN];
3420 	struct zone_rctlvaltab *valptr;
3421 	int err;
3422 
3423 	if (strlen(tabptr->zone_rctl_name) == 0)
3424 		return (Z_INVAL);
3425 
3426 	if ((err = operation_prep(handle)) != Z_OK)
3427 		return (err);
3428 
3429 	cur = handle->zone_dh_cur;
3430 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
3431 		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL))
3432 			continue;
3433 		if ((fetchprop(cur, DTD_ATTR_NAME, savedname,
3434 		    sizeof (savedname)) == Z_OK) &&
3435 		    (strcmp(savedname, tabptr->zone_rctl_name) == 0)) {
3436 			tabptr->zone_rctl_valptr = NULL;
3437 			for (val = cur->xmlChildrenNode; val != NULL;
3438 			    val = val->next) {
3439 				valptr = (struct zone_rctlvaltab *)malloc(
3440 				    sizeof (struct zone_rctlvaltab));
3441 				if (valptr == NULL)
3442 					return (Z_NOMEM);
3443 				if ((fetchprop(val, DTD_ATTR_PRIV,
3444 				    valptr->zone_rctlval_priv,
3445 				    sizeof (valptr->zone_rctlval_priv)) !=
3446 				    Z_OK))
3447 					break;
3448 				if ((fetchprop(val, DTD_ATTR_LIMIT,
3449 				    valptr->zone_rctlval_limit,
3450 				    sizeof (valptr->zone_rctlval_limit)) !=
3451 				    Z_OK))
3452 					break;
3453 				if ((fetchprop(val, DTD_ATTR_ACTION,
3454 				    valptr->zone_rctlval_action,
3455 				    sizeof (valptr->zone_rctlval_action)) !=
3456 				    Z_OK))
3457 					break;
3458 				if (zonecfg_add_rctl_value(tabptr, valptr) !=
3459 				    Z_OK)
3460 					break;
3461 			}
3462 			return (Z_OK);
3463 		}
3464 	}
3465 	return (Z_NO_RESOURCE_ID);
3466 }
3467 
3468 static int
3469 zonecfg_add_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3470 {
3471 	xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode;
3472 	struct zone_rctlvaltab *valptr;
3473 	int err;
3474 
3475 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_RCTL, NULL);
3476 	err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_rctl_name);
3477 	if (err != Z_OK)
3478 		return (err);
3479 	for (valptr = tabptr->zone_rctl_valptr; valptr != NULL;
3480 	    valptr = valptr->zone_rctlval_next) {
3481 		valnode = xmlNewTextChild(newnode, NULL,
3482 		    DTD_ELEM_RCTLVALUE, NULL);
3483 		err = newprop(valnode, DTD_ATTR_PRIV,
3484 		    valptr->zone_rctlval_priv);
3485 		if (err != Z_OK)
3486 			return (err);
3487 		err = newprop(valnode, DTD_ATTR_LIMIT,
3488 		    valptr->zone_rctlval_limit);
3489 		if (err != Z_OK)
3490 			return (err);
3491 		err = newprop(valnode, DTD_ATTR_ACTION,
3492 		    valptr->zone_rctlval_action);
3493 		if (err != Z_OK)
3494 			return (err);
3495 	}
3496 	return (Z_OK);
3497 }
3498 
3499 int
3500 zonecfg_add_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3501 {
3502 	int err;
3503 
3504 	if (tabptr == NULL)
3505 		return (Z_INVAL);
3506 
3507 	if ((err = operation_prep(handle)) != Z_OK)
3508 		return (err);
3509 
3510 	if ((err = zonecfg_add_rctl_core(handle, tabptr)) != Z_OK)
3511 		return (err);
3512 
3513 	return (Z_OK);
3514 }
3515 
3516 static int
3517 zonecfg_delete_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3518 {
3519 	xmlNodePtr cur = handle->zone_dh_cur;
3520 	xmlChar *savedname;
3521 	int name_result;
3522 
3523 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
3524 		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL))
3525 			continue;
3526 
3527 		savedname = xmlGetProp(cur, DTD_ATTR_NAME);
3528 		if (savedname == NULL)	/* shouldn't happen */
3529 			continue;
3530 		name_result = xmlStrcmp(savedname,
3531 		    (const xmlChar *) tabptr->zone_rctl_name);
3532 		xmlFree(savedname);
3533 
3534 		if (name_result == 0) {
3535 			xmlUnlinkNode(cur);
3536 			xmlFreeNode(cur);
3537 			return (Z_OK);
3538 		}
3539 	}
3540 	return (Z_NO_RESOURCE_ID);
3541 }
3542 
3543 int
3544 zonecfg_delete_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3545 {
3546 	int err;
3547 
3548 	if (tabptr == NULL)
3549 		return (Z_INVAL);
3550 
3551 	if ((err = operation_prep(handle)) != Z_OK)
3552 		return (err);
3553 
3554 	if ((err = zonecfg_delete_rctl_core(handle, tabptr)) != Z_OK)
3555 		return (err);
3556 
3557 	return (Z_OK);
3558 }
3559 
3560 int
3561 zonecfg_modify_rctl(
3562 	zone_dochandle_t handle,
3563 	struct zone_rctltab *oldtabptr,
3564 	struct zone_rctltab *newtabptr)
3565 {
3566 	int err;
3567 
3568 	if (oldtabptr == NULL || newtabptr == NULL)
3569 		return (Z_INVAL);
3570 
3571 	if ((err = operation_prep(handle)) != Z_OK)
3572 		return (err);
3573 
3574 	if ((err = zonecfg_delete_rctl_core(handle, oldtabptr)) != Z_OK)
3575 		return (err);
3576 
3577 	if ((err = zonecfg_add_rctl_core(handle, newtabptr)) != Z_OK)
3578 		return (err);
3579 
3580 	return (Z_OK);
3581 }
3582 
3583 int
3584 zonecfg_add_rctl_value(
3585 	struct zone_rctltab *tabptr,
3586 	struct zone_rctlvaltab *valtabptr)
3587 {
3588 	struct zone_rctlvaltab *last, *old, *new;
3589 	rctlblk_t *rctlblk = alloca(rctlblk_size());
3590 
3591 	last = tabptr->zone_rctl_valptr;
3592 	for (old = last; old != NULL; old = old->zone_rctlval_next)
3593 		last = old;	/* walk to the end of the list */
3594 	new = valtabptr;	/* alloc'd by caller */
3595 	new->zone_rctlval_next = NULL;
3596 	if (zonecfg_construct_rctlblk(valtabptr, rctlblk) != Z_OK)
3597 		return (Z_INVAL);
3598 	if (!zonecfg_valid_rctlblk(rctlblk))
3599 		return (Z_INVAL);
3600 	if (last == NULL)
3601 		tabptr->zone_rctl_valptr = new;
3602 	else
3603 		last->zone_rctlval_next = new;
3604 	return (Z_OK);
3605 }
3606 
3607 int
3608 zonecfg_remove_rctl_value(
3609 	struct zone_rctltab *tabptr,
3610 	struct zone_rctlvaltab *valtabptr)
3611 {
3612 	struct zone_rctlvaltab *last, *this, *next;
3613 
3614 	last = tabptr->zone_rctl_valptr;
3615 	for (this = last; this != NULL; this = this->zone_rctlval_next) {
3616 		if (strcmp(this->zone_rctlval_priv,
3617 		    valtabptr->zone_rctlval_priv) == 0 &&
3618 		    strcmp(this->zone_rctlval_limit,
3619 		    valtabptr->zone_rctlval_limit) == 0 &&
3620 		    strcmp(this->zone_rctlval_action,
3621 		    valtabptr->zone_rctlval_action) == 0) {
3622 			next = this->zone_rctlval_next;
3623 			if (this == tabptr->zone_rctl_valptr)
3624 				tabptr->zone_rctl_valptr = next;
3625 			else
3626 				last->zone_rctlval_next = next;
3627 			free(this);
3628 			return (Z_OK);
3629 		} else
3630 			last = this;
3631 	}
3632 	return (Z_NO_PROPERTY_ID);
3633 }
3634 
3635 void
3636 zonecfg_set_swinv(zone_dochandle_t handle)
3637 {
3638 	handle->zone_dh_sw_inv = B_TRUE;
3639 }
3640 
3641 /*
3642  * Add the pkg to the sw inventory on the handle.
3643  */
3644 int
3645 zonecfg_add_pkg(zone_dochandle_t handle, char *name, char *version)
3646 {
3647 	xmlNodePtr newnode;
3648 	xmlNodePtr cur;
3649 	int err;
3650 
3651 	if ((err = operation_prep(handle)) != Z_OK)
3652 		return (err);
3653 
3654 	cur = handle->zone_dh_cur;
3655 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL);
3656 	if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK)
3657 		return (err);
3658 	if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK)
3659 		return (err);
3660 	return (Z_OK);
3661 }
3662 
3663 char *
3664 zonecfg_strerror(int errnum)
3665 {
3666 	switch (errnum) {
3667 	case Z_OK:
3668 		return (dgettext(TEXT_DOMAIN, "OK"));
3669 	case Z_EMPTY_DOCUMENT:
3670 		return (dgettext(TEXT_DOMAIN, "Empty document"));
3671 	case Z_WRONG_DOC_TYPE:
3672 		return (dgettext(TEXT_DOMAIN, "Wrong document type"));
3673 	case Z_BAD_PROPERTY:
3674 		return (dgettext(TEXT_DOMAIN, "Bad document property"));
3675 	case Z_TEMP_FILE:
3676 		return (dgettext(TEXT_DOMAIN,
3677 		    "Problem creating temporary file"));
3678 	case Z_SAVING_FILE:
3679 		return (dgettext(TEXT_DOMAIN, "Problem saving file"));
3680 	case Z_NO_ENTRY:
3681 		return (dgettext(TEXT_DOMAIN, "No such entry"));
3682 	case Z_BOGUS_ZONE_NAME:
3683 		return (dgettext(TEXT_DOMAIN, "Bogus zone name"));
3684 	case Z_REQD_RESOURCE_MISSING:
3685 		return (dgettext(TEXT_DOMAIN, "Required resource missing"));
3686 	case Z_REQD_PROPERTY_MISSING:
3687 		return (dgettext(TEXT_DOMAIN, "Required property missing"));
3688 	case Z_BAD_HANDLE:
3689 		return (dgettext(TEXT_DOMAIN, "Bad handle"));
3690 	case Z_NOMEM:
3691 		return (dgettext(TEXT_DOMAIN, "Out of memory"));
3692 	case Z_INVAL:
3693 		return (dgettext(TEXT_DOMAIN, "Invalid argument"));
3694 	case Z_ACCES:
3695 		return (dgettext(TEXT_DOMAIN, "Permission denied"));
3696 	case Z_TOO_BIG:
3697 		return (dgettext(TEXT_DOMAIN, "Argument list too long"));
3698 	case Z_MISC_FS:
3699 		return (dgettext(TEXT_DOMAIN,
3700 		    "Miscellaneous file system error"));
3701 	case Z_NO_ZONE:
3702 		return (dgettext(TEXT_DOMAIN, "No such zone configured"));
3703 	case Z_NO_RESOURCE_TYPE:
3704 		return (dgettext(TEXT_DOMAIN, "No such resource type"));
3705 	case Z_NO_RESOURCE_ID:
3706 		return (dgettext(TEXT_DOMAIN, "No such resource with that id"));
3707 	case Z_NO_PROPERTY_TYPE:
3708 		return (dgettext(TEXT_DOMAIN, "No such property type"));
3709 	case Z_NO_PROPERTY_ID:
3710 		return (dgettext(TEXT_DOMAIN, "No such property with that id"));
3711 	case Z_BAD_ZONE_STATE:
3712 		return (dgettext(TEXT_DOMAIN,
3713 		    "Zone state is invalid for the requested operation"));
3714 	case Z_INVALID_DOCUMENT:
3715 		return (dgettext(TEXT_DOMAIN, "Invalid document"));
3716 	case Z_NAME_IN_USE:
3717 		return (dgettext(TEXT_DOMAIN, "Zone name already in use"));
3718 	case Z_NO_SUCH_ID:
3719 		return (dgettext(TEXT_DOMAIN, "No such zone ID"));
3720 	case Z_UPDATING_INDEX:
3721 		return (dgettext(TEXT_DOMAIN, "Problem updating index file"));
3722 	case Z_LOCKING_FILE:
3723 		return (dgettext(TEXT_DOMAIN, "Locking index file"));
3724 	case Z_UNLOCKING_FILE:
3725 		return (dgettext(TEXT_DOMAIN, "Unlocking index file"));
3726 	case Z_INSUFFICIENT_SPEC:
3727 		return (dgettext(TEXT_DOMAIN, "Insufficient specification"));
3728 	case Z_RESOLVED_PATH:
3729 		return (dgettext(TEXT_DOMAIN, "Resolved path mismatch"));
3730 	case Z_IPV6_ADDR_PREFIX_LEN:
3731 		return (dgettext(TEXT_DOMAIN,
3732 		    "IPv6 address missing required prefix length"));
3733 	case Z_BOGUS_ADDRESS:
3734 		return (dgettext(TEXT_DOMAIN,
3735 		    "Neither an IPv4 nor an IPv6 address nor a host name"));
3736 	case Z_PRIV_PROHIBITED:
3737 		return (dgettext(TEXT_DOMAIN,
3738 		    "Specified privilege is prohibited"));
3739 	case Z_PRIV_REQUIRED:
3740 		return (dgettext(TEXT_DOMAIN,
3741 		    "Required privilege is missing"));
3742 	case Z_PRIV_UNKNOWN:
3743 		return (dgettext(TEXT_DOMAIN,
3744 		    "Specified privilege is unknown"));
3745 	case Z_BRAND_ERROR:
3746 		return (dgettext(TEXT_DOMAIN,
3747 		    "Brand-specific error"));
3748 	case Z_INCOMPATIBLE:
3749 		return (dgettext(TEXT_DOMAIN, "Incompatible settings"));
3750 	case Z_ALIAS_DISALLOW:
3751 		return (dgettext(TEXT_DOMAIN,
3752 		    "An incompatible rctl already exists for this property"));
3753 	case Z_CLEAR_DISALLOW:
3754 		return (dgettext(TEXT_DOMAIN,
3755 		    "Clearing this property is not allowed"));
3756 	case Z_POOL:
3757 		return (dgettext(TEXT_DOMAIN, "libpool(3LIB) error"));
3758 	case Z_POOLS_NOT_ACTIVE:
3759 		return (dgettext(TEXT_DOMAIN, "Pools facility not active; "
3760 		    "zone will not be bound to pool"));
3761 	case Z_POOL_ENABLE:
3762 		return (dgettext(TEXT_DOMAIN,
3763 		    "Could not enable pools facility"));
3764 	case Z_NO_POOL:
3765 		return (dgettext(TEXT_DOMAIN,
3766 		    "Pool not found; using default pool"));
3767 	case Z_POOL_CREATE:
3768 		return (dgettext(TEXT_DOMAIN,
3769 		    "Could not create a temporary pool"));
3770 	case Z_POOL_BIND:
3771 		return (dgettext(TEXT_DOMAIN, "Could not bind zone to pool"));
3772 	case Z_INVALID_PROPERTY:
3773 		return (dgettext(TEXT_DOMAIN, "Specified property is invalid"));
3774 	case Z_SYSTEM:
3775 		return (strerror(errno));
3776 	default:
3777 		return (dgettext(TEXT_DOMAIN, "Unknown error"));
3778 	}
3779 }
3780 
3781 /*
3782  * Note that the zonecfg_setXent() and zonecfg_endXent() calls are all the
3783  * same, as they just turn around and call zonecfg_setent() / zonecfg_endent().
3784  */
3785 
3786 static int
3787 zonecfg_setent(zone_dochandle_t handle)
3788 {
3789 	xmlNodePtr cur;
3790 	int err;
3791 
3792 	if (handle == NULL)
3793 		return (Z_INVAL);
3794 
3795 	if ((err = operation_prep(handle)) != Z_OK) {
3796 		handle->zone_dh_cur = NULL;
3797 		return (err);
3798 	}
3799 	cur = handle->zone_dh_cur;
3800 	cur = cur->xmlChildrenNode;
3801 	handle->zone_dh_cur = cur;
3802 	return (Z_OK);
3803 }
3804 
3805 static int
3806 zonecfg_endent(zone_dochandle_t handle)
3807 {
3808 	if (handle == NULL)
3809 		return (Z_INVAL);
3810 
3811 	handle->zone_dh_cur = handle->zone_dh_top;
3812 	return (Z_OK);
3813 }
3814 
3815 /*
3816  * Do the work required to manipulate a process through libproc.
3817  * If grab_process() returns no errors (0), then release_process()
3818  * must eventually be called.
3819  *
3820  * Return values:
3821  *      0 Successful creation of agent thread
3822  *      1 Error grabbing
3823  *      2 Error creating agent
3824  */
3825 static int
3826 grab_process(pr_info_handle_t *p)
3827 {
3828 	int ret;
3829 
3830 	if ((p->pr = Pgrab(p->pid, 0, &ret)) != NULL) {
3831 
3832 		if (Psetflags(p->pr, PR_RLC) != 0) {
3833 			Prelease(p->pr, 0);
3834 			return (1);
3835 		}
3836 		if (Pcreate_agent(p->pr) == 0) {
3837 			return (0);
3838 
3839 		} else {
3840 			Prelease(p->pr, 0);
3841 			return (2);
3842 		}
3843 	} else {
3844 		return (1);
3845 	}
3846 }
3847 
3848 /*
3849  * Release the specified process. This destroys the agent
3850  * and releases the process. If the process is NULL, nothing
3851  * is done. This function should only be called if grab_process()
3852  * has previously been called and returned success.
3853  *
3854  * This function is Pgrab-safe.
3855  */
3856 static void
3857 release_process(struct ps_prochandle *Pr)
3858 {
3859 	if (Pr == NULL)
3860 		return;
3861 
3862 	Pdestroy_agent(Pr);
3863 	Prelease(Pr, 0);
3864 }
3865 
3866 static boolean_t
3867 grab_zone_proc(char *zonename, pr_info_handle_t *p)
3868 {
3869 	DIR *dirp;
3870 	struct dirent *dentp;
3871 	zoneid_t zoneid;
3872 	int pid_self;
3873 	psinfo_t psinfo;
3874 
3875 	if (zone_get_id(zonename, &zoneid) != 0)
3876 		return (B_FALSE);
3877 
3878 	pid_self = getpid();
3879 
3880 	if ((dirp = opendir("/proc")) == NULL)
3881 		return (B_FALSE);
3882 
3883 	while (dentp = readdir(dirp)) {
3884 		p->pid = atoi(dentp->d_name);
3885 
3886 		/* Skip self */
3887 		if (p->pid == pid_self)
3888 			continue;
3889 
3890 		if (proc_get_psinfo(p->pid, &psinfo) != 0)
3891 			continue;
3892 
3893 		if (psinfo.pr_zoneid != zoneid)
3894 			continue;
3895 
3896 		/* attempt to grab process */
3897 		if (grab_process(p) != 0)
3898 			continue;
3899 
3900 		if (pr_getzoneid(p->pr) != zoneid) {
3901 			release_process(p->pr);
3902 			continue;
3903 		}
3904 
3905 		(void) closedir(dirp);
3906 		return (B_TRUE);
3907 	}
3908 
3909 	(void) closedir(dirp);
3910 	return (B_FALSE);
3911 }
3912 
3913 static boolean_t
3914 get_priv_rctl(struct ps_prochandle *pr, char *name, rctlblk_t *rblk)
3915 {
3916 	if (pr_getrctl(pr, name, NULL, rblk, RCTL_FIRST))
3917 		return (B_FALSE);
3918 
3919 	if (rctlblk_get_privilege(rblk) == RCPRIV_PRIVILEGED)
3920 		return (B_TRUE);
3921 
3922 	while (pr_getrctl(pr, name, rblk, rblk, RCTL_NEXT) == 0) {
3923 		if (rctlblk_get_privilege(rblk) == RCPRIV_PRIVILEGED)
3924 			return (B_TRUE);
3925 	}
3926 
3927 	return (B_FALSE);
3928 }
3929 
3930 /*
3931  * Apply the current rctl settings to the specified, running zone.
3932  */
3933 int
3934 zonecfg_apply_rctls(char *zone_name, zone_dochandle_t handle)
3935 {
3936 	int err;
3937 	int res = Z_OK;
3938 	rctlblk_t *rblk;
3939 	pr_info_handle_t p;
3940 	struct zone_rctltab rctl;
3941 
3942 	if ((err = zonecfg_setrctlent(handle)) != Z_OK)
3943 		return (err);
3944 
3945 	if ((rblk = (rctlblk_t *)malloc(rctlblk_size())) == NULL) {
3946 		(void) zonecfg_endrctlent(handle);
3947 		return (Z_NOMEM);
3948 	}
3949 
3950 	if (!grab_zone_proc(zone_name, &p)) {
3951 		(void) zonecfg_endrctlent(handle);
3952 		free(rblk);
3953 		return (Z_SYSTEM);
3954 	}
3955 
3956 	while (zonecfg_getrctlent(handle, &rctl) == Z_OK) {
3957 		char *rname;
3958 		struct zone_rctlvaltab *valptr;
3959 
3960 		rname = rctl.zone_rctl_name;
3961 
3962 		/* first delete all current privileged settings for this rctl */
3963 		while (get_priv_rctl(p.pr, rname, rblk)) {
3964 			if (pr_setrctl(p.pr, rname, NULL, rblk, RCTL_DELETE) !=
3965 			    0) {
3966 				res = Z_SYSTEM;
3967 				goto done;
3968 			}
3969 		}
3970 
3971 		/* now set each new value for the rctl */
3972 		for (valptr = rctl.zone_rctl_valptr; valptr != NULL;
3973 		    valptr = valptr->zone_rctlval_next) {
3974 			if ((err = zonecfg_construct_rctlblk(valptr, rblk))
3975 			    != Z_OK) {
3976 				res = errno = err;
3977 				goto done;
3978 			}
3979 
3980 			if (pr_setrctl(p.pr, rname, NULL, rblk, RCTL_INSERT)) {
3981 				res = Z_SYSTEM;
3982 				goto done;
3983 			}
3984 		}
3985 	}
3986 
3987 done:
3988 	release_process(p.pr);
3989 	free(rblk);
3990 	(void) zonecfg_endrctlent(handle);
3991 
3992 	return (res);
3993 }
3994 
3995 static const xmlChar *
3996 nm_to_dtd(char *nm)
3997 {
3998 	if (strcmp(nm, "device") == 0)
3999 		return (DTD_ELEM_DEVICE);
4000 	if (strcmp(nm, "fs") == 0)
4001 		return (DTD_ELEM_FS);
4002 	if (strcmp(nm, "net") == 0)
4003 		return (DTD_ELEM_NET);
4004 	if (strcmp(nm, "attr") == 0)
4005 		return (DTD_ELEM_ATTR);
4006 	if (strcmp(nm, "rctl") == 0)
4007 		return (DTD_ELEM_RCTL);
4008 	if (strcmp(nm, "dataset") == 0)
4009 		return (DTD_ELEM_DATASET);
4010 	if (strcmp(nm, "admin") == 0)
4011 		return (DTD_ELEM_ADMIN);
4012 
4013 	return (NULL);
4014 }
4015 
4016 int
4017 zonecfg_num_resources(zone_dochandle_t handle, char *rsrc)
4018 {
4019 	int num = 0;
4020 	const xmlChar *dtd;
4021 	xmlNodePtr cur;
4022 
4023 	if ((dtd = nm_to_dtd(rsrc)) == NULL)
4024 		return (num);
4025 
4026 	if (zonecfg_setent(handle) != Z_OK)
4027 		return (num);
4028 
4029 	for (cur = handle->zone_dh_cur; cur != NULL; cur = cur->next)
4030 		if (xmlStrcmp(cur->name, dtd) == 0)
4031 			num++;
4032 
4033 	(void) zonecfg_endent(handle);
4034 
4035 	return (num);
4036 }
4037 
4038 int
4039 zonecfg_del_all_resources(zone_dochandle_t handle, char *rsrc)
4040 {
4041 	int err;
4042 	const xmlChar *dtd;
4043 	xmlNodePtr cur;
4044 
4045 	if ((dtd = nm_to_dtd(rsrc)) == NULL)
4046 		return (Z_NO_RESOURCE_TYPE);
4047 
4048 	if ((err = zonecfg_setent(handle)) != Z_OK)
4049 		return (err);
4050 
4051 	cur = handle->zone_dh_cur;
4052 	while (cur != NULL) {
4053 		xmlNodePtr tmp;
4054 
4055 		if (xmlStrcmp(cur->name, dtd)) {
4056 			cur = cur->next;
4057 			continue;
4058 		}
4059 
4060 		tmp = cur->next;
4061 		xmlUnlinkNode(cur);
4062 		xmlFreeNode(cur);
4063 		cur = tmp;
4064 	}
4065 
4066 	(void) zonecfg_endent(handle);
4067 	return (Z_OK);
4068 }
4069 
4070 static boolean_t
4071 valid_uint(char *s, uint64_t *n)
4072 {
4073 	char *endp;
4074 
4075 	/* strtoull accepts '-'?! so we want to flag that as an error */
4076 	if (strchr(s, '-') != NULL)
4077 		return (B_FALSE);
4078 
4079 	errno = 0;
4080 	*n = strtoull(s, &endp, 10);
4081 
4082 	if (errno != 0 || *endp != '\0')
4083 		return (B_FALSE);
4084 	return (B_TRUE);
4085 }
4086 
4087 /*
4088  * Convert a string representing a number (possibly a fraction) into an integer.
4089  * The string can have a modifier (K, M, G or T).   The modifiers are treated
4090  * as powers of two (not 10).
4091  */
4092 int
4093 zonecfg_str_to_bytes(char *str, uint64_t *bytes)
4094 {
4095 	long double val;
4096 	char *unitp;
4097 	uint64_t scale;
4098 
4099 	if ((val = strtold(str, &unitp)) < 0)
4100 		return (-1);
4101 
4102 	/* remove any leading white space from units string */
4103 	while (isspace(*unitp) != 0)
4104 		++unitp;
4105 
4106 	/* if no units explicitly set, error */
4107 	if (unitp == NULL || *unitp == '\0') {
4108 		scale = 1;
4109 	} else {
4110 		int i;
4111 		char *units[] = {"K", "M", "G", "T", NULL};
4112 
4113 		scale = 1024;
4114 
4115 		/* update scale based on units */
4116 		for (i = 0; units[i] != NULL; i++) {
4117 			if (strcasecmp(unitp, units[i]) == 0)
4118 				break;
4119 			scale <<= 10;
4120 		}
4121 
4122 		if (units[i] == NULL)
4123 			return (-1);
4124 	}
4125 
4126 	*bytes = (uint64_t)(val * scale);
4127 	return (0);
4128 }
4129 
4130 boolean_t
4131 zonecfg_valid_ncpus(char *lowstr, char *highstr)
4132 {
4133 	uint64_t low, high;
4134 
4135 	if (!valid_uint(lowstr, &low) || !valid_uint(highstr, &high) ||
4136 	    low < 1 || low > high)
4137 		return (B_FALSE);
4138 
4139 	return (B_TRUE);
4140 }
4141 
4142 boolean_t
4143 zonecfg_valid_importance(char *impstr)
4144 {
4145 	uint64_t num;
4146 
4147 	if (!valid_uint(impstr, &num))
4148 		return (B_FALSE);
4149 
4150 	return (B_TRUE);
4151 }
4152 
4153 boolean_t
4154 zonecfg_valid_alias_limit(char *name, char *limitstr, uint64_t *limit)
4155 {
4156 	int i;
4157 
4158 	for (i = 0; aliases[i].shortname != NULL; i++)
4159 		if (strcmp(name, aliases[i].shortname) == 0)
4160 			break;
4161 
4162 	if (aliases[i].shortname == NULL)
4163 		return (B_FALSE);
4164 
4165 	if (!valid_uint(limitstr, limit) || *limit < aliases[i].low_limit)
4166 		return (B_FALSE);
4167 
4168 	return (B_TRUE);
4169 }
4170 
4171 boolean_t
4172 zonecfg_valid_memlimit(char *memstr, uint64_t *mem_val)
4173 {
4174 	if (zonecfg_str_to_bytes(memstr, mem_val) != 0)
4175 		return (B_FALSE);
4176 
4177 	return (B_TRUE);
4178 }
4179 
4180 static int
4181 zerr_pool(char *pool_err, int err_size, int res)
4182 {
4183 	(void) strlcpy(pool_err, pool_strerror(pool_error()), err_size);
4184 	return (res);
4185 }
4186 
4187 static int
4188 create_tmp_pset(char *pool_err, int err_size, pool_conf_t *pconf, pool_t *pool,
4189     char *name, int min, int max)
4190 {
4191 	pool_resource_t *res;
4192 	pool_elem_t *elem;
4193 	pool_value_t *val;
4194 
4195 	if ((res = pool_resource_create(pconf, "pset", name)) == NULL)
4196 		return (zerr_pool(pool_err, err_size, Z_POOL));
4197 
4198 	if (pool_associate(pconf, pool, res) != PO_SUCCESS)
4199 		return (zerr_pool(pool_err, err_size, Z_POOL));
4200 
4201 	if ((elem = pool_resource_to_elem(pconf, res)) == NULL)
4202 		return (zerr_pool(pool_err, err_size, Z_POOL));
4203 
4204 	if ((val = pool_value_alloc()) == NULL)
4205 		return (zerr_pool(pool_err, err_size, Z_POOL));
4206 
4207 	/* set the maximum number of cpus for the pset */
4208 	pool_value_set_uint64(val, (uint64_t)max);
4209 
4210 	if (pool_put_property(pconf, elem, "pset.max", val) != PO_SUCCESS) {
4211 		pool_value_free(val);
4212 		return (zerr_pool(pool_err, err_size, Z_POOL));
4213 	}
4214 
4215 	/* set the minimum number of cpus for the pset */
4216 	pool_value_set_uint64(val, (uint64_t)min);
4217 
4218 	if (pool_put_property(pconf, elem, "pset.min", val) != PO_SUCCESS) {
4219 		pool_value_free(val);
4220 		return (zerr_pool(pool_err, err_size, Z_POOL));
4221 	}
4222 
4223 	pool_value_free(val);
4224 
4225 	return (Z_OK);
4226 }
4227 
4228 static int
4229 create_tmp_pool(char *pool_err, int err_size, pool_conf_t *pconf, char *name,
4230     struct zone_psettab *pset_tab)
4231 {
4232 	pool_t *pool;
4233 	int res = Z_OK;
4234 
4235 	/* create a temporary pool configuration */
4236 	if (pool_conf_open(pconf, NULL, PO_TEMP) != PO_SUCCESS) {
4237 		res = zerr_pool(pool_err, err_size, Z_POOL);
4238 		return (res);
4239 	}
4240 
4241 	if ((pool = pool_create(pconf, name)) == NULL) {
4242 		res = zerr_pool(pool_err, err_size, Z_POOL_CREATE);
4243 		goto done;
4244 	}
4245 
4246 	/* set pool importance */
4247 	if (pset_tab->zone_importance[0] != '\0') {
4248 		pool_elem_t *elem;
4249 		pool_value_t *val;
4250 
4251 		if ((elem = pool_to_elem(pconf, pool)) == NULL) {
4252 			res = zerr_pool(pool_err, err_size, Z_POOL);
4253 			goto done;
4254 		}
4255 
4256 		if ((val = pool_value_alloc()) == NULL) {
4257 			res = zerr_pool(pool_err, err_size, Z_POOL);
4258 			goto done;
4259 		}
4260 
4261 		pool_value_set_int64(val,
4262 		    (int64_t)atoi(pset_tab->zone_importance));
4263 
4264 		if (pool_put_property(pconf, elem, "pool.importance", val)
4265 		    != PO_SUCCESS) {
4266 			res = zerr_pool(pool_err, err_size, Z_POOL);
4267 			pool_value_free(val);
4268 			goto done;
4269 		}
4270 
4271 		pool_value_free(val);
4272 	}
4273 
4274 	if ((res = create_tmp_pset(pool_err, err_size, pconf, pool, name,
4275 	    atoi(pset_tab->zone_ncpu_min),
4276 	    atoi(pset_tab->zone_ncpu_max))) != Z_OK)
4277 		goto done;
4278 
4279 	/* validation */
4280 	if (pool_conf_status(pconf) == POF_INVALID) {
4281 		res = zerr_pool(pool_err, err_size, Z_POOL);
4282 		goto done;
4283 	}
4284 
4285 	/*
4286 	 * This validation is the one we expect to fail if the user specified
4287 	 * an invalid configuration (too many cpus) for this system.
4288 	 */
4289 	if (pool_conf_validate(pconf, POV_RUNTIME) != PO_SUCCESS) {
4290 		res = zerr_pool(pool_err, err_size, Z_POOL_CREATE);
4291 		goto done;
4292 	}
4293 
4294 	/*
4295 	 * Commit the dynamic configuration but not the pool configuration
4296 	 * file.
4297 	 */
4298 	if (pool_conf_commit(pconf, 1) != PO_SUCCESS)
4299 		res = zerr_pool(pool_err, err_size, Z_POOL);
4300 
4301 done:
4302 	(void) pool_conf_close(pconf);
4303 	return (res);
4304 }
4305 
4306 static int
4307 get_running_tmp_pset(pool_conf_t *pconf, pool_t *pool, pool_resource_t *pset,
4308     struct zone_psettab *pset_tab)
4309 {
4310 	int nfound = 0;
4311 	pool_elem_t *pe;
4312 	pool_value_t *pv = pool_value_alloc();
4313 	uint64_t val_uint;
4314 
4315 	if (pool != NULL) {
4316 		pe = pool_to_elem(pconf, pool);
4317 		if (pool_get_property(pconf, pe, "pool.importance", pv)
4318 		    != POC_INVAL) {
4319 			int64_t val_int;
4320 
4321 			(void) pool_value_get_int64(pv, &val_int);
4322 			(void) snprintf(pset_tab->zone_importance,
4323 			    sizeof (pset_tab->zone_importance), "%d", val_int);
4324 			nfound++;
4325 		}
4326 	}
4327 
4328 	if (pset != NULL) {
4329 		pe = pool_resource_to_elem(pconf, pset);
4330 		if (pool_get_property(pconf, pe, "pset.min", pv) != POC_INVAL) {
4331 			(void) pool_value_get_uint64(pv, &val_uint);
4332 			(void) snprintf(pset_tab->zone_ncpu_min,
4333 			    sizeof (pset_tab->zone_ncpu_min), "%u", val_uint);
4334 			nfound++;
4335 		}
4336 
4337 		if (pool_get_property(pconf, pe, "pset.max", pv) != POC_INVAL) {
4338 			(void) pool_value_get_uint64(pv, &val_uint);
4339 			(void) snprintf(pset_tab->zone_ncpu_max,
4340 			    sizeof (pset_tab->zone_ncpu_max), "%u", val_uint);
4341 			nfound++;
4342 		}
4343 	}
4344 
4345 	pool_value_free(pv);
4346 
4347 	if (nfound == 3)
4348 		return (PO_SUCCESS);
4349 
4350 	return (PO_FAIL);
4351 }
4352 
4353 /*
4354  * Determine if a tmp pool is configured and if so, if the configuration is
4355  * still valid or if it has been changed since the tmp pool was created.
4356  * If the tmp pool configuration is no longer valid, delete the tmp pool.
4357  *
4358  * Set *valid=B_TRUE if there is an existing, valid tmp pool configuration.
4359  */
4360 static int
4361 verify_del_tmp_pool(pool_conf_t *pconf, char *tmp_name, char *pool_err,
4362     int err_size, struct zone_psettab *pset_tab, boolean_t *exists)
4363 {
4364 	int res = Z_OK;
4365 	pool_t *pool;
4366 	pool_resource_t *pset;
4367 	struct zone_psettab pset_current;
4368 
4369 	*exists = B_FALSE;
4370 
4371 	if (pool_conf_open(pconf, pool_dynamic_location(), PO_RDWR)
4372 	    != PO_SUCCESS) {
4373 		res = zerr_pool(pool_err, err_size, Z_POOL);
4374 		return (res);
4375 	}
4376 
4377 	pool = pool_get_pool(pconf, tmp_name);
4378 	pset = pool_get_resource(pconf, "pset", tmp_name);
4379 
4380 	if (pool == NULL && pset == NULL) {
4381 		/* no tmp pool configured */
4382 		goto done;
4383 	}
4384 
4385 	/*
4386 	 * If an existing tmp pool for this zone is configured with the proper
4387 	 * settings, then the tmp pool is valid.
4388 	 */
4389 	if (get_running_tmp_pset(pconf, pool, pset, &pset_current)
4390 	    == PO_SUCCESS &&
4391 	    strcmp(pset_tab->zone_ncpu_min,
4392 	    pset_current.zone_ncpu_min) == 0 &&
4393 	    strcmp(pset_tab->zone_ncpu_max,
4394 	    pset_current.zone_ncpu_max) == 0 &&
4395 	    strcmp(pset_tab->zone_importance,
4396 	    pset_current.zone_importance) == 0) {
4397 		*exists = B_TRUE;
4398 
4399 	} else {
4400 		/*
4401 		 * An out-of-date tmp pool configuration exists.  Delete it
4402 		 * so that we can create the correct tmp pool config.
4403 		 */
4404 		if (pset != NULL &&
4405 		    pool_resource_destroy(pconf, pset) != PO_SUCCESS) {
4406 			res = zerr_pool(pool_err, err_size, Z_POOL);
4407 			goto done;
4408 		}
4409 
4410 		if (pool != NULL &&
4411 		    pool_destroy(pconf, pool) != PO_SUCCESS) {
4412 			res = zerr_pool(pool_err, err_size, Z_POOL);
4413 			goto done;
4414 		}
4415 
4416 		/* commit dynamic config */
4417 		if (pool_conf_commit(pconf, 0) != PO_SUCCESS)
4418 			res = zerr_pool(pool_err, err_size, Z_POOL);
4419 	}
4420 
4421 done:
4422 	(void) pool_conf_close(pconf);
4423 
4424 	return (res);
4425 }
4426 
4427 /*
4428  * Destroy any existing tmp pool.
4429  */
4430 int
4431 zonecfg_destroy_tmp_pool(char *zone_name, char *pool_err, int err_size)
4432 {
4433 	int status;
4434 	int res = Z_OK;
4435 	pool_conf_t *pconf;
4436 	pool_t *pool;
4437 	pool_resource_t *pset;
4438 	char tmp_name[MAX_TMP_POOL_NAME];
4439 
4440 	/* if pools not enabled then nothing to do */
4441 	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
4442 		return (Z_OK);
4443 
4444 	if ((pconf = pool_conf_alloc()) == NULL)
4445 		return (zerr_pool(pool_err, err_size, Z_POOL));
4446 
4447 	(void) snprintf(tmp_name, sizeof (tmp_name), TMP_POOL_NAME, zone_name);
4448 
4449 	if (pool_conf_open(pconf, pool_dynamic_location(), PO_RDWR)
4450 	    != PO_SUCCESS) {
4451 		res = zerr_pool(pool_err, err_size, Z_POOL);
4452 		pool_conf_free(pconf);
4453 		return (res);
4454 	}
4455 
4456 	pool = pool_get_pool(pconf, tmp_name);
4457 	pset = pool_get_resource(pconf, "pset", tmp_name);
4458 
4459 	if (pool == NULL && pset == NULL) {
4460 		/* nothing to destroy, we're done */
4461 		goto done;
4462 	}
4463 
4464 	if (pset != NULL && pool_resource_destroy(pconf, pset) != PO_SUCCESS) {
4465 		res = zerr_pool(pool_err, err_size, Z_POOL);
4466 		goto done;
4467 	}
4468 
4469 	if (pool != NULL && pool_destroy(pconf, pool) != PO_SUCCESS) {
4470 		res = zerr_pool(pool_err, err_size, Z_POOL);
4471 		goto done;
4472 	}
4473 
4474 	/* commit dynamic config */
4475 	if (pool_conf_commit(pconf, 0) != PO_SUCCESS)
4476 		res = zerr_pool(pool_err, err_size, Z_POOL);
4477 
4478 done:
4479 	(void) pool_conf_close(pconf);
4480 	pool_conf_free(pconf);
4481 
4482 	return (res);
4483 }
4484 
4485 /*
4486  * Attempt to bind to a tmp pool for this zone.  If there is no tmp pool
4487  * configured, we just return Z_OK.
4488  *
4489  * We either attempt to create the tmp pool for this zone or rebind to an
4490  * existing tmp pool for this zone.
4491  *
4492  * Rebinding is used when a zone with a tmp pool reboots so that we don't have
4493  * to recreate the tmp pool.  To do this we need to be sure we work correctly
4494  * for the following cases:
4495  *
4496  *	- there is an existing, properly configured tmp pool.
4497  *	- zonecfg added tmp pool after zone was booted, must now create.
4498  *	- zonecfg updated tmp pool config after zone was booted, in this case
4499  *	  we destroy the old tmp pool and create a new one.
4500  */
4501 int
4502 zonecfg_bind_tmp_pool(zone_dochandle_t handle, zoneid_t zoneid, char *pool_err,
4503     int err_size)
4504 {
4505 	struct zone_psettab pset_tab;
4506 	int err;
4507 	int status;
4508 	pool_conf_t *pconf;
4509 	boolean_t exists;
4510 	char zone_name[ZONENAME_MAX];
4511 	char tmp_name[MAX_TMP_POOL_NAME];
4512 
4513 	(void) getzonenamebyid(zoneid, zone_name, sizeof (zone_name));
4514 
4515 	err = zonecfg_lookup_pset(handle, &pset_tab);
4516 
4517 	/* if no temporary pool configured, we're done */
4518 	if (err == Z_NO_ENTRY)
4519 		return (Z_OK);
4520 
4521 	/*
4522 	 * importance might not have a value but we need to validate it here,
4523 	 * so set the default.
4524 	 */
4525 	if (pset_tab.zone_importance[0] == '\0')
4526 		(void) strlcpy(pset_tab.zone_importance, "1",
4527 		    sizeof (pset_tab.zone_importance));
4528 
4529 	/* if pools not enabled, enable them now */
4530 	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) {
4531 		if (pool_set_status(POOL_ENABLED) != PO_SUCCESS)
4532 			return (Z_POOL_ENABLE);
4533 	}
4534 
4535 	if ((pconf = pool_conf_alloc()) == NULL)
4536 		return (zerr_pool(pool_err, err_size, Z_POOL));
4537 
4538 	(void) snprintf(tmp_name, sizeof (tmp_name), TMP_POOL_NAME, zone_name);
4539 
4540 	/*
4541 	 * Check if a valid tmp pool/pset already exists.  If so, we just
4542 	 * reuse it.
4543 	 */
4544 	if ((err = verify_del_tmp_pool(pconf, tmp_name, pool_err, err_size,
4545 	    &pset_tab, &exists)) != Z_OK) {
4546 		pool_conf_free(pconf);
4547 		return (err);
4548 	}
4549 
4550 	if (!exists)
4551 		err = create_tmp_pool(pool_err, err_size, pconf, tmp_name,
4552 		    &pset_tab);
4553 
4554 	pool_conf_free(pconf);
4555 
4556 	if (err != Z_OK)
4557 		return (err);
4558 
4559 	/* Bind the zone to the pool. */
4560 	if (pool_set_binding(tmp_name, P_ZONEID, zoneid) != PO_SUCCESS)
4561 		return (zerr_pool(pool_err, err_size, Z_POOL_BIND));
4562 
4563 	return (Z_OK);
4564 }
4565 
4566 /*
4567  * Attempt to bind to a permanent pool for this zone.  If there is no
4568  * permanent pool configured, we just return Z_OK.
4569  */
4570 int
4571 zonecfg_bind_pool(zone_dochandle_t handle, zoneid_t zoneid, char *pool_err,
4572     int err_size)
4573 {
4574 	pool_conf_t *poolconf;
4575 	pool_t *pool;
4576 	char poolname[MAXPATHLEN];
4577 	int status;
4578 	int error;
4579 
4580 	/*
4581 	 * Find the pool mentioned in the zone configuration, and bind to it.
4582 	 */
4583 	error = zonecfg_get_pool(handle, poolname, sizeof (poolname));
4584 	if (error == Z_NO_ENTRY || (error == Z_OK && strlen(poolname) == 0)) {
4585 		/*
4586 		 * The property is not set on the zone, so the pool
4587 		 * should be bound to the default pool.  But that's
4588 		 * already done by the kernel, so we can just return.
4589 		 */
4590 		return (Z_OK);
4591 	}
4592 	if (error != Z_OK) {
4593 		/*
4594 		 * Not an error, even though it shouldn't be happening.
4595 		 */
4596 		return (Z_OK);
4597 	}
4598 	/*
4599 	 * Don't do anything if pools aren't enabled.
4600 	 */
4601 	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
4602 		return (Z_POOLS_NOT_ACTIVE);
4603 
4604 	/*
4605 	 * Try to provide a sane error message if the requested pool doesn't
4606 	 * exist.
4607 	 */
4608 	if ((poolconf = pool_conf_alloc()) == NULL)
4609 		return (zerr_pool(pool_err, err_size, Z_POOL));
4610 
4611 	if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) !=
4612 	    PO_SUCCESS) {
4613 		pool_conf_free(poolconf);
4614 		return (zerr_pool(pool_err, err_size, Z_POOL));
4615 	}
4616 	pool = pool_get_pool(poolconf, poolname);
4617 	(void) pool_conf_close(poolconf);
4618 	pool_conf_free(poolconf);
4619 	if (pool == NULL)
4620 		return (Z_NO_POOL);
4621 
4622 	/*
4623 	 * Bind the zone to the pool.
4624 	 */
4625 	if (pool_set_binding(poolname, P_ZONEID, zoneid) != PO_SUCCESS) {
4626 		/* if bind fails, return poolname for the error msg */
4627 		(void) strlcpy(pool_err, poolname, err_size);
4628 		return (Z_POOL_BIND);
4629 	}
4630 
4631 	return (Z_OK);
4632 }
4633 
4634 int
4635 zonecfg_get_poolname(zone_dochandle_t handle, char *zone, char *pool,
4636     size_t poolsize)
4637 {
4638 	int err;
4639 	struct zone_psettab pset_tab;
4640 
4641 	err = zonecfg_lookup_pset(handle, &pset_tab);
4642 	if ((err != Z_NO_ENTRY) && (err != Z_OK))
4643 		return (err);
4644 
4645 	/* pset was found so a temporary pool was created */
4646 	if (err == Z_OK) {
4647 		(void) snprintf(pool, poolsize, TMP_POOL_NAME, zone);
4648 		return (Z_OK);
4649 	}
4650 
4651 	/* lookup the poolname in zonecfg */
4652 	return (zonecfg_get_pool(handle, pool, poolsize));
4653 }
4654 
4655 static boolean_t
4656 svc_enabled(char *svc_name)
4657 {
4658 	scf_simple_prop_t	*prop;
4659 	boolean_t		found = B_FALSE;
4660 
4661 	prop = scf_simple_prop_get(NULL, svc_name, SCF_PG_GENERAL,
4662 	    SCF_PROPERTY_ENABLED);
4663 
4664 	if (scf_simple_prop_numvalues(prop) == 1 &&
4665 	    *scf_simple_prop_next_boolean(prop) != 0)
4666 		found = B_TRUE;
4667 
4668 	scf_simple_prop_free(prop);
4669 
4670 	return (found);
4671 }
4672 
4673 /*
4674  * If the zone has capped-memory, make sure the rcap service is enabled.
4675  */
4676 int
4677 zonecfg_enable_rcapd(char *err, int size)
4678 {
4679 	if (!svc_enabled(RCAP_SERVICE) &&
4680 	    smf_enable_instance(RCAP_SERVICE, 0) == -1) {
4681 		(void) strlcpy(err, scf_strerror(scf_error()), size);
4682 		return (Z_SYSTEM);
4683 	}
4684 
4685 	return (Z_OK);
4686 }
4687 
4688 /*
4689  * Return true if pset has cpu range specified and poold is not enabled.
4690  */
4691 boolean_t
4692 zonecfg_warn_poold(zone_dochandle_t handle)
4693 {
4694 	struct zone_psettab pset_tab;
4695 	int min, max;
4696 	int err;
4697 
4698 	err = zonecfg_lookup_pset(handle, &pset_tab);
4699 
4700 	/* if no temporary pool configured, we're done */
4701 	if (err == Z_NO_ENTRY)
4702 		return (B_FALSE);
4703 
4704 	min = atoi(pset_tab.zone_ncpu_min);
4705 	max = atoi(pset_tab.zone_ncpu_max);
4706 
4707 	/* range not specified, no need for poold */
4708 	if (min == max)
4709 		return (B_FALSE);
4710 
4711 	/* we have a range, check if poold service is enabled */
4712 	if (svc_enabled(POOLD_SERVICE))
4713 		return (B_FALSE);
4714 
4715 	return (B_TRUE);
4716 }
4717 
4718 /*
4719  * Retrieve the specified pool's thread scheduling class.  'poolname' must
4720  * refer to the name of a configured resource pool.  The thread scheduling
4721  * class specified by the pool will be stored in the buffer to which 'class'
4722  * points.  'clsize' is the byte size of the buffer to which 'class' points.
4723  *
4724  * This function returns Z_OK if it successfully stored the specified pool's
4725  * thread scheduling class into the buffer to which 'class' points.  It returns
4726  * Z_NO_POOL if resource pools are not enabled, the function is unable to
4727  * access the system's resource pools configuration, or the specified pool
4728  * does not exist.  The function returns Z_TOO_BIG if the buffer to which
4729  * 'class' points is not large enough to contain the thread scheduling class'
4730  * name.  The function returns Z_NO_ENTRY if the pool does not specify a thread
4731  * scheduling class.
4732  */
4733 static int
4734 get_pool_sched_class(char *poolname, char *class, int clsize)
4735 {
4736 	int status;
4737 	pool_conf_t *poolconf;
4738 	pool_t *pool;
4739 	pool_elem_t *pe;
4740 	pool_value_t *pv = pool_value_alloc();
4741 	const char *sched_str;
4742 
4743 	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
4744 		return (Z_NO_POOL);
4745 
4746 	if ((poolconf = pool_conf_alloc()) == NULL)
4747 		return (Z_NO_POOL);
4748 
4749 	if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) !=
4750 	    PO_SUCCESS) {
4751 		pool_conf_free(poolconf);
4752 		return (Z_NO_POOL);
4753 	}
4754 
4755 	if ((pool = pool_get_pool(poolconf, poolname)) == NULL) {
4756 		(void) pool_conf_close(poolconf);
4757 		pool_conf_free(poolconf);
4758 		return (Z_NO_POOL);
4759 	}
4760 
4761 	pe = pool_to_elem(poolconf, pool);
4762 	if (pool_get_property(poolconf, pe, "pool.scheduler", pv) !=
4763 	    POC_STRING) {
4764 		(void) pool_conf_close(poolconf);
4765 		pool_conf_free(poolconf);
4766 		return (Z_NO_ENTRY);
4767 	}
4768 	(void) pool_value_get_string(pv, &sched_str);
4769 	(void) pool_conf_close(poolconf);
4770 	pool_conf_free(poolconf);
4771 	if (strlcpy(class, sched_str, clsize) >= clsize)
4772 		return (Z_TOO_BIG);
4773 	return (Z_OK);
4774 }
4775 
4776 /*
4777  * Get the default scheduling class for the zone.  This will either be the
4778  * class set on the zone's pool or the system default scheduling class.
4779  */
4780 int
4781 zonecfg_get_dflt_sched_class(zone_dochandle_t handle, char *class, int clsize)
4782 {
4783 	char poolname[MAXPATHLEN];
4784 
4785 	if (zonecfg_get_pool(handle, poolname, sizeof (poolname)) == Z_OK) {
4786 		/* check if the zone's pool specified a sched class */
4787 		if (get_pool_sched_class(poolname, class, clsize) == Z_OK)
4788 			return (Z_OK);
4789 	}
4790 
4791 	if (priocntl(0, 0, PC_GETDFLCL, class, (uint64_t)clsize) == -1)
4792 		return (Z_TOO_BIG);
4793 
4794 	return (Z_OK);
4795 }
4796 
4797 int
4798 zonecfg_setfsent(zone_dochandle_t handle)
4799 {
4800 	return (zonecfg_setent(handle));
4801 }
4802 
4803 int
4804 zonecfg_getfsent(zone_dochandle_t handle, struct zone_fstab *tabptr)
4805 {
4806 	xmlNodePtr cur, options;
4807 	char options_str[MAX_MNTOPT_STR];
4808 	int err;
4809 
4810 	if (handle == NULL)
4811 		return (Z_INVAL);
4812 
4813 	if ((cur = handle->zone_dh_cur) == NULL)
4814 		return (Z_NO_ENTRY);
4815 
4816 	for (; cur != NULL; cur = cur->next)
4817 		if (!xmlStrcmp(cur->name, DTD_ELEM_FS))
4818 			break;
4819 	if (cur == NULL) {
4820 		handle->zone_dh_cur = handle->zone_dh_top;
4821 		return (Z_NO_ENTRY);
4822 	}
4823 
4824 	if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
4825 	    sizeof (tabptr->zone_fs_special))) != Z_OK) {
4826 		handle->zone_dh_cur = handle->zone_dh_top;
4827 		return (err);
4828 	}
4829 
4830 	if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
4831 	    sizeof (tabptr->zone_fs_raw))) != Z_OK) {
4832 		handle->zone_dh_cur = handle->zone_dh_top;
4833 		return (err);
4834 	}
4835 
4836 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
4837 	    sizeof (tabptr->zone_fs_dir))) != Z_OK) {
4838 		handle->zone_dh_cur = handle->zone_dh_top;
4839 		return (err);
4840 	}
4841 
4842 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
4843 	    sizeof (tabptr->zone_fs_type))) != Z_OK) {
4844 		handle->zone_dh_cur = handle->zone_dh_top;
4845 		return (err);
4846 	}
4847 
4848 	/* OK for options to be NULL */
4849 	tabptr->zone_fs_options = NULL;
4850 	for (options = cur->xmlChildrenNode; options != NULL;
4851 	    options = options->next) {
4852 		if (fetchprop(options, DTD_ATTR_NAME, options_str,
4853 		    sizeof (options_str)) != Z_OK)
4854 			break;
4855 		if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
4856 			break;
4857 	}
4858 
4859 	handle->zone_dh_cur = cur->next;
4860 	return (Z_OK);
4861 }
4862 
4863 int
4864 zonecfg_endfsent(zone_dochandle_t handle)
4865 {
4866 	return (zonecfg_endent(handle));
4867 }
4868 
4869 int
4870 zonecfg_setnwifent(zone_dochandle_t handle)
4871 {
4872 	return (zonecfg_setent(handle));
4873 }
4874 
4875 int
4876 zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
4877 {
4878 	xmlNodePtr cur;
4879 	int err;
4880 
4881 	if (handle == NULL)
4882 		return (Z_INVAL);
4883 
4884 	if ((cur = handle->zone_dh_cur) == NULL)
4885 		return (Z_NO_ENTRY);
4886 
4887 	for (; cur != NULL; cur = cur->next)
4888 		if (!xmlStrcmp(cur->name, DTD_ELEM_NET))
4889 			break;
4890 	if (cur == NULL) {
4891 		handle->zone_dh_cur = handle->zone_dh_top;
4892 		return (Z_NO_ENTRY);
4893 	}
4894 
4895 	if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
4896 	    sizeof (tabptr->zone_nwif_address))) != Z_OK) {
4897 		handle->zone_dh_cur = handle->zone_dh_top;
4898 		return (err);
4899 	}
4900 
4901 	if ((err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
4902 	    tabptr->zone_nwif_allowed_address,
4903 	    sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK) {
4904 		handle->zone_dh_cur = handle->zone_dh_top;
4905 		return (err);
4906 	}
4907 
4908 	if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
4909 	    sizeof (tabptr->zone_nwif_physical))) != Z_OK) {
4910 		handle->zone_dh_cur = handle->zone_dh_top;
4911 		return (err);
4912 	}
4913 
4914 	if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
4915 	    tabptr->zone_nwif_defrouter,
4916 	    sizeof (tabptr->zone_nwif_defrouter))) != Z_OK) {
4917 		handle->zone_dh_cur = handle->zone_dh_top;
4918 		return (err);
4919 	}
4920 
4921 	handle->zone_dh_cur = cur->next;
4922 	return (Z_OK);
4923 }
4924 
4925 int
4926 zonecfg_endnwifent(zone_dochandle_t handle)
4927 {
4928 	return (zonecfg_endent(handle));
4929 }
4930 
4931 int
4932 zonecfg_setdevent(zone_dochandle_t handle)
4933 {
4934 	return (zonecfg_setent(handle));
4935 }
4936 
4937 int
4938 zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr)
4939 {
4940 	xmlNodePtr cur;
4941 	int err;
4942 
4943 	if (handle == NULL)
4944 		return (Z_INVAL);
4945 
4946 	if ((cur = handle->zone_dh_cur) == NULL)
4947 		return (Z_NO_ENTRY);
4948 
4949 	for (; cur != NULL; cur = cur->next)
4950 		if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
4951 			break;
4952 	if (cur == NULL) {
4953 		handle->zone_dh_cur = handle->zone_dh_top;
4954 		return (Z_NO_ENTRY);
4955 	}
4956 
4957 	if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
4958 	    sizeof (tabptr->zone_dev_match))) != Z_OK) {
4959 		handle->zone_dh_cur = handle->zone_dh_top;
4960 		return (err);
4961 	}
4962 
4963 	handle->zone_dh_cur = cur->next;
4964 	return (Z_OK);
4965 }
4966 
4967 int
4968 zonecfg_enddevent(zone_dochandle_t handle)
4969 {
4970 	return (zonecfg_endent(handle));
4971 }
4972 
4973 int
4974 zonecfg_setrctlent(zone_dochandle_t handle)
4975 {
4976 	return (zonecfg_setent(handle));
4977 }
4978 
4979 int
4980 zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr)
4981 {
4982 	xmlNodePtr cur, val;
4983 	struct zone_rctlvaltab *valptr;
4984 	int err;
4985 
4986 	if (handle == NULL)
4987 		return (Z_INVAL);
4988 
4989 	if ((cur = handle->zone_dh_cur) == NULL)
4990 		return (Z_NO_ENTRY);
4991 
4992 	for (; cur != NULL; cur = cur->next)
4993 		if (!xmlStrcmp(cur->name, DTD_ELEM_RCTL))
4994 			break;
4995 	if (cur == NULL) {
4996 		handle->zone_dh_cur = handle->zone_dh_top;
4997 		return (Z_NO_ENTRY);
4998 	}
4999 
5000 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_rctl_name,
5001 	    sizeof (tabptr->zone_rctl_name))) != Z_OK) {
5002 		handle->zone_dh_cur = handle->zone_dh_top;
5003 		return (err);
5004 	}
5005 
5006 	tabptr->zone_rctl_valptr = NULL;
5007 	for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
5008 		valptr = (struct zone_rctlvaltab *)malloc(
5009 		    sizeof (struct zone_rctlvaltab));
5010 		if (valptr == NULL)
5011 			return (Z_NOMEM);
5012 		if (fetchprop(val, DTD_ATTR_PRIV, valptr->zone_rctlval_priv,
5013 		    sizeof (valptr->zone_rctlval_priv)) != Z_OK)
5014 			break;
5015 		if (fetchprop(val, DTD_ATTR_LIMIT, valptr->zone_rctlval_limit,
5016 		    sizeof (valptr->zone_rctlval_limit)) != Z_OK)
5017 			break;
5018 		if (fetchprop(val, DTD_ATTR_ACTION, valptr->zone_rctlval_action,
5019 		    sizeof (valptr->zone_rctlval_action)) != Z_OK)
5020 			break;
5021 		if (zonecfg_add_rctl_value(tabptr, valptr) != Z_OK)
5022 			break;
5023 	}
5024 
5025 	handle->zone_dh_cur = cur->next;
5026 	return (Z_OK);
5027 }
5028 
5029 int
5030 zonecfg_endrctlent(zone_dochandle_t handle)
5031 {
5032 	return (zonecfg_endent(handle));
5033 }
5034 
5035 int
5036 zonecfg_setattrent(zone_dochandle_t handle)
5037 {
5038 	return (zonecfg_setent(handle));
5039 }
5040 
5041 int
5042 zonecfg_getattrent(zone_dochandle_t handle, struct zone_attrtab *tabptr)
5043 {
5044 	xmlNodePtr cur;
5045 	int err;
5046 
5047 	if (handle == NULL)
5048 		return (Z_INVAL);
5049 
5050 	if ((cur = handle->zone_dh_cur) == NULL)
5051 		return (Z_NO_ENTRY);
5052 
5053 	for (; cur != NULL; cur = cur->next)
5054 		if (!xmlStrcmp(cur->name, DTD_ELEM_ATTR))
5055 			break;
5056 	if (cur == NULL) {
5057 		handle->zone_dh_cur = handle->zone_dh_top;
5058 		return (Z_NO_ENTRY);
5059 	}
5060 
5061 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
5062 	    sizeof (tabptr->zone_attr_name))) != Z_OK) {
5063 		handle->zone_dh_cur = handle->zone_dh_top;
5064 		return (err);
5065 	}
5066 
5067 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
5068 	    sizeof (tabptr->zone_attr_type))) != Z_OK) {
5069 		handle->zone_dh_cur = handle->zone_dh_top;
5070 		return (err);
5071 	}
5072 
5073 	if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
5074 	    sizeof (tabptr->zone_attr_value))) != Z_OK) {
5075 		handle->zone_dh_cur = handle->zone_dh_top;
5076 		return (err);
5077 	}
5078 
5079 	handle->zone_dh_cur = cur->next;
5080 	return (Z_OK);
5081 }
5082 
5083 int
5084 zonecfg_endattrent(zone_dochandle_t handle)
5085 {
5086 	return (zonecfg_endent(handle));
5087 }
5088 
5089 int
5090 zonecfg_setadminent(zone_dochandle_t handle)
5091 {
5092 	return (zonecfg_setent(handle));
5093 }
5094 
5095 int
5096 zonecfg_getadminent(zone_dochandle_t handle, struct zone_admintab *tabptr)
5097 {
5098 	xmlNodePtr cur;
5099 	int err;
5100 
5101 	if (handle == NULL)
5102 		return (Z_INVAL);
5103 
5104 	if ((cur = handle->zone_dh_cur) == NULL)
5105 		return (Z_NO_ENTRY);
5106 
5107 	for (; cur != NULL; cur = cur->next)
5108 		if (!xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
5109 			break;
5110 	if (cur == NULL) {
5111 		handle->zone_dh_cur = handle->zone_dh_top;
5112 		return (Z_NO_ENTRY);
5113 	}
5114 
5115 	if ((err = fetchprop(cur, DTD_ATTR_USER, tabptr->zone_admin_user,
5116 	    sizeof (tabptr->zone_admin_user))) != Z_OK) {
5117 		handle->zone_dh_cur = handle->zone_dh_top;
5118 		return (err);
5119 	}
5120 
5121 
5122 	if ((err = fetchprop(cur, DTD_ATTR_AUTHS, tabptr->zone_admin_auths,
5123 	    sizeof (tabptr->zone_admin_auths))) != Z_OK) {
5124 		handle->zone_dh_cur = handle->zone_dh_top;
5125 		return (err);
5126 	}
5127 
5128 	handle->zone_dh_cur = cur->next;
5129 	return (Z_OK);
5130 }
5131 
5132 int
5133 zonecfg_endadminent(zone_dochandle_t handle)
5134 {
5135 	return (zonecfg_endent(handle));
5136 }
5137 
5138 /*
5139  * The privileges available on the system and described in privileges(5)
5140  * fall into four categories with respect to non-global zones:
5141  *
5142  *      Default set of privileges considered safe for all non-global
5143  *      zones.  These privileges are "safe" in the sense that a
5144  *      privileged process in the zone cannot affect processes in any
5145  *      other zone on the system.
5146  *
5147  *      Set of privileges not currently permitted within a non-global
5148  *      zone.  These privileges are considered by default, "unsafe,"
5149  *      and include ones which affect global resources (such as the
5150  *      system clock or physical memory) or are overly broad and cover
5151  *      more than one mechanism in the system.  In other cases, there
5152  *      has not been sufficient virtualization in the parts of the
5153  *      system the privilege covers to allow its use within a
5154  *      non-global zone.
5155  *
5156  *      Set of privileges required in order to get a zone booted and
5157  *      init(1M) started.  These cannot be removed from the zone's
5158  *      privilege set.
5159  *
5160  * All other privileges are optional and are potentially useful for
5161  * processes executing inside a non-global zone.
5162  *
5163  * When privileges are added to the system, a determination needs to be
5164  * made as to which category the privilege belongs to.  Ideally,
5165  * privileges should be fine-grained enough and the mechanisms they cover
5166  * virtualized enough so that they can be made available to non-global
5167  * zones.
5168  */
5169 
5170 /*
5171  * Define some of the tokens that priv_str_to_set(3C) recognizes.  Since
5172  * the privilege string separator can be any character, although it is
5173  * usually a comma character, define these here as well in the event that
5174  * they change or are augmented in the future.
5175  */
5176 #define	BASIC_TOKEN		"basic"
5177 #define	DEFAULT_TOKEN		"default"
5178 #define	ZONE_TOKEN		"zone"
5179 #define	TOKEN_PRIV_CHAR		','
5180 #define	TOKEN_PRIV_STR		","
5181 
5182 typedef struct priv_node {
5183 	struct priv_node	*pn_next;	/* Next privilege */
5184 	char			*pn_priv;	/* Privileges name */
5185 } priv_node_t;
5186 
5187 /* Privileges lists can differ across brands */
5188 typedef struct priv_lists {
5189 	/* Privileges considered safe for all non-global zones of a brand */
5190 	struct priv_node	*pl_default;
5191 
5192 	/* Privileges not permitted for all non-global zones of a brand */
5193 	struct priv_node	*pl_prohibited;
5194 
5195 	/* Privileges required for all non-global zones of a brand */
5196 	struct priv_node	*pl_required;
5197 
5198 	/*
5199 	 * ip-type of the zone these privileges lists apply to.
5200 	 * It is used to pass ip-type to the callback function,
5201 	 * priv_lists_cb, which has no way of getting the ip-type.
5202 	 */
5203 	const char		*pl_iptype;
5204 } priv_lists_t;
5205 
5206 static int
5207 priv_lists_cb(void *data, priv_iter_t *priv_iter)
5208 {
5209 	priv_lists_t *plp = (priv_lists_t *)data;
5210 	priv_node_t *pnp;
5211 
5212 	/* Skip this privilege if ip-type does not match */
5213 	if ((strcmp(priv_iter->pi_iptype, "all") != 0) &&
5214 	    (strcmp(priv_iter->pi_iptype, plp->pl_iptype) != 0))
5215 		return (0);
5216 
5217 	/* Allocate a new priv list node. */
5218 	if ((pnp = malloc(sizeof (*pnp))) == NULL)
5219 		return (-1);
5220 	if ((pnp->pn_priv = strdup(priv_iter->pi_name)) == NULL) {
5221 		free(pnp);
5222 		return (-1);
5223 	}
5224 
5225 	/* Insert the new priv list node into the right list */
5226 	if (strcmp(priv_iter->pi_set, "default") == 0) {
5227 		pnp->pn_next = plp->pl_default;
5228 		plp->pl_default = pnp;
5229 	} else if (strcmp(priv_iter->pi_set, "prohibited") == 0) {
5230 		pnp->pn_next = plp->pl_prohibited;
5231 		plp->pl_prohibited = pnp;
5232 	} else if (strcmp(priv_iter->pi_set, "required") == 0) {
5233 		pnp->pn_next = plp->pl_required;
5234 		plp->pl_required = pnp;
5235 	} else {
5236 		free(pnp->pn_priv);
5237 		free(pnp);
5238 		return (-1);
5239 	}
5240 	return (0);
5241 }
5242 
5243 static void
5244 priv_lists_destroy(priv_lists_t *plp)
5245 {
5246 	priv_node_t *pnp;
5247 
5248 	assert(plp != NULL);
5249 
5250 	while ((pnp = plp->pl_default) != NULL) {
5251 		plp->pl_default = pnp->pn_next;
5252 		free(pnp->pn_priv);
5253 		free(pnp);
5254 	}
5255 	while ((pnp = plp->pl_prohibited) != NULL) {
5256 		plp->pl_prohibited = pnp->pn_next;
5257 		free(pnp->pn_priv);
5258 		free(pnp);
5259 	}
5260 	while ((pnp = plp->pl_required) != NULL) {
5261 		plp->pl_required = pnp->pn_next;
5262 		free(pnp->pn_priv);
5263 		free(pnp);
5264 	}
5265 	free(plp);
5266 }
5267 
5268 static int
5269 priv_lists_create(zone_dochandle_t handle, char *brand, priv_lists_t **plpp,
5270     const char *curr_iptype)
5271 {
5272 	priv_lists_t *plp;
5273 	brand_handle_t bh;
5274 	char brand_str[MAXNAMELEN];
5275 
5276 	/* handle or brand must be set, but never both */
5277 	assert((handle != NULL) || (brand != NULL));
5278 	assert((handle == NULL) || (brand == NULL));
5279 
5280 	if (handle != NULL) {
5281 		brand = brand_str;
5282 		if (zonecfg_get_brand(handle, brand, sizeof (brand_str)) != 0)
5283 			return (Z_BRAND_ERROR);
5284 	}
5285 
5286 	if ((bh = brand_open(brand)) == NULL)
5287 		return (Z_BRAND_ERROR);
5288 
5289 	if ((plp = calloc(1, sizeof (priv_lists_t))) == NULL) {
5290 		brand_close(bh);
5291 		return (Z_NOMEM);
5292 	}
5293 
5294 	plp->pl_iptype = curr_iptype;
5295 
5296 	/* construct the privilege lists */
5297 	if (brand_config_iter_privilege(bh, priv_lists_cb, plp) != 0) {
5298 		priv_lists_destroy(plp);
5299 		brand_close(bh);
5300 		return (Z_BRAND_ERROR);
5301 	}
5302 
5303 	brand_close(bh);
5304 	*plpp = plp;
5305 	return (Z_OK);
5306 }
5307 
5308 static int
5309 get_default_privset(priv_set_t *privs, priv_lists_t *plp)
5310 {
5311 	priv_node_t *pnp;
5312 	priv_set_t *basic;
5313 
5314 	basic = priv_str_to_set(BASIC_TOKEN, TOKEN_PRIV_STR, NULL);
5315 	if (basic == NULL)
5316 		return (errno == ENOMEM ? Z_NOMEM : Z_INVAL);
5317 
5318 	priv_union(basic, privs);
5319 	priv_freeset(basic);
5320 
5321 	for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) {
5322 		if (priv_addset(privs, pnp->pn_priv) != 0)
5323 			return (Z_INVAL);
5324 	}
5325 
5326 	return (Z_OK);
5327 }
5328 
5329 int
5330 zonecfg_default_brand(char *brand, size_t brandsize)
5331 {
5332 	zone_dochandle_t handle;
5333 	int myzoneid = getzoneid();
5334 	int ret;
5335 
5336 	/*
5337 	 * If we're running within a zone, then the default brand is the
5338 	 * current zone's brand.
5339 	 */
5340 	if (myzoneid != GLOBAL_ZONEID) {
5341 		ret = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brand, brandsize);
5342 		if (ret < 0)
5343 			return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL);
5344 		return (Z_OK);
5345 	}
5346 
5347 	if ((handle = zonecfg_init_handle()) == NULL)
5348 		return (Z_NOMEM);
5349 	if ((ret = zonecfg_get_handle("SUNWdefault", handle)) == Z_OK) {
5350 		ret = i_zonecfg_get_brand(handle, brand, brandsize, B_TRUE);
5351 		zonecfg_fini_handle(handle);
5352 		return (ret);
5353 	}
5354 	return (ret);
5355 }
5356 
5357 int
5358 zonecfg_default_privset(priv_set_t *privs, const char *curr_iptype)
5359 {
5360 	priv_lists_t *plp;
5361 	char buf[MAXNAMELEN];
5362 	int ret;
5363 
5364 	if ((ret = zonecfg_default_brand(buf, sizeof (buf))) != Z_OK)
5365 		return (ret);
5366 	if ((ret = priv_lists_create(NULL, buf, &plp, curr_iptype)) != Z_OK)
5367 		return (ret);
5368 	ret = get_default_privset(privs, plp);
5369 	priv_lists_destroy(plp);
5370 	return (ret);
5371 }
5372 
5373 void
5374 append_priv_token(char *priv, char *str, size_t strlen)
5375 {
5376 	if (*str != '\0')
5377 		(void) strlcat(str, TOKEN_PRIV_STR, strlen);
5378 	(void) strlcat(str, priv, strlen);
5379 }
5380 
5381 /*
5382  * Verify that the supplied string is a valid privilege limit set for a
5383  * non-global zone.  This string must not only be acceptable to
5384  * priv_str_to_set(3C) which parses it, but it also must resolve to a
5385  * privilege set that includes certain required privileges and lacks
5386  * certain prohibited privileges.
5387  */
5388 static int
5389 verify_privset(char *privbuf, priv_set_t *privs, char **privname,
5390     boolean_t add_default, priv_lists_t *plp)
5391 {
5392 	priv_node_t *pnp;
5393 	char *tmp, *cp, *lasts;
5394 	size_t len;
5395 	priv_set_t *mergeset;
5396 	const char *token;
5397 
5398 	/*
5399 	 * The verification of the privilege string occurs in several
5400 	 * phases.  In the first phase, the supplied string is scanned for
5401 	 * the ZONE_TOKEN token which is not support as part of the
5402 	 * "limitpriv" property.
5403 	 *
5404 	 * Duplicate the supplied privilege string since strtok_r(3C)
5405 	 * tokenizes its input by null-terminating the tokens.
5406 	 */
5407 	if ((tmp = strdup(privbuf)) == NULL)
5408 		return (Z_NOMEM);
5409 	for (cp = strtok_r(tmp, TOKEN_PRIV_STR, &lasts); cp != NULL;
5410 	    cp = strtok_r(NULL, TOKEN_PRIV_STR, &lasts)) {
5411 		if (strcmp(cp, ZONE_TOKEN) == 0) {
5412 			free(tmp);
5413 			if ((*privname = strdup(ZONE_TOKEN)) == NULL)
5414 				return (Z_NOMEM);
5415 			else
5416 				return (Z_PRIV_UNKNOWN);
5417 		}
5418 	}
5419 	free(tmp);
5420 
5421 	if (add_default) {
5422 		/*
5423 		 * If DEFAULT_TOKEN was specified, a string needs to be
5424 		 * built containing the privileges from the default, safe
5425 		 * set along with those of the "limitpriv" property.
5426 		 */
5427 		len = strlen(privbuf) + sizeof (BASIC_TOKEN) + 2;
5428 
5429 		for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next)
5430 			len += strlen(pnp->pn_priv) + 1;
5431 		tmp = alloca(len);
5432 		*tmp = '\0';
5433 
5434 		append_priv_token(BASIC_TOKEN, tmp, len);
5435 		for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next)
5436 			append_priv_token(pnp->pn_priv, tmp, len);
5437 		(void) strlcat(tmp, TOKEN_PRIV_STR, len);
5438 		(void) strlcat(tmp, privbuf, len);
5439 	} else {
5440 		tmp = privbuf;
5441 	}
5442 
5443 
5444 	/*
5445 	 * In the next phase, attempt to convert the merged privilege
5446 	 * string into a privilege set.  In the case of an error, either
5447 	 * there was a memory allocation failure or there was an invalid
5448 	 * privilege token in the string.  In either case, return an
5449 	 * appropriate error code but in the event of an invalid token,
5450 	 * allocate a string containing its name and return that back to
5451 	 * the caller.
5452 	 */
5453 	mergeset = priv_str_to_set(tmp, TOKEN_PRIV_STR, &token);
5454 	if (mergeset == NULL) {
5455 		if (token == NULL)
5456 			return (Z_NOMEM);
5457 		if ((cp = strchr(token, TOKEN_PRIV_CHAR)) != NULL)
5458 			*cp = '\0';
5459 		if ((*privname = strdup(token)) == NULL)
5460 			return (Z_NOMEM);
5461 		else
5462 			return (Z_PRIV_UNKNOWN);
5463 	}
5464 
5465 	/*
5466 	 * Next, verify that none of the prohibited zone privileges are
5467 	 * present in the merged privilege set.
5468 	 */
5469 	for (pnp = plp->pl_prohibited; pnp != NULL; pnp = pnp->pn_next) {
5470 		if (priv_ismember(mergeset, pnp->pn_priv)) {
5471 			priv_freeset(mergeset);
5472 			if ((*privname = strdup(pnp->pn_priv)) == NULL)
5473 				return (Z_NOMEM);
5474 			else
5475 				return (Z_PRIV_PROHIBITED);
5476 		}
5477 	}
5478 
5479 	/*
5480 	 * Finally, verify that all of the required zone privileges are
5481 	 * present in the merged privilege set.
5482 	 */
5483 	for (pnp = plp->pl_required; pnp != NULL; pnp = pnp->pn_next) {
5484 		if (!priv_ismember(mergeset, pnp->pn_priv)) {
5485 			priv_freeset(mergeset);
5486 			if ((*privname = strdup(pnp->pn_priv)) == NULL)
5487 				return (Z_NOMEM);
5488 			else
5489 				return (Z_PRIV_REQUIRED);
5490 		}
5491 	}
5492 
5493 	priv_copyset(mergeset, privs);
5494 	priv_freeset(mergeset);
5495 	return (Z_OK);
5496 }
5497 
5498 /*
5499  * Fill in the supplied privilege set with either the default, safe set of
5500  * privileges suitable for a non-global zone, or one based on the
5501  * "limitpriv" property in the zone's configuration.
5502  *
5503  * In the event of an invalid privilege specification in the
5504  * configuration, a string is allocated and returned containing the
5505  * "privilege" causing the issue.  It is the caller's responsibility to
5506  * free this memory when it is done with it.
5507  */
5508 int
5509 zonecfg_get_privset(zone_dochandle_t handle, priv_set_t *privs,
5510     char **privname)
5511 {
5512 	priv_lists_t *plp;
5513 	char *cp, *limitpriv = NULL;
5514 	int err, limitlen;
5515 	zone_iptype_t iptype;
5516 	const char *curr_iptype;
5517 
5518 	/*
5519 	 * Attempt to lookup the "limitpriv" property.  If it does not
5520 	 * exist or matches the string DEFAULT_TOKEN exactly, then the
5521 	 * default, safe privilege set is returned.
5522 	 */
5523 	if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) != Z_OK)
5524 		return (err);
5525 
5526 	if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK)
5527 		return (err);
5528 
5529 	switch (iptype) {
5530 	case ZS_SHARED:
5531 		curr_iptype = "shared";
5532 		break;
5533 	case ZS_EXCLUSIVE:
5534 		curr_iptype = "exclusive";
5535 		break;
5536 	}
5537 
5538 	if ((err = priv_lists_create(handle, NULL, &plp, curr_iptype)) != Z_OK)
5539 		return (err);
5540 
5541 	limitlen = strlen(limitpriv);
5542 	if (limitlen == 0 || strcmp(limitpriv, DEFAULT_TOKEN) == 0) {
5543 		free(limitpriv);
5544 		err = get_default_privset(privs, plp);
5545 		priv_lists_destroy(plp);
5546 		return (err);
5547 	}
5548 
5549 	/*
5550 	 * Check if the string DEFAULT_TOKEN is the first token in a list
5551 	 * of privileges.
5552 	 */
5553 	cp = strchr(limitpriv, TOKEN_PRIV_CHAR);
5554 	if (cp != NULL &&
5555 	    strncmp(limitpriv, DEFAULT_TOKEN, cp - limitpriv) == 0)
5556 		err = verify_privset(cp + 1, privs, privname, B_TRUE, plp);
5557 	else
5558 		err = verify_privset(limitpriv, privs, privname, B_FALSE, plp);
5559 
5560 	free(limitpriv);
5561 	priv_lists_destroy(plp);
5562 	return (err);
5563 }
5564 
5565 int
5566 zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz)
5567 {
5568 	zone_dochandle_t handle;
5569 	boolean_t found = B_FALSE;
5570 	struct zoneent *ze;
5571 	FILE *cookie;
5572 	int err;
5573 	char *cp;
5574 
5575 	if (zone_name == NULL)
5576 		return (Z_INVAL);
5577 
5578 	(void) strlcpy(zonepath, zonecfg_root, rp_sz);
5579 	cp = zonepath + strlen(zonepath);
5580 	while (cp > zonepath && cp[-1] == '/')
5581 		*--cp = '\0';
5582 
5583 	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) {
5584 		if (zonepath[0] == '\0')
5585 			(void) strlcpy(zonepath, "/", rp_sz);
5586 		return (Z_OK);
5587 	}
5588 
5589 	/*
5590 	 * First check the index file.  Because older versions did not have
5591 	 * a copy of the zone path, allow for it to be zero length, in which
5592 	 * case we ignore this result and fall back to the XML files.
5593 	 */
5594 	cookie = setzoneent();
5595 	while ((ze = getzoneent_private(cookie)) != NULL) {
5596 		if (strcmp(ze->zone_name, zone_name) == 0) {
5597 			found = B_TRUE;
5598 			if (ze->zone_path[0] != '\0')
5599 				(void) strlcpy(cp, ze->zone_path,
5600 				    rp_sz - (cp - zonepath));
5601 		}
5602 		free(ze);
5603 		if (found)
5604 			break;
5605 	}
5606 	endzoneent(cookie);
5607 	if (found && *cp != '\0')
5608 		return (Z_OK);
5609 
5610 	/* Fall back to the XML files. */
5611 	if ((handle = zonecfg_init_handle()) == NULL)
5612 		return (Z_NOMEM);
5613 
5614 	/*
5615 	 * Check the snapshot first: if a zone is running, its zonepath
5616 	 * may have changed.
5617 	 */
5618 	if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
5619 		if ((err = zonecfg_get_handle(zone_name, handle)) != Z_OK) {
5620 			zonecfg_fini_handle(handle);
5621 			return (err);
5622 		}
5623 	}
5624 	err = zonecfg_get_zonepath(handle, zonepath, rp_sz);
5625 	zonecfg_fini_handle(handle);
5626 	return (err);
5627 }
5628 
5629 int
5630 zone_get_rootpath(char *zone_name, char *rootpath, size_t rp_sz)
5631 {
5632 	int err;
5633 
5634 	/* This function makes sense for non-global zones only. */
5635 	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
5636 		return (Z_BOGUS_ZONE_NAME);
5637 	if ((err = zone_get_zonepath(zone_name, rootpath, rp_sz)) != Z_OK)
5638 		return (err);
5639 	if (strlcat(rootpath, "/root", rp_sz) >= rp_sz)
5640 		return (Z_TOO_BIG);
5641 	return (Z_OK);
5642 }
5643 
5644 int
5645 zone_get_brand(char *zone_name, char *brandname, size_t rp_sz)
5646 {
5647 	int err;
5648 	zone_dochandle_t handle;
5649 	char myzone[MAXNAMELEN];
5650 	int myzoneid = getzoneid();
5651 
5652 	/*
5653 	 * If we are not in the global zone, then we don't have the zone
5654 	 * .xml files with the brand name available.  Thus, we are going to
5655 	 * have to ask the kernel for the information.
5656 	 */
5657 	if (myzoneid != GLOBAL_ZONEID) {
5658 		if (is_system_labeled()) {
5659 			(void) strlcpy(brandname, NATIVE_BRAND_NAME, rp_sz);
5660 			return (Z_OK);
5661 		}
5662 		if (zone_getattr(myzoneid, ZONE_ATTR_NAME, myzone,
5663 		    sizeof (myzone)) < 0)
5664 			return (Z_NO_ZONE);
5665 		if (!zonecfg_is_scratch(myzone)) {
5666 			if (strncmp(zone_name, myzone, MAXNAMELEN) != 0)
5667 				return (Z_NO_ZONE);
5668 		}
5669 		err = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brandname, rp_sz);
5670 		if (err < 0)
5671 			return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL);
5672 
5673 		return (Z_OK);
5674 	}
5675 
5676 	if (strcmp(zone_name, "global") == 0)
5677 		return (zonecfg_default_brand(brandname, rp_sz));
5678 
5679 	if ((handle = zonecfg_init_handle()) == NULL)
5680 		return (Z_NOMEM);
5681 
5682 	err = zonecfg_get_handle((char *)zone_name, handle);
5683 	if (err == Z_OK)
5684 		err = zonecfg_get_brand(handle, brandname, rp_sz);
5685 
5686 	zonecfg_fini_handle(handle);
5687 	return (err);
5688 }
5689 
5690 /*
5691  * Return the appropriate root for the active /dev.
5692  * For normal zone, the path is $ZONEPATH/root;
5693  * for scratch zone, the dev path is $ZONEPATH/lu.
5694  */
5695 int
5696 zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz)
5697 {
5698 	int err;
5699 	char *suffix;
5700 	zone_state_t state;
5701 
5702 	/* This function makes sense for non-global zones only. */
5703 	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
5704 		return (Z_BOGUS_ZONE_NAME);
5705 	if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK)
5706 		return (err);
5707 
5708 	if (zone_get_state(zone_name, &state) == Z_OK &&
5709 	    state == ZONE_STATE_MOUNTED)
5710 		suffix = "/lu";
5711 	else
5712 		suffix = "/root";
5713 	if (strlcat(devroot, suffix, rp_sz) >= rp_sz)
5714 		return (Z_TOO_BIG);
5715 	return (Z_OK);
5716 }
5717 
5718 static zone_state_t
5719 kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state)
5720 {
5721 	char zoneroot[MAXPATHLEN];
5722 	size_t zlen;
5723 
5724 	assert(kernel_state <= ZONE_MAX_STATE);
5725 	switch (kernel_state) {
5726 		case ZONE_IS_UNINITIALIZED:
5727 		case ZONE_IS_INITIALIZED:
5728 			/* The kernel will not return these two states */
5729 			return (ZONE_STATE_READY);
5730 		case ZONE_IS_READY:
5731 			/*
5732 			 * If the zone's root is mounted on $ZONEPATH/lu, then
5733 			 * it's a mounted scratch zone.
5734 			 */
5735 			if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot,
5736 			    sizeof (zoneroot)) >= 0) {
5737 				zlen = strlen(zoneroot);
5738 				if (zlen > 3 &&
5739 				    strcmp(zoneroot + zlen - 3, "/lu") == 0)
5740 					return (ZONE_STATE_MOUNTED);
5741 			}
5742 			return (ZONE_STATE_READY);
5743 		case ZONE_IS_BOOTING:
5744 		case ZONE_IS_RUNNING:
5745 			return (ZONE_STATE_RUNNING);
5746 		case ZONE_IS_SHUTTING_DOWN:
5747 		case ZONE_IS_EMPTY:
5748 			return (ZONE_STATE_SHUTTING_DOWN);
5749 		case ZONE_IS_DOWN:
5750 		case ZONE_IS_DYING:
5751 		case ZONE_IS_DEAD:
5752 		default:
5753 			return (ZONE_STATE_DOWN);
5754 	}
5755 	/* NOTREACHED */
5756 }
5757 
5758 int
5759 zone_get_state(char *zone_name, zone_state_t *state_num)
5760 {
5761 	zone_status_t status;
5762 	zoneid_t zone_id;
5763 	struct zoneent *ze;
5764 	boolean_t found = B_FALSE;
5765 	FILE *cookie;
5766 	char kernzone[ZONENAME_MAX];
5767 	FILE *fp;
5768 
5769 	if (zone_name == NULL)
5770 		return (Z_INVAL);
5771 
5772 	/*
5773 	 * If we're looking at an alternate root, then we need to query the
5774 	 * kernel using the scratch zone name.
5775 	 */
5776 	zone_id = -1;
5777 	if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) {
5778 		if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) {
5779 			if (zonecfg_find_scratch(fp, zone_name, zonecfg_root,
5780 			    kernzone, sizeof (kernzone)) == 0)
5781 				zone_id = getzoneidbyname(kernzone);
5782 			zonecfg_close_scratch(fp);
5783 		}
5784 	} else {
5785 		zone_id = getzoneidbyname(zone_name);
5786 	}
5787 
5788 	/* check to see if zone is running */
5789 	if (zone_id != -1 &&
5790 	    zone_getattr(zone_id, ZONE_ATTR_STATUS, &status,
5791 	    sizeof (status)) >= 0) {
5792 		*state_num = kernel_state_to_user_state(zone_id, status);
5793 		return (Z_OK);
5794 	}
5795 
5796 	cookie = setzoneent();
5797 	while ((ze = getzoneent_private(cookie)) != NULL) {
5798 		if (strcmp(ze->zone_name, zone_name) == 0) {
5799 			found = B_TRUE;
5800 			*state_num = ze->zone_state;
5801 		}
5802 		free(ze);
5803 		if (found)
5804 			break;
5805 	}
5806 	endzoneent(cookie);
5807 	return ((found) ? Z_OK : Z_NO_ZONE);
5808 }
5809 
5810 int
5811 zone_set_state(char *zone, zone_state_t state)
5812 {
5813 	struct zoneent ze;
5814 
5815 	if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED &&
5816 	    state != ZONE_STATE_INCOMPLETE)
5817 		return (Z_INVAL);
5818 
5819 	bzero(&ze, sizeof (ze));
5820 	(void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name));
5821 	ze.zone_state = state;
5822 	(void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path));
5823 	return (putzoneent(&ze, PZE_MODIFY));
5824 }
5825 
5826 /*
5827  * Get id (if any) for specified zone.  There are four possible outcomes:
5828  * - If the string corresponds to the numeric id of an active (booted)
5829  *   zone, sets *zip to the zone id and returns 0.
5830  * - If the string corresponds to the name of an active (booted) zone,
5831  *   sets *zip to the zone id and returns 0.
5832  * - If the string is a name in the configuration but is not booted,
5833  *   sets *zip to ZONE_ID_UNDEFINED and returns 0.
5834  * - Otherwise, leaves *zip unchanged and returns -1.
5835  *
5836  * This function acts as an auxiliary filter on the function of the same
5837  * name in libc; the linker binds to this version if libzonecfg exists,
5838  * and the libc version if it doesn't.  Any changes to this version of
5839  * the function should probably be reflected in the libc version as well.
5840  */
5841 int
5842 zone_get_id(const char *str, zoneid_t *zip)
5843 {
5844 	zone_dochandle_t hdl;
5845 	zoneid_t zoneid;
5846 	char *cp;
5847 	int err;
5848 
5849 	/* first try looking for active zone by id */
5850 	errno = 0;
5851 	zoneid = (zoneid_t)strtol(str, &cp, 0);
5852 	if (errno == 0 && cp != str && *cp == '\0' &&
5853 	    getzonenamebyid(zoneid, NULL, 0) != -1) {
5854 		*zip = zoneid;
5855 		return (0);
5856 	}
5857 
5858 	/* then look for active zone by name */
5859 	if ((zoneid = getzoneidbyname(str)) != -1) {
5860 		*zip = zoneid;
5861 		return (0);
5862 	}
5863 
5864 	/* if in global zone, try looking up name in configuration database */
5865 	if (getzoneid() != GLOBAL_ZONEID ||
5866 	    (hdl = zonecfg_init_handle()) == NULL)
5867 		return (-1);
5868 
5869 	if (zonecfg_get_handle(str, hdl) == Z_OK) {
5870 		/* zone exists but isn't active */
5871 		*zip = ZONE_ID_UNDEFINED;
5872 		err = 0;
5873 	} else {
5874 		err = -1;
5875 	}
5876 
5877 	zonecfg_fini_handle(hdl);
5878 	return (err);
5879 }
5880 
5881 char *
5882 zone_state_str(zone_state_t state_num)
5883 {
5884 	switch (state_num) {
5885 	case ZONE_STATE_CONFIGURED:
5886 		return (ZONE_STATE_STR_CONFIGURED);
5887 	case ZONE_STATE_INCOMPLETE:
5888 		return (ZONE_STATE_STR_INCOMPLETE);
5889 	case ZONE_STATE_INSTALLED:
5890 		return (ZONE_STATE_STR_INSTALLED);
5891 	case ZONE_STATE_READY:
5892 		return (ZONE_STATE_STR_READY);
5893 	case ZONE_STATE_MOUNTED:
5894 		return (ZONE_STATE_STR_MOUNTED);
5895 	case ZONE_STATE_RUNNING:
5896 		return (ZONE_STATE_STR_RUNNING);
5897 	case ZONE_STATE_SHUTTING_DOWN:
5898 		return (ZONE_STATE_STR_SHUTTING_DOWN);
5899 	case ZONE_STATE_DOWN:
5900 		return (ZONE_STATE_STR_DOWN);
5901 	default:
5902 		return ("unknown");
5903 	}
5904 }
5905 
5906 /*
5907  * Given a UUID value, find an associated zone name.  This is intended to be
5908  * used by callers who set up some 'default' name (corresponding to the
5909  * expected name for the zone) in the zonename buffer, and thus the function
5910  * doesn't touch this buffer on failure.
5911  */
5912 int
5913 zonecfg_get_name_by_uuid(const uuid_t uuidin, char *zonename, size_t namelen)
5914 {
5915 	FILE *fp;
5916 	struct zoneent *ze;
5917 	uchar_t *uuid;
5918 
5919 	/*
5920 	 * A small amount of subterfuge via casts is necessary here because
5921 	 * libuuid doesn't use const correctly, but we don't want to export
5922 	 * this brokenness to our clients.
5923 	 */
5924 	uuid = (uchar_t *)uuidin;
5925 	if (uuid_is_null(uuid))
5926 		return (Z_NO_ZONE);
5927 	if ((fp = setzoneent()) == NULL)
5928 		return (Z_NO_ZONE);
5929 	while ((ze = getzoneent_private(fp)) != NULL) {
5930 		if (uuid_compare(uuid, ze->zone_uuid) == 0)
5931 			break;
5932 		free(ze);
5933 	}
5934 	endzoneent(fp);
5935 	if (ze != NULL) {
5936 		(void) strlcpy(zonename, ze->zone_name, namelen);
5937 		free(ze);
5938 		return (Z_OK);
5939 	} else {
5940 		return (Z_NO_ZONE);
5941 	}
5942 }
5943 
5944 /*
5945  * Given a zone name, get its UUID.  Returns a "NULL" UUID value if the zone
5946  * exists but the file doesn't have a value set yet.  Returns an error if the
5947  * zone cannot be located.
5948  */
5949 int
5950 zonecfg_get_uuid(const char *zonename, uuid_t uuid)
5951 {
5952 	FILE *fp;
5953 	struct zoneent *ze;
5954 
5955 	if ((fp = setzoneent()) == NULL)
5956 		return (Z_NO_ZONE);
5957 	while ((ze = getzoneent_private(fp)) != NULL) {
5958 		if (strcmp(ze->zone_name, zonename) == 0)
5959 			break;
5960 		free(ze);
5961 	}
5962 	endzoneent(fp);
5963 	if (ze != NULL) {
5964 		uuid_copy(uuid, ze->zone_uuid);
5965 		free(ze);
5966 		return (Z_OK);
5967 	} else {
5968 		return (Z_NO_ZONE);
5969 	}
5970 }
5971 
5972 /*
5973  * File-system convenience functions.
5974  */
5975 boolean_t
5976 zonecfg_valid_fs_type(const char *type)
5977 {
5978 	/*
5979 	 * We already know which FS types don't work.
5980 	 */
5981 	if (strcmp(type, "proc") == 0 ||
5982 	    strcmp(type, "mntfs") == 0 ||
5983 	    strcmp(type, "autofs") == 0 ||
5984 	    strncmp(type, "nfs", sizeof ("nfs") - 1) == 0)
5985 		return (B_FALSE);
5986 	/*
5987 	 * The caller may do more detailed verification to make sure other
5988 	 * aspects of this filesystem type make sense.
5989 	 */
5990 	return (B_TRUE);
5991 }
5992 
5993 /*
5994  * Generally uninteresting rctl convenience functions.
5995  */
5996 
5997 int
5998 zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval,
5999     rctlblk_t *rctlblk)
6000 {
6001 	unsigned long long ull;
6002 	char *endp;
6003 	rctl_priv_t priv;
6004 	rctl_qty_t limit;
6005 	uint_t action;
6006 
6007 	/* Get the privilege */
6008 	if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) {
6009 		priv = RCPRIV_BASIC;
6010 	} else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) {
6011 		priv = RCPRIV_PRIVILEGED;
6012 	} else {
6013 		/* Invalid privilege */
6014 		return (Z_INVAL);
6015 	}
6016 
6017 	/* deal with negative input; strtoull(3c) doesn't do what we want */
6018 	if (rctlval->zone_rctlval_limit[0] == '-')
6019 		return (Z_INVAL);
6020 	/* Get the limit */
6021 	errno = 0;
6022 	ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0);
6023 	if (errno != 0 || *endp != '\0') {
6024 		/* parse failed */
6025 		return (Z_INVAL);
6026 	}
6027 	limit = (rctl_qty_t)ull;
6028 
6029 	/* Get the action */
6030 	if (strcmp(rctlval->zone_rctlval_action, "none") == 0) {
6031 		action = RCTL_LOCAL_NOACTION;
6032 	} else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) {
6033 		action = RCTL_LOCAL_SIGNAL;
6034 	} else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) {
6035 		action = RCTL_LOCAL_DENY;
6036 	} else {
6037 		/* Invalid Action */
6038 		return (Z_INVAL);
6039 	}
6040 	rctlblk_set_local_action(rctlblk, action, 0);
6041 	rctlblk_set_privilege(rctlblk, priv);
6042 	rctlblk_set_value(rctlblk, limit);
6043 	return (Z_OK);
6044 }
6045 
6046 static int
6047 rctl_check(const char *rctlname, void *arg)
6048 {
6049 	const char *attrname = arg;
6050 
6051 	/*
6052 	 * Returning 1 here is our signal to zonecfg_is_rctl() that it is
6053 	 * indeed an rctl name recognized by the system.
6054 	 */
6055 	return (strcmp(rctlname, attrname) == 0 ? 1 : 0);
6056 }
6057 
6058 boolean_t
6059 zonecfg_is_rctl(const char *name)
6060 {
6061 	return (rctl_walk(rctl_check, (void *)name) == 1);
6062 }
6063 
6064 boolean_t
6065 zonecfg_valid_rctlname(const char *name)
6066 {
6067 	const char *c;
6068 
6069 	if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0)
6070 		return (B_FALSE);
6071 	if (strlen(name) == sizeof ("zone.") - 1)
6072 		return (B_FALSE);
6073 	for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) {
6074 		if (!isalpha(*c) && *c != '-')
6075 			return (B_FALSE);
6076 	}
6077 	return (B_TRUE);
6078 }
6079 
6080 boolean_t
6081 zonecfg_valid_rctlblk(const rctlblk_t *rctlblk)
6082 {
6083 	rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk);
6084 	uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
6085 
6086 	if (priv != RCPRIV_PRIVILEGED)
6087 		return (B_FALSE);
6088 	if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY)
6089 		return (B_FALSE);
6090 	return (B_TRUE);
6091 }
6092 
6093 boolean_t
6094 zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk)
6095 {
6096 	rctlblk_t *current, *next;
6097 	rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk);
6098 	uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
6099 	uint_t global_flags;
6100 
6101 	if (!zonecfg_valid_rctlblk(rctlblk))
6102 		return (B_FALSE);
6103 	if (!zonecfg_valid_rctlname(name))
6104 		return (B_FALSE);
6105 
6106 	current = alloca(rctlblk_size());
6107 	if (getrctl(name, NULL, current, RCTL_FIRST) != 0)
6108 		return (B_TRUE);	/* not an rctl on this system */
6109 	/*
6110 	 * Make sure the proposed value isn't greater than the current system
6111 	 * value.
6112 	 */
6113 	next = alloca(rctlblk_size());
6114 	while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) {
6115 		rctlblk_t *tmp;
6116 
6117 		if (getrctl(name, current, next, RCTL_NEXT) != 0)
6118 			return (B_FALSE);	/* shouldn't happen */
6119 		tmp = current;
6120 		current = next;
6121 		next = tmp;
6122 	}
6123 	if (limit > rctlblk_get_value(current))
6124 		return (B_FALSE);
6125 
6126 	/*
6127 	 * Make sure the proposed action is allowed.
6128 	 */
6129 	global_flags = rctlblk_get_global_flags(current);
6130 	if ((global_flags & RCTL_GLOBAL_DENY_NEVER) &&
6131 	    action == RCTL_LOCAL_DENY)
6132 		return (B_FALSE);
6133 	if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) &&
6134 	    action == RCTL_LOCAL_NOACTION)
6135 		return (B_FALSE);
6136 
6137 	return (B_TRUE);
6138 }
6139 
6140 /*
6141  * There is always a race condition between reading the initial copy of
6142  * a zones state and its state changing.  We address this by providing
6143  * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions.
6144  * When zonecfg_critical_enter is called, sets the state field to LOCKED
6145  * and aquires biglock. Biglock protects against other threads executing
6146  * critical_enter and the state field protects against state changes during
6147  * the critical period.
6148  *
6149  * If any state changes occur, zn_cb will set the failed field of the znotify
6150  * structure.  This will cause the critical_exit function to re-lock the
6151  * channel and return an error. Since evsnts may be delayed, the critical_exit
6152  * function "flushes" the queue by putting an event on the queue and waiting for
6153  * zn_cb to notify critical_exit that it received the ping event.
6154  */
6155 static const char *
6156 string_get_tok(const char *in, char delim, int num)
6157 {
6158 	int i = 0;
6159 
6160 	for (; i < num; in++) {
6161 		if (*in == delim)
6162 			i++;
6163 		if (*in == 0)
6164 			return (NULL);
6165 	}
6166 	return (in);
6167 }
6168 
6169 static boolean_t
6170 is_ping(sysevent_t *ev)
6171 {
6172 	if (strcmp(sysevent_get_subclass_name(ev),
6173 	    ZONE_EVENT_PING_SUBCLASS) == 0) {
6174 		return (B_TRUE);
6175 	} else {
6176 		return (B_FALSE);
6177 	}
6178 }
6179 
6180 static boolean_t
6181 is_my_ping(sysevent_t *ev)
6182 {
6183 	const char *sender;
6184 	char mypid[sizeof (pid_t) * 3 + 1];
6185 
6186 	(void) snprintf(mypid, sizeof (mypid), "%i", getpid());
6187 	sender = string_get_tok(sysevent_get_pub(ev), ':', 3);
6188 	if (sender == NULL)
6189 		return (B_FALSE);
6190 	if (strcmp(sender, mypid) != 0)
6191 		return (B_FALSE);
6192 	return (B_TRUE);
6193 }
6194 
6195 static int
6196 do_callback(struct znotify *zevtchan, sysevent_t *ev)
6197 {
6198 	nvlist_t *l;
6199 	int zid;
6200 	char *zonename;
6201 	char *newstate;
6202 	char *oldstate;
6203 	int ret;
6204 	hrtime_t when;
6205 
6206 	if (strcmp(sysevent_get_subclass_name(ev),
6207 	    ZONE_EVENT_STATUS_SUBCLASS) == 0) {
6208 
6209 		if (sysevent_get_attr_list(ev, &l) != 0) {
6210 			if (errno == ENOMEM) {
6211 				zevtchan->zn_failure_count++;
6212 				return (EAGAIN);
6213 			}
6214 			return (0);
6215 		}
6216 		ret = 0;
6217 
6218 		if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) &&
6219 		    (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate)
6220 		    == 0) &&
6221 		    (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate)
6222 		    == 0) &&
6223 		    (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP,
6224 		    (uint64_t *)&when) == 0) &&
6225 		    (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) {
6226 			ret = zevtchan->zn_callback(zonename, zid, newstate,
6227 			    oldstate, when, zevtchan->zn_private);
6228 		}
6229 
6230 		zevtchan->zn_failure_count = 0;
6231 		nvlist_free(l);
6232 		return (ret);
6233 	} else {
6234 		/*
6235 		 * We have received an event in an unknown subclass. Ignore.
6236 		 */
6237 		zevtchan->zn_failure_count = 0;
6238 		return (0);
6239 	}
6240 }
6241 
6242 static int
6243 zn_cb(sysevent_t *ev, void *p)
6244 {
6245 	struct znotify *zevtchan = p;
6246 	int error;
6247 
6248 	(void) pthread_mutex_lock(&(zevtchan->zn_mutex));
6249 
6250 	if (is_ping(ev) && !is_my_ping(ev)) {
6251 		(void) pthread_mutex_unlock((&zevtchan->zn_mutex));
6252 		return (0);
6253 	}
6254 
6255 	if (zevtchan->zn_state == ZN_LOCKED) {
6256 		assert(!is_ping(ev));
6257 		zevtchan->zn_failed = B_TRUE;
6258 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
6259 		return (0);
6260 	}
6261 
6262 	if (zevtchan->zn_state == ZN_PING_INFLIGHT) {
6263 		if (is_ping(ev)) {
6264 			zevtchan->zn_state = ZN_PING_RECEIVED;
6265 			(void) pthread_cond_signal(&(zevtchan->zn_cond));
6266 			(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
6267 			return (0);
6268 		} else {
6269 			zevtchan->zn_failed = B_TRUE;
6270 			(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
6271 			return (0);
6272 		}
6273 	}
6274 
6275 	if (zevtchan->zn_state == ZN_UNLOCKED) {
6276 
6277 		error = do_callback(zevtchan, ev);
6278 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
6279 		/*
6280 		 * Every ENOMEM failure causes do_callback to increment
6281 		 * zn_failure_count and every success causes it to
6282 		 * set zn_failure_count to zero.  If we got EAGAIN,
6283 		 * we will sleep for zn_failure_count seconds and return
6284 		 * EAGAIN to gpec to try again.
6285 		 *
6286 		 * After 55 seconds, or 10 try's we give up and drop the
6287 		 * event.
6288 		 */
6289 		if (error == EAGAIN) {
6290 			if (zevtchan->zn_failure_count > ZONE_CB_RETRY_COUNT) {
6291 				return (0);
6292 			}
6293 			(void) sleep(zevtchan->zn_failure_count);
6294 		}
6295 		return (error);
6296 	}
6297 
6298 	if (zevtchan->zn_state == ZN_PING_RECEIVED) {
6299 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
6300 		return (0);
6301 	}
6302 
6303 	abort();
6304 	return (0);
6305 }
6306 
6307 void
6308 zonecfg_notify_critical_enter(void *h)
6309 {
6310 	struct znotify *zevtchan = h;
6311 
6312 	(void) pthread_mutex_lock(&(zevtchan->zn_bigmutex));
6313 	zevtchan->zn_state = ZN_LOCKED;
6314 }
6315 
6316 int
6317 zonecfg_notify_critical_exit(void * h)
6318 {
6319 
6320 	struct znotify *zevtchan = h;
6321 
6322 	if (zevtchan->zn_state == ZN_UNLOCKED)
6323 		return (0);
6324 
6325 	(void) pthread_mutex_lock(&(zevtchan->zn_mutex));
6326 	zevtchan->zn_state = ZN_PING_INFLIGHT;
6327 
6328 	(void) sysevent_evc_publish(zevtchan->zn_eventchan,
6329 	    ZONE_EVENT_STATUS_CLASS,
6330 	    ZONE_EVENT_PING_SUBCLASS, ZONE_EVENT_PING_PUBLISHER,
6331 	    zevtchan->zn_subscriber_id, NULL, EVCH_SLEEP);
6332 
6333 	while (zevtchan->zn_state != ZN_PING_RECEIVED) {
6334 		(void) pthread_cond_wait(&(zevtchan->zn_cond),
6335 		    &(zevtchan->zn_mutex));
6336 	}
6337 
6338 	if (zevtchan->zn_failed == B_TRUE) {
6339 		zevtchan->zn_state = ZN_LOCKED;
6340 		zevtchan->zn_failed = B_FALSE;
6341 		(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
6342 		return (1);
6343 	}
6344 
6345 	zevtchan->zn_state = ZN_UNLOCKED;
6346 	(void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
6347 	(void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex));
6348 	return (0);
6349 }
6350 
6351 void
6352 zonecfg_notify_critical_abort(void *h)
6353 {
6354 	struct znotify *zevtchan = h;
6355 
6356 	zevtchan->zn_state = ZN_UNLOCKED;
6357 	zevtchan->zn_failed = B_FALSE;
6358 	/*
6359 	 * Don't do anything about zn_lock. If it is held, it could only be
6360 	 * held by zn_cb and it will be unlocked soon.
6361 	 */
6362 	(void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex));
6363 }
6364 
6365 void *
6366 zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid,
6367     const char *newstate, const char *oldstate, hrtime_t when, void *p),
6368     void *p)
6369 {
6370 	struct znotify *zevtchan;
6371 	int i = 1;
6372 	int r;
6373 
6374 	zevtchan = malloc(sizeof (struct znotify));
6375 
6376 	if (zevtchan == NULL)
6377 		return (NULL);
6378 
6379 	zevtchan->zn_private = p;
6380 	zevtchan->zn_callback = func;
6381 	zevtchan->zn_state = ZN_UNLOCKED;
6382 	zevtchan->zn_failed = B_FALSE;
6383 
6384 	if (pthread_mutex_init(&(zevtchan->zn_mutex), NULL))
6385 		goto out3;
6386 	if (pthread_cond_init(&(zevtchan->zn_cond), NULL)) {
6387 		(void) pthread_mutex_destroy(&(zevtchan->zn_mutex));
6388 		goto out3;
6389 	}
6390 	if (pthread_mutex_init(&(zevtchan->zn_bigmutex), NULL)) {
6391 		(void) pthread_mutex_destroy(&(zevtchan->zn_mutex));
6392 		(void) pthread_cond_destroy(&(zevtchan->zn_cond));
6393 		goto out3;
6394 	}
6395 
6396 	if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &(zevtchan->zn_eventchan),
6397 	    0) != 0)
6398 		goto out2;
6399 
6400 	do {
6401 		/*
6402 		 * At 4 digits the subscriber ID gets too long and we have
6403 		 * no chance of successfully registering.
6404 		 */
6405 		if (i > 999)
6406 			goto out1;
6407 
6408 		(void) sprintf(zevtchan->zn_subscriber_id, "zone_%li_%i",
6409 		    getpid() % 999999l, i);
6410 
6411 		r = sysevent_evc_subscribe(zevtchan->zn_eventchan,
6412 		    zevtchan->zn_subscriber_id, ZONE_EVENT_STATUS_CLASS, zn_cb,
6413 		    zevtchan, 0);
6414 
6415 		i++;
6416 
6417 	} while (r);
6418 
6419 	return (zevtchan);
6420 out1:
6421 	(void) sysevent_evc_unbind(zevtchan->zn_eventchan);
6422 out2:
6423 	(void) pthread_mutex_destroy(&zevtchan->zn_mutex);
6424 	(void) pthread_cond_destroy(&zevtchan->zn_cond);
6425 	(void) pthread_mutex_destroy(&(zevtchan->zn_bigmutex));
6426 out3:
6427 	free(zevtchan);
6428 
6429 	return (NULL);
6430 }
6431 
6432 void
6433 zonecfg_notify_unbind(void *handle)
6434 {
6435 
6436 	int ret;
6437 
6438 	(void) sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan);
6439 	/*
6440 	 * Check that all evc threads have gone away. This should be
6441 	 * enforced by sysevent_evc_unbind.
6442 	 */
6443 	ret = pthread_mutex_trylock(&((struct znotify *)handle)->zn_mutex);
6444 
6445 	if (ret)
6446 		abort();
6447 
6448 	(void) pthread_mutex_unlock(&((struct znotify *)handle)->zn_mutex);
6449 	(void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_mutex);
6450 	(void) pthread_cond_destroy(&((struct znotify *)handle)->zn_cond);
6451 	(void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_bigmutex);
6452 
6453 	free(handle);
6454 }
6455 
6456 static int
6457 zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
6458 {
6459 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
6460 	int err;
6461 
6462 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DATASET, NULL);
6463 	if ((err = newprop(newnode, DTD_ATTR_NAME,
6464 	    tabptr->zone_dataset_name)) != Z_OK)
6465 		return (err);
6466 	return (Z_OK);
6467 }
6468 
6469 int
6470 zonecfg_add_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
6471 {
6472 	int err;
6473 
6474 	if (tabptr == NULL)
6475 		return (Z_INVAL);
6476 
6477 	if ((err = operation_prep(handle)) != Z_OK)
6478 		return (err);
6479 
6480 	if ((err = zonecfg_add_ds_core(handle, tabptr)) != Z_OK)
6481 		return (err);
6482 
6483 	return (Z_OK);
6484 }
6485 
6486 static int
6487 zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
6488 {
6489 	xmlNodePtr cur = handle->zone_dh_cur;
6490 
6491 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6492 		if (xmlStrcmp(cur->name, DTD_ELEM_DATASET))
6493 			continue;
6494 
6495 		if (match_prop(cur, DTD_ATTR_NAME,
6496 		    tabptr->zone_dataset_name)) {
6497 			xmlUnlinkNode(cur);
6498 			xmlFreeNode(cur);
6499 			return (Z_OK);
6500 		}
6501 	}
6502 	return (Z_NO_RESOURCE_ID);
6503 }
6504 
6505 int
6506 zonecfg_delete_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
6507 {
6508 	int err;
6509 
6510 	if (tabptr == NULL)
6511 		return (Z_INVAL);
6512 
6513 	if ((err = operation_prep(handle)) != Z_OK)
6514 		return (err);
6515 
6516 	if ((err = zonecfg_delete_ds_core(handle, tabptr)) != Z_OK)
6517 		return (err);
6518 
6519 	return (Z_OK);
6520 }
6521 
6522 int
6523 zonecfg_modify_ds(
6524 	zone_dochandle_t handle,
6525 	struct zone_dstab *oldtabptr,
6526 	struct zone_dstab *newtabptr)
6527 {
6528 	int err;
6529 
6530 	if (oldtabptr == NULL || newtabptr == NULL)
6531 		return (Z_INVAL);
6532 
6533 	if ((err = operation_prep(handle)) != Z_OK)
6534 		return (err);
6535 
6536 	if ((err = zonecfg_delete_ds_core(handle, oldtabptr)) != Z_OK)
6537 		return (err);
6538 
6539 	if ((err = zonecfg_add_ds_core(handle, newtabptr)) != Z_OK)
6540 		return (err);
6541 
6542 	return (Z_OK);
6543 }
6544 
6545 int
6546 zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
6547 {
6548 	xmlNodePtr cur, firstmatch;
6549 	int err;
6550 	char dataset[MAXNAMELEN];
6551 
6552 	if (tabptr == NULL)
6553 		return (Z_INVAL);
6554 
6555 	if ((err = operation_prep(handle)) != Z_OK)
6556 		return (err);
6557 
6558 	cur = handle->zone_dh_cur;
6559 	firstmatch = NULL;
6560 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6561 		if (xmlStrcmp(cur->name, DTD_ELEM_DATASET))
6562 			continue;
6563 		if (strlen(tabptr->zone_dataset_name) > 0) {
6564 			if ((fetchprop(cur, DTD_ATTR_NAME, dataset,
6565 			    sizeof (dataset)) == Z_OK) &&
6566 			    (strcmp(tabptr->zone_dataset_name,
6567 			    dataset) == 0)) {
6568 				if (firstmatch == NULL)
6569 					firstmatch = cur;
6570 				else
6571 					return (Z_INSUFFICIENT_SPEC);
6572 			}
6573 		}
6574 	}
6575 	if (firstmatch == NULL)
6576 		return (Z_NO_RESOURCE_ID);
6577 
6578 	cur = firstmatch;
6579 
6580 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
6581 	    sizeof (tabptr->zone_dataset_name))) != Z_OK)
6582 		return (err);
6583 
6584 	return (Z_OK);
6585 }
6586 
6587 int
6588 zonecfg_setdsent(zone_dochandle_t handle)
6589 {
6590 	return (zonecfg_setent(handle));
6591 }
6592 
6593 int
6594 zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr)
6595 {
6596 	xmlNodePtr cur;
6597 	int err;
6598 
6599 	if (handle == NULL)
6600 		return (Z_INVAL);
6601 
6602 	if ((cur = handle->zone_dh_cur) == NULL)
6603 		return (Z_NO_ENTRY);
6604 
6605 	for (; cur != NULL; cur = cur->next)
6606 		if (!xmlStrcmp(cur->name, DTD_ELEM_DATASET))
6607 			break;
6608 	if (cur == NULL) {
6609 		handle->zone_dh_cur = handle->zone_dh_top;
6610 		return (Z_NO_ENTRY);
6611 	}
6612 
6613 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
6614 	    sizeof (tabptr->zone_dataset_name))) != Z_OK) {
6615 		handle->zone_dh_cur = handle->zone_dh_top;
6616 		return (err);
6617 	}
6618 
6619 	handle->zone_dh_cur = cur->next;
6620 	return (Z_OK);
6621 }
6622 
6623 int
6624 zonecfg_enddsent(zone_dochandle_t handle)
6625 {
6626 	return (zonecfg_endent(handle));
6627 }
6628 
6629 /*
6630  * Support for aliased rctls; that is, rctls that have simplified names in
6631  * zonecfg.  For example, max-lwps is an alias for a well defined zone.max-lwps
6632  * rctl.  If there are multiple existing values for one of these rctls or if
6633  * there is a single value that does not match the well defined template (i.e.
6634  * it has a different action) then we cannot treat the rctl as having an alias
6635  * so we return Z_ALIAS_DISALLOW.  That means that the rctl cannot be
6636  * managed in zonecfg via an alias and that the standard rctl syntax must be
6637  * used.
6638  *
6639  * The possible return values are:
6640  *	Z_NO_PROPERTY_ID - invalid alias name
6641  *	Z_ALIAS_DISALLOW - pre-existing, incompatible rctl definition
6642  *	Z_NO_ENTRY - no rctl is configured for this alias
6643  *	Z_OK - we got a valid rctl for the specified alias
6644  */
6645 int
6646 zonecfg_get_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t *rval)
6647 {
6648 	boolean_t found = B_FALSE;
6649 	boolean_t found_val = B_FALSE;
6650 	xmlNodePtr cur, val;
6651 	char savedname[MAXNAMELEN];
6652 	struct zone_rctlvaltab rctl;
6653 	int i;
6654 	int err;
6655 
6656 	for (i = 0; aliases[i].shortname != NULL; i++)
6657 		if (strcmp(name, aliases[i].shortname) == 0)
6658 			break;
6659 
6660 	if (aliases[i].shortname == NULL)
6661 		return (Z_NO_PROPERTY_ID);
6662 
6663 	if ((err = operation_prep(handle)) != Z_OK)
6664 		return (err);
6665 
6666 	cur = handle->zone_dh_cur;
6667 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6668 		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL) != 0)
6669 			continue;
6670 		if ((fetchprop(cur, DTD_ATTR_NAME, savedname,
6671 		    sizeof (savedname)) == Z_OK) &&
6672 		    (strcmp(savedname, aliases[i].realname) == 0)) {
6673 
6674 			/*
6675 			 * If we already saw one of these, we can't have an
6676 			 * alias since we just found another.
6677 			 */
6678 			if (found)
6679 				return (Z_ALIAS_DISALLOW);
6680 			found = B_TRUE;
6681 
6682 			for (val = cur->xmlChildrenNode; val != NULL;
6683 			    val = val->next) {
6684 				/*
6685 				 * If we already have one value, we can't have
6686 				 * an alias since we just found another.
6687 				 */
6688 				if (found_val)
6689 					return (Z_ALIAS_DISALLOW);
6690 				found_val = B_TRUE;
6691 
6692 				if ((fetchprop(val, DTD_ATTR_PRIV,
6693 				    rctl.zone_rctlval_priv,
6694 				    sizeof (rctl.zone_rctlval_priv)) != Z_OK))
6695 					break;
6696 				if ((fetchprop(val, DTD_ATTR_LIMIT,
6697 				    rctl.zone_rctlval_limit,
6698 				    sizeof (rctl.zone_rctlval_limit)) != Z_OK))
6699 					break;
6700 				if ((fetchprop(val, DTD_ATTR_ACTION,
6701 				    rctl.zone_rctlval_action,
6702 				    sizeof (rctl.zone_rctlval_action)) != Z_OK))
6703 					break;
6704 			}
6705 
6706 			/* check priv and action match the expected vals */
6707 			if (strcmp(rctl.zone_rctlval_priv,
6708 			    aliases[i].priv) != 0 ||
6709 			    strcmp(rctl.zone_rctlval_action,
6710 			    aliases[i].action) != 0)
6711 				return (Z_ALIAS_DISALLOW);
6712 		}
6713 	}
6714 
6715 	if (found) {
6716 		*rval = strtoull(rctl.zone_rctlval_limit, NULL, 10);
6717 		return (Z_OK);
6718 	}
6719 
6720 	return (Z_NO_ENTRY);
6721 }
6722 
6723 int
6724 zonecfg_rm_aliased_rctl(zone_dochandle_t handle, char *name)
6725 {
6726 	int i;
6727 	uint64_t val;
6728 	struct zone_rctltab rctltab;
6729 
6730 	/*
6731 	 * First check that we have a valid aliased rctl to remove.
6732 	 * This will catch an rctl entry with non-standard values or
6733 	 * multiple rctl values for this name.  We need to ignore those
6734 	 * rctl entries.
6735 	 */
6736 	if (zonecfg_get_aliased_rctl(handle, name, &val) != Z_OK)
6737 		return (Z_OK);
6738 
6739 	for (i = 0; aliases[i].shortname != NULL; i++)
6740 		if (strcmp(name, aliases[i].shortname) == 0)
6741 			break;
6742 
6743 	if (aliases[i].shortname == NULL)
6744 		return (Z_NO_RESOURCE_ID);
6745 
6746 	(void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname,
6747 	    sizeof (rctltab.zone_rctl_name));
6748 
6749 	return (zonecfg_delete_rctl(handle, &rctltab));
6750 }
6751 
6752 boolean_t
6753 zonecfg_aliased_rctl_ok(zone_dochandle_t handle, char *name)
6754 {
6755 	uint64_t tmp_val;
6756 
6757 	switch (zonecfg_get_aliased_rctl(handle, name, &tmp_val)) {
6758 	case Z_OK:
6759 		/*FALLTHRU*/
6760 	case Z_NO_ENTRY:
6761 		return (B_TRUE);
6762 	default:
6763 		return (B_FALSE);
6764 	}
6765 }
6766 
6767 int
6768 zonecfg_set_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t val)
6769 {
6770 	int i;
6771 	int err;
6772 	struct zone_rctltab rctltab;
6773 	struct zone_rctlvaltab *rctlvaltab;
6774 	char buf[128];
6775 
6776 	if (!zonecfg_aliased_rctl_ok(handle, name))
6777 		return (Z_ALIAS_DISALLOW);
6778 
6779 	for (i = 0; aliases[i].shortname != NULL; i++)
6780 		if (strcmp(name, aliases[i].shortname) == 0)
6781 			break;
6782 
6783 	if (aliases[i].shortname == NULL)
6784 		return (Z_NO_RESOURCE_ID);
6785 
6786 	/* remove any pre-existing definition for this rctl */
6787 	(void) zonecfg_rm_aliased_rctl(handle, name);
6788 
6789 	(void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname,
6790 	    sizeof (rctltab.zone_rctl_name));
6791 
6792 	rctltab.zone_rctl_valptr = NULL;
6793 
6794 	if ((rctlvaltab = calloc(1, sizeof (struct zone_rctlvaltab))) == NULL)
6795 		return (Z_NOMEM);
6796 
6797 	(void) snprintf(buf, sizeof (buf), "%llu", (long long)val);
6798 
6799 	(void) strlcpy(rctlvaltab->zone_rctlval_priv, aliases[i].priv,
6800 	    sizeof (rctlvaltab->zone_rctlval_priv));
6801 	(void) strlcpy(rctlvaltab->zone_rctlval_limit, buf,
6802 	    sizeof (rctlvaltab->zone_rctlval_limit));
6803 	(void) strlcpy(rctlvaltab->zone_rctlval_action, aliases[i].action,
6804 	    sizeof (rctlvaltab->zone_rctlval_action));
6805 
6806 	rctlvaltab->zone_rctlval_next = NULL;
6807 
6808 	if ((err = zonecfg_add_rctl_value(&rctltab, rctlvaltab)) != Z_OK)
6809 		return (err);
6810 
6811 	return (zonecfg_add_rctl(handle, &rctltab));
6812 }
6813 
6814 static int
6815 delete_tmp_pool(zone_dochandle_t handle)
6816 {
6817 	int err;
6818 	xmlNodePtr cur = handle->zone_dh_cur;
6819 
6820 	if ((err = operation_prep(handle)) != Z_OK)
6821 		return (err);
6822 
6823 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6824 		if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) {
6825 			xmlUnlinkNode(cur);
6826 			xmlFreeNode(cur);
6827 			return (Z_OK);
6828 		}
6829 	}
6830 
6831 	return (Z_NO_RESOURCE_ID);
6832 }
6833 
6834 static int
6835 modify_tmp_pool(zone_dochandle_t handle, char *pool_importance)
6836 {
6837 	int err;
6838 	xmlNodePtr cur = handle->zone_dh_cur;
6839 	xmlNodePtr newnode;
6840 
6841 	err = delete_tmp_pool(handle);
6842 	if (err != Z_OK && err != Z_NO_RESOURCE_ID)
6843 		return (err);
6844 
6845 	if (*pool_importance != '\0') {
6846 		if ((err = operation_prep(handle)) != Z_OK)
6847 			return (err);
6848 
6849 		newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_TMPPOOL, NULL);
6850 		if ((err = newprop(newnode, DTD_ATTR_IMPORTANCE,
6851 		    pool_importance)) != Z_OK)
6852 			return (err);
6853 	}
6854 
6855 	return (Z_OK);
6856 }
6857 
6858 static int
6859 add_pset_core(zone_dochandle_t handle, struct zone_psettab *tabptr)
6860 {
6861 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
6862 	int err;
6863 
6864 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PSET, NULL);
6865 	if ((err = newprop(newnode, DTD_ATTR_NCPU_MIN,
6866 	    tabptr->zone_ncpu_min)) != Z_OK)
6867 		return (err);
6868 	if ((err = newprop(newnode, DTD_ATTR_NCPU_MAX,
6869 	    tabptr->zone_ncpu_max)) != Z_OK)
6870 		return (err);
6871 
6872 	if ((err = modify_tmp_pool(handle, tabptr->zone_importance)) != Z_OK)
6873 		return (err);
6874 
6875 	return (Z_OK);
6876 }
6877 
6878 int
6879 zonecfg_add_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
6880 {
6881 	int err;
6882 
6883 	if (tabptr == NULL)
6884 		return (Z_INVAL);
6885 
6886 	if ((err = operation_prep(handle)) != Z_OK)
6887 		return (err);
6888 
6889 	if ((err = add_pset_core(handle, tabptr)) != Z_OK)
6890 		return (err);
6891 
6892 	return (Z_OK);
6893 }
6894 
6895 int
6896 zonecfg_delete_pset(zone_dochandle_t handle)
6897 {
6898 	int err;
6899 	int res = Z_NO_RESOURCE_ID;
6900 	xmlNodePtr cur = handle->zone_dh_cur;
6901 
6902 	if ((err = operation_prep(handle)) != Z_OK)
6903 		return (err);
6904 
6905 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6906 		if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) {
6907 			xmlUnlinkNode(cur);
6908 			xmlFreeNode(cur);
6909 			res = Z_OK;
6910 			break;
6911 		}
6912 	}
6913 
6914 	/*
6915 	 * Once we have msets, we should check that a mset
6916 	 * do not exist before we delete the tmp_pool data.
6917 	 */
6918 	err = delete_tmp_pool(handle);
6919 	if (err != Z_OK && err != Z_NO_RESOURCE_ID)
6920 		return (err);
6921 
6922 	return (res);
6923 }
6924 
6925 int
6926 zonecfg_modify_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
6927 {
6928 	int err;
6929 
6930 	if (tabptr == NULL)
6931 		return (Z_INVAL);
6932 
6933 	if ((err = zonecfg_delete_pset(handle)) != Z_OK)
6934 		return (err);
6935 
6936 	if ((err = add_pset_core(handle, tabptr)) != Z_OK)
6937 		return (err);
6938 
6939 	return (Z_OK);
6940 }
6941 
6942 int
6943 zonecfg_lookup_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
6944 {
6945 	xmlNodePtr cur;
6946 	int err;
6947 	int res = Z_NO_ENTRY;
6948 
6949 	if (tabptr == NULL)
6950 		return (Z_INVAL);
6951 
6952 	if ((err = operation_prep(handle)) != Z_OK)
6953 		return (err);
6954 
6955 	/* this is an optional component */
6956 	tabptr->zone_importance[0] = '\0';
6957 
6958 	cur = handle->zone_dh_cur;
6959 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6960 		if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) {
6961 			if ((err = fetchprop(cur, DTD_ATTR_NCPU_MIN,
6962 			    tabptr->zone_ncpu_min,
6963 			    sizeof (tabptr->zone_ncpu_min))) != Z_OK) {
6964 				handle->zone_dh_cur = handle->zone_dh_top;
6965 				return (err);
6966 			}
6967 
6968 			if ((err = fetchprop(cur, DTD_ATTR_NCPU_MAX,
6969 			    tabptr->zone_ncpu_max,
6970 			    sizeof (tabptr->zone_ncpu_max))) != Z_OK) {
6971 				handle->zone_dh_cur = handle->zone_dh_top;
6972 				return (err);
6973 			}
6974 
6975 			res = Z_OK;
6976 
6977 		} else if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) {
6978 			if ((err = fetchprop(cur, DTD_ATTR_IMPORTANCE,
6979 			    tabptr->zone_importance,
6980 			    sizeof (tabptr->zone_importance))) != Z_OK) {
6981 				handle->zone_dh_cur = handle->zone_dh_top;
6982 				return (err);
6983 			}
6984 		}
6985 	}
6986 
6987 	return (res);
6988 }
6989 
6990 int
6991 zonecfg_getpsetent(zone_dochandle_t handle, struct zone_psettab *tabptr)
6992 {
6993 	int err;
6994 
6995 	if ((err = zonecfg_setent(handle)) != Z_OK)
6996 		return (err);
6997 
6998 	err = zonecfg_lookup_pset(handle, tabptr);
6999 
7000 	(void) zonecfg_endent(handle);
7001 
7002 	return (err);
7003 }
7004 
7005 static int
7006 add_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
7007 {
7008 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
7009 	int err;
7010 
7011 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_MCAP, NULL);
7012 	if ((err = newprop(newnode, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap))
7013 	    != Z_OK)
7014 		return (err);
7015 
7016 	return (Z_OK);
7017 }
7018 
7019 int
7020 zonecfg_delete_mcap(zone_dochandle_t handle)
7021 {
7022 	int err;
7023 	xmlNodePtr cur = handle->zone_dh_cur;
7024 
7025 	if ((err = operation_prep(handle)) != Z_OK)
7026 		return (err);
7027 
7028 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
7029 		if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
7030 			continue;
7031 
7032 		xmlUnlinkNode(cur);
7033 		xmlFreeNode(cur);
7034 		return (Z_OK);
7035 	}
7036 	return (Z_NO_RESOURCE_ID);
7037 }
7038 
7039 int
7040 zonecfg_modify_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
7041 {
7042 	int err;
7043 
7044 	if (tabptr == NULL)
7045 		return (Z_INVAL);
7046 
7047 	err = zonecfg_delete_mcap(handle);
7048 	/* it is ok if there is no mcap entry */
7049 	if (err != Z_OK && err != Z_NO_RESOURCE_ID)
7050 		return (err);
7051 
7052 	if ((err = add_mcap(handle, tabptr)) != Z_OK)
7053 		return (err);
7054 
7055 	return (Z_OK);
7056 }
7057 
7058 int
7059 zonecfg_lookup_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
7060 {
7061 	xmlNodePtr cur;
7062 	int err;
7063 
7064 	if (tabptr == NULL)
7065 		return (Z_INVAL);
7066 
7067 	if ((err = operation_prep(handle)) != Z_OK)
7068 		return (err);
7069 
7070 	cur = handle->zone_dh_cur;
7071 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
7072 		if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
7073 			continue;
7074 		if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP,
7075 		    tabptr->zone_physmem_cap,
7076 		    sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
7077 			handle->zone_dh_cur = handle->zone_dh_top;
7078 			return (err);
7079 		}
7080 
7081 		return (Z_OK);
7082 	}
7083 
7084 	return (Z_NO_ENTRY);
7085 }
7086 
7087 int
7088 zonecfg_getsecflagsent(zone_dochandle_t handle,
7089     struct zone_secflagstab *tabptr)
7090 {
7091 	int err;
7092 	xmlNodePtr cur;
7093 
7094 	if (handle == NULL)
7095 		return (Z_INVAL);
7096 
7097 	if ((err = zonecfg_setent(handle)) != Z_OK)
7098 		return (err);
7099 
7100 
7101 	if ((cur = handle->zone_dh_cur) == NULL)
7102 		return (Z_NO_ENTRY);
7103 
7104 	for (; cur != NULL; cur = cur->next) {
7105 		if (xmlStrcmp(cur->name, DTD_ELEM_SECFLAGS) == 0)
7106 			break;
7107 	}
7108 
7109 	if (cur == NULL) {
7110 		handle->zone_dh_cur = handle->zone_dh_top;
7111 		return (Z_NO_ENTRY);
7112 	}
7113 
7114 	if ((err = fetchprop(cur, DTD_ATTR_DEFAULT,
7115 	    tabptr->zone_secflags_default,
7116 	    sizeof (tabptr->zone_secflags_default))) != Z_OK) {
7117 		handle->zone_dh_cur = handle->zone_dh_top;
7118 		return (err);
7119 	}
7120 
7121 	if ((err = fetchprop(cur, DTD_ATTR_LOWER,
7122 	    tabptr->zone_secflags_lower,
7123 	    sizeof (tabptr->zone_secflags_lower))) != Z_OK) {
7124 		handle->zone_dh_cur = handle->zone_dh_top;
7125 		return (err);
7126 	}
7127 
7128 	if ((err = fetchprop(cur, DTD_ATTR_UPPER,
7129 	    tabptr->zone_secflags_upper,
7130 	    sizeof (tabptr->zone_secflags_upper))) != Z_OK) {
7131 		handle->zone_dh_cur = handle->zone_dh_top;
7132 		return (err);
7133 	}
7134 
7135 	handle->zone_dh_cur = cur->next;
7136 
7137 	(void) zonecfg_endent(handle);
7138 
7139 	return (err);
7140 }
7141 
7142 static int
7143 getmcapent_core(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
7144 {
7145 	xmlNodePtr cur;
7146 	int err;
7147 
7148 	if (handle == NULL)
7149 		return (Z_INVAL);
7150 
7151 	if ((cur = handle->zone_dh_cur) == NULL)
7152 		return (Z_NO_ENTRY);
7153 
7154 	for (; cur != NULL; cur = cur->next)
7155 		if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) == 0)
7156 			break;
7157 	if (cur == NULL) {
7158 		handle->zone_dh_cur = handle->zone_dh_top;
7159 		return (Z_NO_ENTRY);
7160 	}
7161 
7162 	if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap,
7163 	    sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
7164 		handle->zone_dh_cur = handle->zone_dh_top;
7165 		return (err);
7166 	}
7167 
7168 	handle->zone_dh_cur = cur->next;
7169 	return (Z_OK);
7170 }
7171 
7172 int
7173 zonecfg_getmcapent(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
7174 {
7175 	int err;
7176 
7177 	if ((err = zonecfg_setent(handle)) != Z_OK)
7178 		return (err);
7179 
7180 	err = getmcapent_core(handle, tabptr);
7181 
7182 	(void) zonecfg_endent(handle);
7183 
7184 	return (err);
7185 }
7186 
7187 /*
7188  * Get the full tree of pkg metadata in a set of nested AVL trees.
7189  * pkgs_avl is an AVL tree of pkgs.
7190  *
7191  * The zone xml data contains DTD_ELEM_PACKAGE elements.
7192  */
7193 int
7194 zonecfg_getpkgdata(zone_dochandle_t handle, uu_avl_pool_t *pkg_pool,
7195     uu_avl_t *pkgs_avl)
7196 {
7197 	xmlNodePtr cur;
7198 	int res;
7199 	zone_pkg_entry_t *pkg;
7200 	char name[MAXNAMELEN];
7201 	char version[ZONE_PKG_VERSMAX];
7202 
7203 	if (handle == NULL)
7204 		return (Z_INVAL);
7205 
7206 	if ((res = zonecfg_setent(handle)) != Z_OK)
7207 		return (res);
7208 
7209 	if ((cur = handle->zone_dh_cur) == NULL) {
7210 		res = Z_NO_ENTRY;
7211 		goto done;
7212 	}
7213 
7214 	for (; cur != NULL; cur = cur->next) {
7215 		if (xmlStrcmp(cur->name, DTD_ELEM_PACKAGE) == 0) {
7216 			uu_avl_index_t where;
7217 
7218 			if ((res = fetchprop(cur, DTD_ATTR_NAME, name,
7219 			    sizeof (name))) != Z_OK)
7220 				goto done;
7221 
7222 			if ((res = fetchprop(cur, DTD_ATTR_VERSION, version,
7223 			    sizeof (version))) != Z_OK)
7224 				goto done;
7225 
7226 			if ((pkg = (zone_pkg_entry_t *)
7227 			    malloc(sizeof (zone_pkg_entry_t))) == NULL) {
7228 				res = Z_NOMEM;
7229 				goto done;
7230 			}
7231 
7232 			if ((pkg->zpe_name = strdup(name)) == NULL) {
7233 				free(pkg);
7234 				res = Z_NOMEM;
7235 				goto done;
7236 			}
7237 
7238 			if ((pkg->zpe_vers = strdup(version)) == NULL) {
7239 				free(pkg->zpe_name);
7240 				free(pkg);
7241 				res = Z_NOMEM;
7242 				goto done;
7243 			}
7244 
7245 			uu_avl_node_init(pkg, &pkg->zpe_entry, pkg_pool);
7246 			if (uu_avl_find(pkgs_avl, pkg, NULL, &where) != NULL) {
7247 				free(pkg->zpe_name);
7248 				free(pkg->zpe_vers);
7249 				free(pkg);
7250 			} else {
7251 				uu_avl_insert(pkgs_avl, pkg, where);
7252 			}
7253 		}
7254 	}
7255 
7256 done:
7257 	(void) zonecfg_endent(handle);
7258 	return (res);
7259 }
7260 
7261 int
7262 zonecfg_setdevperment(zone_dochandle_t handle)
7263 {
7264 	return (zonecfg_setent(handle));
7265 }
7266 
7267 int
7268 zonecfg_getdevperment(zone_dochandle_t handle, struct zone_devpermtab *tabptr)
7269 {
7270 	xmlNodePtr cur;
7271 	int err;
7272 	char buf[128];
7273 
7274 	tabptr->zone_devperm_acl = NULL;
7275 
7276 	if (handle == NULL)
7277 		return (Z_INVAL);
7278 
7279 	if ((cur = handle->zone_dh_cur) == NULL)
7280 		return (Z_NO_ENTRY);
7281 
7282 	for (; cur != NULL; cur = cur->next)
7283 		if (!xmlStrcmp(cur->name, DTD_ELEM_DEV_PERM))
7284 			break;
7285 	if (cur == NULL) {
7286 		handle->zone_dh_cur = handle->zone_dh_top;
7287 		return (Z_NO_ENTRY);
7288 	}
7289 
7290 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_devperm_name,
7291 	    sizeof (tabptr->zone_devperm_name))) != Z_OK) {
7292 		handle->zone_dh_cur = handle->zone_dh_top;
7293 		return (err);
7294 	}
7295 
7296 	if ((err = fetchprop(cur, DTD_ATTR_UID, buf, sizeof (buf))) != Z_OK) {
7297 		handle->zone_dh_cur = handle->zone_dh_top;
7298 		return (err);
7299 	}
7300 	tabptr->zone_devperm_uid = (uid_t)atol(buf);
7301 
7302 	if ((err = fetchprop(cur, DTD_ATTR_GID, buf, sizeof (buf))) != Z_OK) {
7303 		handle->zone_dh_cur = handle->zone_dh_top;
7304 		return (err);
7305 	}
7306 	tabptr->zone_devperm_gid = (gid_t)atol(buf);
7307 
7308 	if ((err = fetchprop(cur, DTD_ATTR_MODE, buf, sizeof (buf))) != Z_OK) {
7309 		handle->zone_dh_cur = handle->zone_dh_top;
7310 		return (err);
7311 	}
7312 	tabptr->zone_devperm_mode = (mode_t)strtol(buf, (char **)NULL, 8);
7313 
7314 	if ((err = fetch_alloc_prop(cur, DTD_ATTR_ACL,
7315 	    &(tabptr->zone_devperm_acl))) != Z_OK) {
7316 		handle->zone_dh_cur = handle->zone_dh_top;
7317 		return (err);
7318 	}
7319 
7320 	handle->zone_dh_cur = cur->next;
7321 	return (Z_OK);
7322 }
7323 
7324 int
7325 zonecfg_enddevperment(zone_dochandle_t handle)
7326 {
7327 	return (zonecfg_endent(handle));
7328 }
7329 
7330 /* PRINTFLIKE1 */
7331 static void
7332 zerror(const char *zone_name, const char *fmt, ...)
7333 {
7334 	va_list alist;
7335 
7336 	va_start(alist, fmt);
7337 	(void) fprintf(stderr, "zone '%s': ", zone_name);
7338 	(void) vfprintf(stderr, fmt, alist);
7339 	(void) fprintf(stderr, "\n");
7340 	va_end(alist);
7341 }
7342 
7343 static void
7344 zperror(const char *str)
7345 {
7346 	(void) fprintf(stderr, "%s: %s\n", str, strerror(errno));
7347 }
7348 
7349 /*
7350  * The following three routines implement a simple locking mechanism to
7351  * ensure that only one instance of zoneadm at a time is able to manipulate
7352  * a given zone.  The lock is built on top of an fcntl(2) lock of
7353  * [<altroot>]/var/run/zones/<zonename>.zoneadm.lock.  If a zoneadm instance
7354  * can grab that lock, it is allowed to manipulate the zone.
7355  *
7356  * Since zoneadm may call external applications which in turn invoke
7357  * zoneadm again, we introduce the notion of "lock inheritance".  Any
7358  * instance of zoneadm that has another instance in its ancestry is assumed
7359  * to be acting on behalf of the original zoneadm, and is thus allowed to
7360  * manipulate its zone.
7361  *
7362  * This inheritance is implemented via the _ZONEADM_LOCK_HELD environment
7363  * variable.  When zoneadm is granted a lock on its zone, this environment
7364  * variable is set to 1.  When it releases the lock, the variable is set to
7365  * 0.  Since a child process inherits its parent's environment, checking
7366  * the state of this variable indicates whether or not any ancestor owns
7367  * the lock.
7368  */
7369 void
7370 zonecfg_init_lock_file(const char *zone_name, char **lock_env)
7371 {
7372 	*lock_env = getenv(LOCK_ENV_VAR);
7373 	if (*lock_env == NULL) {
7374 		if (putenv(zoneadm_lock_not_held) != 0) {
7375 			zerror(zone_name, gettext("could not set env: %s"),
7376 			    strerror(errno));
7377 			exit(1);
7378 		}
7379 	} else {
7380 		if (atoi(*lock_env) == 1)
7381 			zone_lock_cnt = 1;
7382 	}
7383 }
7384 
7385 void
7386 zonecfg_release_lock_file(const char *zone_name, int lockfd)
7387 {
7388 	/*
7389 	 * If we are cleaning up from a failed attempt to lock the zone for
7390 	 * the first time, we might have a zone_lock_cnt of 0.  In that
7391 	 * error case, we don't want to do anything but close the lock
7392 	 * file.
7393 	 */
7394 	assert(zone_lock_cnt >= 0);
7395 	if (zone_lock_cnt > 0) {
7396 		assert(getenv(LOCK_ENV_VAR) != NULL);
7397 		assert(atoi(getenv(LOCK_ENV_VAR)) == 1);
7398 		if (--zone_lock_cnt > 0) {
7399 			assert(lockfd == -1);
7400 			return;
7401 		}
7402 		if (putenv(zoneadm_lock_not_held) != 0) {
7403 			zerror(zone_name, gettext("could not set env: %s"),
7404 			    strerror(errno));
7405 			exit(1);
7406 		}
7407 	}
7408 	assert(lockfd >= 0);
7409 	(void) close(lockfd);
7410 }
7411 
7412 int
7413 zonecfg_grab_lock_file(const char *zone_name, int *lockfd)
7414 {
7415 	char pathbuf[PATH_MAX];
7416 	struct flock flock;
7417 
7418 	/*
7419 	 * If we already have the lock, we can skip this expensive song
7420 	 * and dance.
7421 	 */
7422 	assert(zone_lock_cnt >= 0);
7423 	assert(getenv(LOCK_ENV_VAR) != NULL);
7424 	if (zone_lock_cnt > 0) {
7425 		assert(atoi(getenv(LOCK_ENV_VAR)) == 1);
7426 		zone_lock_cnt++;
7427 		*lockfd = -1;
7428 		return (Z_OK);
7429 	}
7430 	assert(getenv(LOCK_ENV_VAR) != NULL);
7431 	assert(atoi(getenv(LOCK_ENV_VAR)) == 0);
7432 
7433 	if (snprintf(pathbuf, sizeof (pathbuf), "%s%s", zonecfg_get_root(),
7434 	    ZONES_TMPDIR) >= sizeof (pathbuf)) {
7435 		zerror(zone_name, gettext("alternate root path is too long"));
7436 		return (-1);
7437 	}
7438 	if (mkdir(pathbuf, S_IRWXU) < 0 && errno != EEXIST) {
7439 		zerror(zone_name, gettext("could not mkdir %s: %s"), pathbuf,
7440 		    strerror(errno));
7441 		return (-1);
7442 	}
7443 	(void) chmod(pathbuf, S_IRWXU);
7444 
7445 	/*
7446 	 * One of these lock files is created for each zone (when needed).
7447 	 * The lock files are not cleaned up (except on system reboot),
7448 	 * but since there is only one per zone, there is no resource
7449 	 * starvation issue.
7450 	 */
7451 	if (snprintf(pathbuf, sizeof (pathbuf), "%s%s/%s.zoneadm.lock",
7452 	    zonecfg_get_root(), ZONES_TMPDIR, zone_name) >= sizeof (pathbuf)) {
7453 		zerror(zone_name, gettext("alternate root path is too long"));
7454 		return (-1);
7455 	}
7456 	if ((*lockfd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
7457 		zerror(zone_name, gettext("could not open %s: %s"), pathbuf,
7458 		    strerror(errno));
7459 		return (-1);
7460 	}
7461 	/*
7462 	 * Lock the file to synchronize with other zoneadmds
7463 	 */
7464 	flock.l_type = F_WRLCK;
7465 	flock.l_whence = SEEK_SET;
7466 	flock.l_start = (off_t)0;
7467 	flock.l_len = (off_t)0;
7468 	if ((fcntl(*lockfd, F_SETLKW, &flock) < 0) ||
7469 	    (putenv(zoneadm_lock_held) != 0)) {
7470 		zerror(zone_name, gettext("unable to lock %s: %s"), pathbuf,
7471 		    strerror(errno));
7472 		zonecfg_release_lock_file(zone_name, *lockfd);
7473 		return (-1);
7474 	}
7475 	zone_lock_cnt = 1;
7476 	return (Z_OK);
7477 }
7478 
7479 boolean_t
7480 zonecfg_lock_file_held(int *lockfd)
7481 {
7482 	if (*lockfd >= 0 || zone_lock_cnt > 0)
7483 		return (B_TRUE);
7484 	return (B_FALSE);
7485 }
7486 
7487 static boolean_t
7488 get_doorname(const char *zone_name, char *buffer)
7489 {
7490 	return (snprintf(buffer, PATH_MAX, "%s" ZONE_DOOR_PATH,
7491 	    zonecfg_get_root(), zone_name) < PATH_MAX);
7492 }
7493 
7494 /*
7495  * system daemons are not audited.  For the global zone, this occurs
7496  * "naturally" since init is started with the default audit
7497  * characteristics.  Since zoneadmd is a system daemon and it starts
7498  * init for a zone, it is necessary to clear out the audit
7499  * characteristics inherited from whomever started zoneadmd.  This is
7500  * indicated by the audit id, which is set from the ruid parameter of
7501  * adt_set_user(), below.
7502  */
7503 
7504 static void
7505 prepare_audit_context(const char *zone_name)
7506 {
7507 	adt_session_data_t	*ah;
7508 	char			*failure = gettext("audit failure: %s");
7509 
7510 	if (adt_start_session(&ah, NULL, 0)) {
7511 		zerror(zone_name, failure, strerror(errno));
7512 		return;
7513 	}
7514 	if (adt_set_user(ah, ADT_NO_AUDIT, ADT_NO_AUDIT,
7515 	    ADT_NO_AUDIT, ADT_NO_AUDIT, NULL, ADT_NEW)) {
7516 		zerror(zone_name, failure, strerror(errno));
7517 		(void) adt_end_session(ah);
7518 		return;
7519 	}
7520 	if (adt_set_proc(ah))
7521 		zerror(zone_name, failure, strerror(errno));
7522 
7523 	(void) adt_end_session(ah);
7524 }
7525 
7526 static const char **
7527 get_zoneadmd_envp(void)
7528 {
7529 	const char **envp = NULL;
7530 	size_t envlen;
7531 	size_t envslot = 0;
7532 	const char *tok;
7533 	void *dstate = NULL;
7534 
7535 	/*
7536 	 * This initial array size is enough to hold the two variables
7537 	 * set below, up to five additional entries from /etc/default/init,
7538 	 * and the NULL terminator. /etc/default/init commonly includes only
7539 	 * TZ, LANG and LC_ALL. The array will be grown if necessary by
7540 	 * doubling the size whenever it is full.
7541 	 */
7542 	envlen = 8;
7543 
7544 	if ((envp = recallocarray(NULL, 0, envlen, sizeof (char *))) == NULL)
7545 		return (NULL);
7546 
7547 	/*
7548 	 * See the comment above zonecfg_init_lock_file() for details on the
7549 	 * implementation of the locking mechanism.
7550 	 * zoneadmd is started with an inherited lock, indicated by the
7551 	 * environment variable being set. Once the starting zoneadm exits,
7552 	 * zoneadmd may persist and will continue to believe that it has the
7553 	 * lock. This is okay as long as the only things that connect to the
7554 	 * zoneadmd door and cause it to do work that requires a lock have
7555 	 * grabbed the lock in advance, which zoneadm does in all cases today.
7556 	 */
7557 	envp[envslot++] = zoneadm_lock_held;
7558 
7559 	if (asprintf((char **)&tok, "PATH=%s", ZONEADMD_PATH) == -1) {
7560 		free(envp);
7561 		return (NULL);
7562 	}
7563 	envp[envslot++] = tok;
7564 
7565 	if (definit_open(DEFINIT_DEFAULT_FILE, &dstate) != 0) {
7566 		if (errno == ENOENT) {
7567 			/*
7568 			 * If the configuration file does not exist, return the
7569 			 * environment populated so far (with PATH and the
7570 			 * zoneadm lock).
7571 			 */
7572 			envp[envslot] = NULL;
7573 			return (envp);
7574 		}
7575 		goto err;
7576 	}
7577 
7578 	while ((tok = definit_token(dstate)) != NULL) {
7579 
7580 		if (strncmp(tok, "CMASK=", 6) == 0) {
7581 			long t;
7582 
7583 			t = strtol(tok + 6, NULL, 8);
7584 
7585 			if (t >= DEFINIT_MIN_UMASK && t <= DEFINIT_MAX_UMASK)
7586 				(void) umask((int)t);
7587 			continue;
7588 		}
7589 
7590 		/*
7591 		 * Always ensure there is space for a terminating
7592 		 * NULL in addition to the new entry being added.
7593 		 */
7594 		if (envslot + 2 >= envlen) {
7595 			const char **newenvp;
7596 
7597 			newenvp = recallocarray(envp, envlen, envlen * 2,
7598 			    sizeof (char *));
7599 			if (newenvp == NULL)
7600 				goto err;
7601 			envp = newenvp;
7602 			envlen *= 2;
7603 		}
7604 
7605 		envp[envslot] = strdup(tok);
7606 		if (envp[envslot] == NULL)
7607 			goto err;
7608 		envslot++;
7609 	}
7610 
7611 	definit_close(dstate);
7612 	envp[envslot] = NULL;
7613 	return (envp);
7614 
7615 err:
7616 	if (dstate != NULL)
7617 		definit_close(dstate);
7618 
7619 	/*
7620 	 * The first slot in envp is 'zoneadm_lock_held' and should not be
7621 	 * freed.
7622 	 */
7623 	while (--envslot > 0)
7624 		free((void *)envp[envslot]);
7625 	free(envp);
7626 
7627 	return (NULL);
7628 }
7629 
7630 static int
7631 start_zoneadmd(const char *zone_name, boolean_t lock)
7632 {
7633 	char doorpath[PATH_MAX];
7634 	pid_t child_pid;
7635 	int error = -1;
7636 	int doorfd, lockfd;
7637 	struct door_info info;
7638 
7639 	if (!get_doorname(zone_name, doorpath))
7640 		return (-1);
7641 
7642 	if (lock)
7643 		if (zonecfg_grab_lock_file(zone_name, &lockfd) != Z_OK)
7644 			return (-1);
7645 
7646 	/*
7647 	 * Now that we have the lock, re-confirm that the daemon is
7648 	 * *not* up and working fine.  If it is still down, we have a green
7649 	 * light to start it.
7650 	 */
7651 	if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
7652 		if (errno != ENOENT) {
7653 			zperror(doorpath);
7654 			goto out;
7655 		}
7656 	} else {
7657 		if (door_info(doorfd, &info) == 0 &&
7658 		    ((info.di_attributes & DOOR_REVOKED) == 0)) {
7659 			error = Z_OK;
7660 			(void) close(doorfd);
7661 			goto out;
7662 		}
7663 		(void) close(doorfd);
7664 	}
7665 
7666 	if ((child_pid = fork()) == -1) {
7667 		zperror(gettext("could not fork"));
7668 		goto out;
7669 	}
7670 
7671 	if (child_pid == 0) {
7672 		const char *argv[6], **ap;
7673 		const char **envp;
7674 
7675 		/* child process */
7676 		prepare_audit_context(zone_name);
7677 
7678 		ap = argv;
7679 		*ap++ = "zoneadmd";
7680 		*ap++ = "-z";
7681 		*ap++ = zone_name;
7682 		if (zonecfg_in_alt_root()) {
7683 			*ap++ = "-R";
7684 			*ap++ = zonecfg_get_root();
7685 		}
7686 		*ap = NULL;
7687 
7688 		envp = get_zoneadmd_envp();
7689 		if (envp == NULL) {
7690 			zperror(gettext(
7691 			    "could not build environment for zoneadmd"));
7692 			_exit(1);
7693 		}
7694 
7695 		(void) execve("/usr/lib/zones/zoneadmd",
7696 		    (char * const *)argv, (char * const *)envp);
7697 		/*
7698 		 * TRANSLATION_NOTE
7699 		 * zoneadmd is a literal that should not be translated.
7700 		 */
7701 		zperror(gettext("could not exec zoneadmd"));
7702 		_exit(1);
7703 	} else {
7704 		/* parent process */
7705 		pid_t retval;
7706 		int pstatus = 0;
7707 
7708 		do {
7709 			retval = waitpid(child_pid, &pstatus, 0);
7710 		} while (retval != child_pid);
7711 		if (WIFSIGNALED(pstatus) || (WIFEXITED(pstatus) &&
7712 		    WEXITSTATUS(pstatus) != 0)) {
7713 			zerror(zone_name, gettext("could not start %s"),
7714 			    "zoneadmd");
7715 			goto out;
7716 		}
7717 	}
7718 	error = Z_OK;
7719 out:
7720 	if (lock)
7721 		zonecfg_release_lock_file(zone_name, lockfd);
7722 	return (error);
7723 }
7724 
7725 int
7726 zonecfg_ping_zoneadmd(const char *zone_name)
7727 {
7728 	char doorpath[PATH_MAX];
7729 	int doorfd;
7730 	struct door_info info;
7731 
7732 	if (!get_doorname(zone_name, doorpath))
7733 		return (-1);
7734 
7735 	if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
7736 		return (-1);
7737 	}
7738 	if (door_info(doorfd, &info) == 0 &&
7739 	    ((info.di_attributes & DOOR_REVOKED) == 0)) {
7740 		(void) close(doorfd);
7741 		return (Z_OK);
7742 	}
7743 	(void) close(doorfd);
7744 	return (-1);
7745 }
7746 
7747 int
7748 zonecfg_call_zoneadmd(const char *zone_name, zone_cmd_arg_t *arg, char *locale,
7749     boolean_t lock)
7750 {
7751 	char doorpath[PATH_MAX];
7752 	int doorfd, result;
7753 	door_arg_t darg;
7754 
7755 	zoneid_t zoneid;
7756 	uint64_t uniqid = 0;
7757 
7758 	zone_cmd_rval_t *rvalp;
7759 	size_t rlen;
7760 	char *cp, *errbuf;
7761 
7762 	rlen = getpagesize();
7763 	if ((rvalp = malloc(rlen)) == NULL) {
7764 		zerror(zone_name, gettext("failed to allocate %lu bytes: %s"),
7765 		    rlen, strerror(errno));
7766 		return (-1);
7767 	}
7768 
7769 	if ((zoneid = getzoneidbyname(zone_name)) != ZONE_ID_UNDEFINED) {
7770 		(void) zone_getattr(zoneid, ZONE_ATTR_UNIQID, &uniqid,
7771 		    sizeof (uniqid));
7772 	}
7773 	arg->uniqid = uniqid;
7774 	(void) strlcpy(arg->locale, locale, sizeof (arg->locale));
7775 	if (!get_doorname(zone_name, doorpath)) {
7776 		zerror(zone_name, gettext("alternate root path is too long"));
7777 		free(rvalp);
7778 		return (-1);
7779 	}
7780 
7781 	/*
7782 	 * Loop trying to start zoneadmd; if something goes seriously
7783 	 * wrong we break out and fail.
7784 	 */
7785 	for (;;) {
7786 		if (start_zoneadmd(zone_name, lock) != Z_OK)
7787 			break;
7788 
7789 		if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
7790 			zperror(gettext("failed to open zone door"));
7791 			break;
7792 		}
7793 
7794 		darg.data_ptr = (char *)arg;
7795 		darg.data_size = sizeof (*arg);
7796 		darg.desc_ptr = NULL;
7797 		darg.desc_num = 0;
7798 		darg.rbuf = (char *)rvalp;
7799 		darg.rsize = rlen;
7800 		if (door_call(doorfd, &darg) != 0) {
7801 			(void) close(doorfd);
7802 			/*
7803 			 * We'll get EBADF if the door has been revoked.
7804 			 */
7805 			if (errno != EBADF) {
7806 				zperror(gettext("door_call failed"));
7807 				break;
7808 			}
7809 			continue;	/* take another lap */
7810 		}
7811 		(void) close(doorfd);
7812 
7813 		if (darg.data_size == 0) {
7814 			/* Door server is going away; kick it again. */
7815 			continue;
7816 		}
7817 
7818 		errbuf = rvalp->errbuf;
7819 		while (*errbuf != '\0') {
7820 			/*
7821 			 * Remove any newlines since zerror()
7822 			 * will append one automatically.
7823 			 */
7824 			cp = strchr(errbuf, '\n');
7825 			if (cp != NULL)
7826 				*cp = '\0';
7827 			zerror(zone_name, "%s", errbuf);
7828 			if (cp == NULL)
7829 				break;
7830 			errbuf = cp + 1;
7831 		}
7832 		result = rvalp->rval == 0 ? 0 : -1;
7833 		free(rvalp);
7834 		return (result);
7835 	}
7836 
7837 	free(rvalp);
7838 	return (-1);
7839 }
7840 
7841 boolean_t
7842 zonecfg_valid_auths(const char *auths, const char *zonename)
7843 {
7844 	char *right;
7845 	char *tmpauths;
7846 	char *lasts;
7847 	char authname[MAXAUTHS];
7848 	boolean_t status = B_TRUE;
7849 
7850 	tmpauths = strdup(auths);
7851 	if (tmpauths == NULL) {
7852 		zerror(zonename, gettext("Out of memory"));
7853 		return (B_FALSE);
7854 	}
7855 	right = strtok_r(tmpauths, ",", &lasts);
7856 	while (right != NULL) {
7857 		(void) snprintf(authname, MAXAUTHS, "%s%s",
7858 		    ZONE_AUTH_PREFIX, right);
7859 		if (getauthnam(authname) == NULL) {
7860 			status = B_FALSE;
7861 			zerror(zonename,
7862 			    gettext("'%s' is not a valid authorization"),
7863 			    right);
7864 		}
7865 		right = strtok_r(NULL, ",", &lasts);
7866 	}
7867 	free(tmpauths);
7868 	return (status);
7869 }
7870 
7871 int
7872 zonecfg_delete_admins(zone_dochandle_t handle, char *zonename)
7873 {
7874 	int err;
7875 	struct zone_admintab admintab;
7876 	boolean_t changed = B_FALSE;
7877 
7878 	if ((err = zonecfg_setadminent(handle)) != Z_OK) {
7879 		return (err);
7880 	}
7881 	while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
7882 		err = zonecfg_delete_admin(handle, &admintab,
7883 		    zonename);
7884 		if (err != Z_OK) {
7885 			(void) zonecfg_endadminent(handle);
7886 			return (err);
7887 		} else {
7888 			changed = B_TRUE;
7889 		}
7890 		if ((err = zonecfg_setadminent(handle)) != Z_OK) {
7891 			return (err);
7892 		}
7893 	}
7894 	(void) zonecfg_endadminent(handle);
7895 	return (changed? Z_OK:Z_NO_ENTRY);
7896 }
7897 
7898 /*
7899  * Checks if a long authorization applies to this zone.
7900  * If so, it returns true, after destructively stripping
7901  * the authorization of its prefix and zone suffix.
7902  */
7903 static boolean_t
7904 is_zone_auth(char **auth, char *zonename, char *oldzonename)
7905 {
7906 	char *suffix;
7907 	size_t offset;
7908 
7909 	offset = strlen(ZONE_AUTH_PREFIX);
7910 	if ((strncmp(*auth, ZONE_AUTH_PREFIX, offset) == 0) &&
7911 	    ((suffix = strchr(*auth, '/')) != NULL)) {
7912 		if (strcmp(suffix + 1, zonename) == 0) {
7913 			*auth += offset;
7914 			suffix[0] = '\0';
7915 			return (B_TRUE);
7916 		} else if ((oldzonename != NULL) &&
7917 		    (strcmp(suffix + 1, oldzonename) == 0)) {
7918 			*auth += offset;
7919 			suffix[0] = '\0';
7920 			return (B_TRUE);
7921 		}
7922 	}
7923 	return (B_FALSE);
7924 }
7925 
7926 /*
7927  * This function determines whether the zone-specific authorization
7928  * assignments in /etc/user_attr have been changed more recently
7929  * than the equivalent data stored in the zone's configuration file.
7930  * This should only happen if the zone-specific authorizations in
7931  * the user_attr file were modified using a tool other than zonecfg.
7932  * If the configuration file is out-of-date with respect to these
7933  * authorization assignments, it is updated to match those specified
7934  * in /etc/user_attr.
7935  */
7936 
7937 int
7938 zonecfg_update_userauths(zone_dochandle_t handle, char *zonename)
7939 {
7940 	userattr_t *ua_ptr;
7941 	char *authlist;
7942 	char *lasts;
7943 	FILE  *uaf;
7944 	struct zone_admintab admintab;
7945 	struct stat config_st, ua_st;
7946 	char config_file[MAXPATHLEN];
7947 	boolean_t changed = B_FALSE;
7948 	int err;
7949 
7950 	if ((uaf = fopen(USERATTR_FILENAME, "r")) == NULL) {
7951 		zerror(zonename, gettext("could not open file %s: %s"),
7952 		    USERATTR_FILENAME, strerror(errno));
7953 		if (errno == EACCES)
7954 			return (Z_ACCES);
7955 		if (errno == ENOENT)
7956 			return (Z_NO_ZONE);
7957 		return (Z_MISC_FS);
7958 	}
7959 	if ((err = fstat(fileno(uaf), &ua_st)) != 0) {
7960 		zerror(zonename, gettext("could not stat file %s: %s"),
7961 		    USERATTR_FILENAME, strerror(errno));
7962 		(void) fclose(uaf);
7963 		return (Z_MISC_FS);
7964 	}
7965 	if (!config_file_path(zonename, config_file)) {
7966 		(void) fclose(uaf);
7967 		return (Z_MISC_FS);
7968 	}
7969 
7970 	if ((err = stat(config_file, &config_st)) != 0) {
7971 		zerror(zonename, gettext("could not stat file %s: %s"),
7972 		    config_file, strerror(errno));
7973 		(void) fclose(uaf);
7974 		return (Z_MISC_FS);
7975 	}
7976 	if (config_st.st_mtime >= ua_st.st_mtime) {
7977 		(void) fclose(uaf);
7978 		return (Z_NO_ENTRY);
7979 	}
7980 	if ((err = zonecfg_delete_admins(handle, zonename)) == Z_OK) {
7981 		changed = B_TRUE;
7982 	} else if (err != Z_NO_ENTRY) {
7983 		(void) fclose(uaf);
7984 		return (err);
7985 	}
7986 	while ((ua_ptr = fgetuserattr(uaf)) != NULL) {
7987 		if (ua_ptr->name[0] == '#') {
7988 			continue;
7989 		}
7990 		authlist = kva_match(ua_ptr->attr, USERATTR_AUTHS_KW);
7991 		if (authlist != NULL) {
7992 			char *cur_auth;
7993 			boolean_t first;
7994 
7995 			first = B_TRUE;
7996 			bzero(&admintab.zone_admin_auths, MAXAUTHS);
7997 			cur_auth = strtok_r(authlist, ",", &lasts);
7998 			while (cur_auth != NULL) {
7999 				if (is_zone_auth(&cur_auth, zonename,
8000 				    NULL)) {
8001 					/*
8002 					 * Add auths for this zone
8003 					 */
8004 					if (first) {
8005 						first = B_FALSE;
8006 					} else {
8007 						(void) strlcat(
8008 						    admintab.zone_admin_auths,
8009 						    ",", MAXAUTHS);
8010 					}
8011 					(void) strlcat(
8012 					    admintab.zone_admin_auths,
8013 					    cur_auth, MAXAUTHS);
8014 				}
8015 				cur_auth = strtok_r(NULL, ",", &lasts);
8016 			}
8017 			if (!first) {
8018 				/*
8019 				 * Add this right to config file
8020 				 */
8021 				(void) strlcpy(admintab.zone_admin_user,
8022 				    ua_ptr->name,
8023 				    sizeof (admintab.zone_admin_user));
8024 				err = zonecfg_add_admin(handle,
8025 				    &admintab, zonename);
8026 				if (err != Z_OK) {
8027 					(void) fclose(uaf);
8028 					return (err);
8029 				} else {
8030 					changed = B_TRUE;
8031 				}
8032 			}
8033 		}
8034 	} /* end-of-while-loop */
8035 	(void) fclose(uaf);
8036 	return (changed? Z_OK: Z_NO_ENTRY);
8037 }
8038 
8039 static void
8040 update_profiles(char *rbac_profs, boolean_t add)
8041 {
8042 	char new_profs[MAXPROFS];
8043 	char *cur_prof;
8044 	boolean_t first = B_TRUE;
8045 	boolean_t found = B_FALSE;
8046 	char *lasts;
8047 
8048 	cur_prof = strtok_r(rbac_profs, ",", &lasts);
8049 	while (cur_prof != NULL) {
8050 		if (strcmp(cur_prof, ZONE_MGMT_PROF) == 0) {
8051 			found = B_TRUE;
8052 			if (!add) {
8053 				cur_prof = strtok_r(NULL, ",", &lasts);
8054 				continue;
8055 			}
8056 		}
8057 		if (first) {
8058 			first = B_FALSE;
8059 		} else {
8060 			(void) strlcat(new_profs, ",",
8061 			    MAXPROFS);
8062 		}
8063 		(void) strlcat(new_profs, cur_prof,
8064 		    MAXPROFS);
8065 		cur_prof = strtok_r(NULL, ",", &lasts);
8066 	}
8067 	/*
8068 	 * Now prepend the Zone Management profile at the beginning
8069 	 * of the list if it is needed, and append the rest.
8070 	 * Return the updated list in the original buffer.
8071 	 */
8072 	if (add && !found) {
8073 		first = B_FALSE;
8074 		(void) strlcpy(rbac_profs, ZONE_MGMT_PROF, MAXPROFS);
8075 	} else {
8076 		first = B_TRUE;
8077 		rbac_profs[0] = '\0';
8078 	}
8079 	if (strlen(new_profs) > 0) {
8080 		if (!first)
8081 			(void) strlcat(rbac_profs, ",", MAXPROFS);
8082 		(void) strlcat(rbac_profs, new_profs, MAXPROFS);
8083 	}
8084 }
8085 
8086 #define	MAX_CMD_LEN	1024
8087 
8088 static int
8089 do_subproc(char *zonename, char *cmdbuf)
8090 {
8091 	char inbuf[MAX_CMD_LEN];
8092 	FILE *file;
8093 	int status;
8094 
8095 	file = popen(cmdbuf, "r");
8096 	if (file == NULL) {
8097 		zerror(zonename, gettext("Could not launch: %s"), cmdbuf);
8098 		return (-1);
8099 	}
8100 
8101 	while (fgets(inbuf, sizeof (inbuf), file) != NULL)
8102 		(void) fprintf(stderr, "%s", inbuf);
8103 	status = pclose(file);
8104 
8105 	if (WIFSIGNALED(status)) {
8106 		zerror(zonename, gettext("%s unexpectedly terminated "
8107 		    "due to signal %d"),
8108 		    cmdbuf, WTERMSIG(status));
8109 		return (-1);
8110 	}
8111 	assert(WIFEXITED(status));
8112 	return (WEXITSTATUS(status));
8113 }
8114 
8115 /*
8116  * This function updates the local /etc/user_attr file to
8117  * correspond to the admin settings that are currently being
8118  * committed. The updates are done via usermod and/or rolemod
8119  * depending on the type of the specified user. It is also
8120  * invoked to remove entries from user_attr corresponding to
8121  * removed admin assignments, using an empty auths string.
8122  *
8123  * Because the removed entries are no longer included in the
8124  * cofiguration that is being committed, a linked list of
8125  * removed admin entries is maintained to keep track of such
8126  * transactions. The head of the list is stored in the zone_dh_userauths
8127  * element of the handle strcture.
8128  */
8129 static int
8130 zonecfg_authorize_user_impl(zone_dochandle_t handle, char *user,
8131     char *auths, char *zonename)
8132 {
8133 	char *right;
8134 	char old_auths[MAXAUTHS];
8135 	char new_auths[MAXAUTHS];
8136 	char rbac_profs[MAXPROFS];
8137 	char *lasts;
8138 	userattr_t *u;
8139 	boolean_t first = B_TRUE;
8140 	boolean_t is_zone_admin = B_FALSE;
8141 	char user_cmd[] = "/usr/sbin/usermod";
8142 	char role_cmd[] = "/usr/sbin/rolemod";
8143 	char *auths_cmd = user_cmd;	/* either usermod or rolemod */
8144 	char *new_auth_start;		/* string containing the new auths */
8145 	int new_auth_cnt = 0;		/* delta of changed authorizations */
8146 
8147 	/*
8148 	 * First get the existing authorizations for this user
8149 	 */
8150 
8151 	bzero(&old_auths, sizeof (old_auths));
8152 	bzero(&new_auths, sizeof (new_auths));
8153 	bzero(&rbac_profs, sizeof (rbac_profs));
8154 	if ((u = getusernam(user)) != NULL) {
8155 		char *current_auths;
8156 		char *current_profs;
8157 		char *type;
8158 
8159 		type = kva_match(u->attr, USERATTR_TYPE_KW);
8160 		if (type != NULL) {
8161 			if (strcmp(type, USERATTR_TYPE_NONADMIN_KW) == 0)
8162 				auths_cmd = role_cmd;
8163 		}
8164 
8165 		current_auths = kva_match(u->attr, USERATTR_AUTHS_KW);
8166 		if (current_auths != NULL) {
8167 			char *cur_auth;
8168 			char *delete_name;
8169 			size_t offset;
8170 
8171 			offset = strlen(ZONE_AUTH_PREFIX);
8172 
8173 			(void) strlcpy(old_auths, current_auths, MAXAUTHS);
8174 			cur_auth = strtok_r(current_auths, ",", &lasts);
8175 
8176 			/*
8177 			 * Next, remove any existing authorizations
8178 			 * for this zone, and determine if the
8179 			 * user still needs the Zone Management Profile.
8180 			 */
8181 			if (is_renaming(handle))
8182 				delete_name = handle->zone_dh_delete_name;
8183 			else
8184 				delete_name = NULL;
8185 			while (cur_auth != NULL) {
8186 				if (!is_zone_auth(&cur_auth, zonename,
8187 				    delete_name)) {
8188 					if (first) {
8189 						first = B_FALSE;
8190 					} else {
8191 						(void) strlcat(new_auths, ",",
8192 						    MAXAUTHS);
8193 					}
8194 					(void) strlcat(new_auths, cur_auth,
8195 					    MAXAUTHS);
8196 					/*
8197 					 * If the user has authorizations
8198 					 * for other zones, then set a
8199 					 * flag indicate that the Zone
8200 					 * Management profile should be
8201 					 * preserved in user_attr.
8202 					 */
8203 					if (strncmp(cur_auth,
8204 					    ZONE_AUTH_PREFIX, offset) == 0)
8205 						is_zone_admin = B_TRUE;
8206 				} else {
8207 					new_auth_cnt++;
8208 				}
8209 				cur_auth = strtok_r(NULL, ",", &lasts);
8210 			}
8211 		}
8212 		current_profs = kva_match(u->attr, USERATTR_PROFILES_KW);
8213 		if (current_profs != NULL) {
8214 			(void) strlcpy(rbac_profs, current_profs, MAXPROFS);
8215 		}
8216 		free_userattr(u);
8217 	}
8218 	/*
8219 	 * The following is done to avoid revisiting the
8220 	 * user_attr entry for this user
8221 	 */
8222 	(void) zonecfg_remove_userauths(handle, user, "", B_FALSE);
8223 
8224 	/*
8225 	 * Convert each right into a properly formatted authorization
8226 	 */
8227 	new_auth_start = new_auths + strlen(new_auths);
8228 	if (!first)
8229 		new_auth_start++;
8230 	right = strtok_r(auths, ",", &lasts);
8231 	while (right != NULL) {
8232 		char auth[MAXAUTHS];
8233 
8234 		(void) snprintf(auth, MAXAUTHS, "%s%s/%s",
8235 		    ZONE_AUTH_PREFIX, right, zonename);
8236 		if (first) {
8237 			first = B_FALSE;
8238 		} else {
8239 			(void) strlcat(new_auths, ",", MAXAUTHS);
8240 		}
8241 		(void) strlcat(new_auths, auth, MAXAUTHS);
8242 		is_zone_admin = B_TRUE;
8243 		new_auth_cnt--;
8244 		right = strtok_r(NULL, ",", &lasts);
8245 	}
8246 
8247 	/*
8248 	 * Need to update the authorizations in user_attr unless
8249 	 * the number of old and new authorizations is unchanged
8250 	 * and the new auths are a substrings of the old auths.
8251 	 *
8252 	 * If the user's previous authorizations have changed
8253 	 * execute the usermod progam to update them in user_attr.
8254 	 */
8255 	if ((new_auth_cnt != 0) ||
8256 	    (strstr(old_auths, new_auth_start) == NULL)) {
8257 		char    *cmdbuf;
8258 		size_t  cmd_len;
8259 
8260 		update_profiles(rbac_profs, is_zone_admin);
8261 		cmd_len = snprintf(NULL, 0, "%s -A \"%s\" -P \"%s\" %s",
8262 		    auths_cmd, new_auths, rbac_profs, user) + 1;
8263 		if ((cmdbuf = malloc(cmd_len)) == NULL) {
8264 			return (Z_NOMEM);
8265 		}
8266 		(void) snprintf(cmdbuf, cmd_len, "%s -A \"%s\" -P \"%s\" %s",
8267 		    auths_cmd, new_auths, rbac_profs, user);
8268 		if (do_subproc(zonename, cmdbuf) != 0) {
8269 			free(cmdbuf);
8270 			return (Z_SYSTEM);
8271 		}
8272 		free(cmdbuf);
8273 	}
8274 
8275 	return (Z_OK);
8276 }
8277 
8278 int
8279 zonecfg_authorize_users(zone_dochandle_t handle, char *zonename)
8280 {
8281 	xmlNodePtr cur;
8282 	int err;
8283 	char user[MAXUSERNAME];
8284 	char auths[MAXAUTHS];
8285 
8286 	if ((err = operation_prep(handle)) != Z_OK)
8287 		return (err);
8288 
8289 	cur = handle->zone_dh_cur;
8290 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
8291 		if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
8292 			continue;
8293 		if (fetchprop(cur, DTD_ATTR_USER, user,
8294 		    sizeof (user)) != Z_OK)
8295 			continue;
8296 		if (fetchprop(cur, DTD_ATTR_AUTHS, auths,
8297 		    sizeof (auths)) != Z_OK)
8298 			continue;
8299 		if (zonecfg_authorize_user_impl(handle, user, auths, zonename)
8300 		    != Z_OK)
8301 			return (Z_SYSTEM);
8302 	}
8303 	(void) zonecfg_remove_userauths(handle, "", "", B_TRUE);
8304 
8305 	return (Z_OK);
8306 }
8307 
8308 int
8309 zonecfg_deauthorize_user(zone_dochandle_t handle, char *user, char *zonename)
8310 {
8311 	return (zonecfg_authorize_user_impl(handle, user, "", zonename));
8312 }
8313 
8314 int
8315 zonecfg_deauthorize_users(zone_dochandle_t handle, char *zonename)
8316 {
8317 	xmlNodePtr cur;
8318 	int err;
8319 	char user[MAXUSERNAME];
8320 
8321 	if ((err = operation_prep(handle)) != Z_OK)
8322 		return (err);
8323 
8324 	cur = handle->zone_dh_cur;
8325 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
8326 		if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
8327 			continue;
8328 		if (fetchprop(cur, DTD_ATTR_USER, user,
8329 		    sizeof (user)) != Z_OK)
8330 			continue;
8331 		if ((err = zonecfg_deauthorize_user(handle, user,
8332 		    zonename)) != Z_OK)
8333 			return (err);
8334 	}
8335 	return (Z_OK);
8336 }
8337 
8338 int
8339 zonecfg_insert_userauths(zone_dochandle_t handle, char *user, char *zonename)
8340 {
8341 	zone_userauths_t *new, **prev, *next;
8342 
8343 	prev = &handle->zone_dh_userauths;
8344 	next = *prev;
8345 	while (next) {
8346 		if ((strncmp(next->user, user, MAXUSERNAME) == 0) &&
8347 		    (strncmp(next->zonename, zonename,
8348 		    ZONENAME_MAX) == 0)) {
8349 			/*
8350 			 * user is already in list
8351 			 * which isn't supposed to happen!
8352 			 */
8353 			return (Z_OK);
8354 		}
8355 		prev = &next->next;
8356 		next = *prev;
8357 	}
8358 	new = (zone_userauths_t *)malloc(sizeof (zone_userauths_t));
8359 	if (new == NULL)
8360 		return (Z_NOMEM);
8361 
8362 	(void) strlcpy(new->user, user, sizeof (new->user));
8363 	(void) strlcpy(new->zonename, zonename, sizeof (new->zonename));
8364 	new->next = NULL;
8365 	*prev = new;
8366 	return (Z_OK);
8367 }
8368 
8369 int
8370 zonecfg_remove_userauths(zone_dochandle_t handle, char *user, char *zonename,
8371     boolean_t deauthorize)
8372 {
8373 	zone_userauths_t *new, **prev, *next;
8374 
8375 	prev = &handle->zone_dh_userauths;
8376 	next = *prev;
8377 
8378 	while (next) {
8379 		if ((strlen(user) == 0 ||
8380 		    strncmp(next->user, user, MAXUSERNAME) == 0) &&
8381 		    (strlen(zonename) == 0 ||
8382 		    (strncmp(next->zonename, zonename, ZONENAME_MAX) == 0))) {
8383 			new = next;
8384 			*prev = next->next;
8385 			next =  *prev;
8386 			if (deauthorize)
8387 				(void) zonecfg_deauthorize_user(handle,
8388 				    new->user, new->zonename);
8389 			free(new);
8390 			continue;
8391 		}
8392 		prev = &next->next;
8393 		next = *prev;
8394 	}
8395 	return (Z_OK);
8396 }
8397