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