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