1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2014 Gary Mills
24 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
25 * Copyright (c) 2018, Joyent, Inc.
26 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
27 */
28
29#include <libsysevent.h>
30#include <pthread.h>
31#include <stdlib.h>
32#include <errno.h>
33#include <fnmatch.h>
34#include <strings.h>
35#include <unistd.h>
36#include <assert.h>
37#include <libgen.h>
38#include <libintl.h>
39#include <alloca.h>
40#include <ctype.h>
41#include <sys/acl.h>
42#include <sys/stat.h>
43#include <sys/brand.h>
44#include <sys/mntio.h>
45#include <sys/mnttab.h>
46#include <sys/nvpair.h>
47#include <sys/types.h>
48#include <sys/sockio.h>
49#include <sys/systeminfo.h>
50#include <ftw.h>
51#include <pool.h>
52#include <libscf.h>
53#include <libproc.h>
54#include <sys/priocntl.h>
55#include <libuutil.h>
56#include <wait.h>
57#include <bsm/adt.h>
58#include <auth_attr.h>
59#include <auth_list.h>
60#include <secdb.h>
61#include <user_attr.h>
62#include <prof_attr.h>
63
64#include <arpa/inet.h>
65#include <netdb.h>
66
67#include <libxml/xmlmemory.h>
68#include <libxml/parser.h>
69
70#include <libdevinfo.h>
71#include <uuid/uuid.h>
72#include <dirent.h>
73#include <libbrand.h>
74
75#include <libzonecfg.h>
76#include "zonecfg_impl.h"
77
78#define	_PATH_TMPFILE	"/zonecfg.XXXXXX"
79#define	ZONE_CB_RETRY_COUNT		10
80#define	ZONE_EVENT_PING_SUBCLASS	"ping"
81#define	ZONE_EVENT_PING_PUBLISHER	"solaris"
82
83/* Hard-code the DTD element/attribute/entity names just once, here. */
84#define	DTD_ELEM_ATTR		(const xmlChar *) "attr"
85#define	DTD_ELEM_COMMENT	(const xmlChar *) "comment"
86#define	DTD_ELEM_DEVICE		(const xmlChar *) "device"
87#define	DTD_ELEM_FS		(const xmlChar *) "filesystem"
88#define	DTD_ELEM_FSOPTION	(const xmlChar *) "fsoption"
89#define	DTD_ELEM_NET		(const xmlChar *) "network"
90#define	DTD_ELEM_RCTL		(const xmlChar *) "rctl"
91#define	DTD_ELEM_RCTLVALUE	(const xmlChar *) "rctl-value"
92#define	DTD_ELEM_ZONE		(const xmlChar *) "zone"
93#define	DTD_ELEM_DATASET	(const xmlChar *) "dataset"
94#define	DTD_ELEM_TMPPOOL	(const xmlChar *) "tmp_pool"
95#define	DTD_ELEM_PSET		(const xmlChar *) "pset"
96#define	DTD_ELEM_MCAP		(const xmlChar *) "mcap"
97#define	DTD_ELEM_PACKAGE	(const xmlChar *) "package"
98#define	DTD_ELEM_OBSOLETES	(const xmlChar *) "obsoletes"
99#define	DTD_ELEM_DEV_PERM	(const xmlChar *) "dev-perm"
100#define	DTD_ELEM_ADMIN		(const xmlChar *) "admin"
101#define	DTD_ELEM_SECFLAGS	(const xmlChar *) "security-flags"
102
103#define	DTD_ATTR_ACTION		(const xmlChar *) "action"
104#define	DTD_ATTR_ADDRESS	(const xmlChar *) "address"
105#define	DTD_ATTR_ALLOWED_ADDRESS	(const xmlChar *) "allowed-address"
106#define	DTD_ATTR_AUTOBOOT	(const xmlChar *) "autoboot"
107#define	DTD_ATTR_IPTYPE		(const xmlChar *) "ip-type"
108#define	DTD_ATTR_DEFROUTER	(const xmlChar *) "defrouter"
109#define	DTD_ATTR_DIR		(const xmlChar *) "directory"
110#define	DTD_ATTR_LIMIT		(const xmlChar *) "limit"
111#define	DTD_ATTR_LIMITPRIV	(const xmlChar *) "limitpriv"
112#define	DTD_ATTR_BOOTARGS	(const xmlChar *) "bootargs"
113#define	DTD_ATTR_SCHED		(const xmlChar *) "scheduling-class"
114#define	DTD_ATTR_MATCH		(const xmlChar *) "match"
115#define	DTD_ATTR_NAME		(const xmlChar *) "name"
116#define	DTD_ATTR_PHYSICAL	(const xmlChar *) "physical"
117#define	DTD_ATTR_POOL		(const xmlChar *) "pool"
118#define	DTD_ATTR_PRIV		(const xmlChar *) "priv"
119#define	DTD_ATTR_RAW		(const xmlChar *) "raw"
120#define	DTD_ATTR_SPECIAL	(const xmlChar *) "special"
121#define	DTD_ATTR_TYPE		(const xmlChar *) "type"
122#define	DTD_ATTR_VALUE		(const xmlChar *) "value"
123#define	DTD_ATTR_ZONEPATH	(const xmlChar *) "zonepath"
124#define	DTD_ATTR_NCPU_MIN	(const xmlChar *) "ncpu_min"
125#define	DTD_ATTR_NCPU_MAX	(const xmlChar *) "ncpu_max"
126#define	DTD_ATTR_IMPORTANCE	(const xmlChar *) "importance"
127#define	DTD_ATTR_PHYSCAP	(const xmlChar *) "physcap"
128#define	DTD_ATTR_VERSION	(const xmlChar *) "version"
129#define	DTD_ATTR_ID		(const xmlChar *) "id"
130#define	DTD_ATTR_UID		(const xmlChar *) "uid"
131#define	DTD_ATTR_GID		(const xmlChar *) "gid"
132#define	DTD_ATTR_MODE		(const xmlChar *) "mode"
133#define	DTD_ATTR_ACL		(const xmlChar *) "acl"
134#define	DTD_ATTR_BRAND		(const xmlChar *) "brand"
135#define	DTD_ATTR_HOSTID		(const xmlChar *) "hostid"
136#define	DTD_ATTR_USER		(const xmlChar *) "user"
137#define	DTD_ATTR_AUTHS		(const xmlChar *) "auths"
138#define	DTD_ATTR_FS_ALLOWED	(const xmlChar *) "fs-allowed"
139#define	DTD_ATTR_DEFAULT	(const xmlChar *) "default"
140#define	DTD_ATTR_LOWER		(const xmlChar *) "lower"
141#define	DTD_ATTR_UPPER		(const xmlChar *) "upper"
142
143
144#define	DTD_ENTITY_BOOLEAN	"boolean"
145#define	DTD_ENTITY_DEVPATH	"devpath"
146#define	DTD_ENTITY_DRIVER	"driver"
147#define	DTD_ENTITY_DRVMIN	"drv_min"
148#define	DTD_ENTITY_FALSE	"false"
149#define	DTD_ENTITY_INT		"int"
150#define	DTD_ENTITY_STRING	"string"
151#define	DTD_ENTITY_TRUE		"true"
152#define	DTD_ENTITY_UINT		"uint"
153
154#define	DTD_ENTITY_BOOL_LEN	6	/* "false" */
155
156#define	ATTACH_FORCED	"SUNWattached.xml"
157
158#define	TMP_POOL_NAME	"SUNWtmp_%s"
159#define	MAX_TMP_POOL_NAME	(ZONENAME_MAX + 9)
160#define	RCAP_SERVICE	"system/rcap:default"
161#define	POOLD_SERVICE	"system/pools/dynamic:default"
162
163/*
164 * rctl alias definitions
165 *
166 * This holds the alias, the full rctl name, the default priv value, action
167 * and lower limit.  The functions that handle rctl aliases step through
168 * this table, matching on the alias, and using the full values for setting
169 * the rctl entry as well the limit for validation.
170 */
171static struct alias {
172	char *shortname;
173	char *realname;
174	char *priv;
175	char *action;
176	uint64_t low_limit;
177} aliases[] = {
178	{ALIAS_MAXLWPS, "zone.max-lwps", "privileged", "deny", 100},
179	{ALIAS_MAXSHMMEM, "zone.max-shm-memory", "privileged", "deny", 0},
180	{ALIAS_MAXSHMIDS, "zone.max-shm-ids", "privileged", "deny", 0},
181	{ALIAS_MAXMSGIDS, "zone.max-msg-ids", "privileged", "deny", 0},
182	{ALIAS_MAXSEMIDS, "zone.max-sem-ids", "privileged", "deny", 0},
183	{ALIAS_MAXLOCKEDMEM, "zone.max-locked-memory", "privileged", "deny", 0},
184	{ALIAS_MAXSWAP, "zone.max-swap", "privileged", "deny", 0},
185	{ALIAS_SHARES, "zone.cpu-shares", "privileged", "none", 0},
186	{ALIAS_CPUCAP, "zone.cpu-cap", "privileged", "deny", 0},
187	{ALIAS_MAXPROCS, "zone.max-processes", "privileged", "deny", 100},
188	{NULL, NULL, NULL, NULL, 0}
189};
190
191/*
192 * Structure for applying rctls to a running zone.  It allows important
193 * process values to be passed together easily.
194 */
195typedef struct pr_info_handle {
196	struct ps_prochandle *pr;
197	pid_t pid;
198} pr_info_handle_t;
199
200struct zone_dochandle {
201	char		*zone_dh_rootdir;
202	xmlDocPtr	zone_dh_doc;
203	xmlNodePtr	zone_dh_cur;
204	xmlNodePtr	zone_dh_top;
205	boolean_t	zone_dh_newzone;
206	boolean_t	zone_dh_snapshot;
207	boolean_t	zone_dh_sw_inv;
208	zone_userauths_t	*zone_dh_userauths;
209	char		zone_dh_delete_name[ZONENAME_MAX];
210};
211
212struct znotify {
213	void * zn_private;
214	evchan_t *zn_eventchan;
215	int (*zn_callback)(const  char *zonename, zoneid_t zid,
216	    const char *newstate, const char *oldstate, hrtime_t when, void *p);
217	pthread_mutex_t zn_mutex;
218	pthread_cond_t zn_cond;
219	pthread_mutex_t zn_bigmutex;
220	volatile enum {ZN_UNLOCKED, ZN_LOCKED, ZN_PING_INFLIGHT,
221	    ZN_PING_RECEIVED} zn_state;
222	char zn_subscriber_id[MAX_SUBID_LEN];
223	volatile boolean_t zn_failed;
224	int zn_failure_count;
225};
226
227/* used to track nested zone-lock operations */
228static int zone_lock_cnt = 0;
229
230/* used to communicate lock status to children */
231#define	LOCK_ENV_VAR	"_ZONEADM_LOCK_HELD"
232static char zoneadm_lock_held[] = LOCK_ENV_VAR"=1";
233static char zoneadm_lock_not_held[] = LOCK_ENV_VAR"=0";
234
235char *zonecfg_root = "";
236
237/*
238 * For functions which return int, which is most of the functions herein,
239 * the return values should be from the Z_foo set defined in <libzonecfg.h>.
240 * In some instances, we take pains mapping some libc errno values to Z_foo
241 * values from this set.
242 */
243
244/*
245 * Set the root (/) path for all zonecfg configuration files.  This is a
246 * private interface used by Live Upgrade extensions to access zone
247 * configuration inside mounted alternate boot environments.
248 * This interface is also used by zoneadm mount and unmount subcommands.
249 */
250void
251zonecfg_set_root(const char *rootpath)
252{
253	if (*zonecfg_root != '\0')
254		free(zonecfg_root);
255	if (rootpath == NULL || rootpath[0] == '\0' || rootpath[1] == '\0' ||
256	    (zonecfg_root = strdup(rootpath)) == NULL)
257		zonecfg_root = "";
258}
259
260const char *
261zonecfg_get_root(void)
262{
263	return (zonecfg_root);
264}
265
266boolean_t
267zonecfg_in_alt_root(void)
268{
269	return (*zonecfg_root != '\0');
270}
271
272/*
273 * Callers of the _file_path() functions are expected to have the second
274 * parameter be a (char foo[MAXPATHLEN]).
275 */
276
277static boolean_t
278config_file_path(const char *zonename, char *answer)
279{
280	return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root,
281	    ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN);
282}
283
284static boolean_t
285snap_file_path(const char *zonename, char *answer)
286{
287	return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml",
288	    zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN);
289}
290
291/*ARGSUSED*/
292static void
293zonecfg_error_func(void *ctx, const char *msg, ...)
294{
295	/*
296	 * This function does nothing by design.  Its purpose is to prevent
297	 * libxml from dumping unwanted messages to stdout/stderr.
298	 */
299}
300
301zone_dochandle_t
302zonecfg_init_handle(void)
303{
304	zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle));
305	if (handle == NULL) {
306		errno = Z_NOMEM;
307		return (NULL);
308	}
309
310	/* generic libxml initialization */
311	(void) xmlLineNumbersDefault(1);
312	xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
313	xmlDoValidityCheckingDefaultValue = 1;
314	(void) xmlKeepBlanksDefault(0);
315	xmlGetWarningsDefaultValue = 0;
316	xmlSetGenericErrorFunc(NULL, zonecfg_error_func);
317
318	return (handle);
319}
320
321int
322zonecfg_check_handle(zone_dochandle_t handle)
323{
324	if (handle == NULL || handle->zone_dh_doc == NULL)
325		return (Z_BAD_HANDLE);
326	return (Z_OK);
327}
328
329void
330zonecfg_fini_handle(zone_dochandle_t handle)
331{
332	if (zonecfg_check_handle(handle) == Z_OK)
333		xmlFreeDoc(handle->zone_dh_doc);
334	if (handle != NULL)
335		free(handle);
336}
337
338static int
339zonecfg_destroy_impl(char *filename)
340{
341	if (unlink(filename) == -1) {
342		if (errno == EACCES)
343			return (Z_ACCES);
344		if (errno == ENOENT)
345			return (Z_NO_ZONE);
346		return (Z_MISC_FS);
347	}
348	return (Z_OK);
349}
350
351int
352zonecfg_destroy(const char *zonename, boolean_t force)
353{
354	char path[MAXPATHLEN];
355	struct zoneent ze;
356	int err, state_err;
357	zone_state_t state;
358
359	if (!config_file_path(zonename, path))
360		return (Z_MISC_FS);
361
362	state_err = zone_get_state((char *)zonename, &state);
363	err = access(path, W_OK);
364
365	/*
366	 * If there is no file, and no index entry, reliably indicate that no
367	 * such zone exists.
368	 */
369	if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT))
370		return (Z_NO_ZONE);
371
372	/*
373	 * Handle any other filesystem related errors (except if the XML
374	 * file is missing, which we treat silently), unless we're forcing,
375	 * in which case we plow on.
376	 */
377	if (err == -1 && errno != ENOENT) {
378		if (errno == EACCES)
379			return (Z_ACCES);
380		else if (!force)
381			return (Z_MISC_FS);
382	}
383
384	if (state > ZONE_STATE_INSTALLED)
385		return (Z_BAD_ZONE_STATE);
386
387	if (!force && state > ZONE_STATE_CONFIGURED)
388		return (Z_BAD_ZONE_STATE);
389
390	/*
391	 * Index deletion succeeds even if the entry doesn't exist.  So this
392	 * will fail only if we've had some more severe problem.
393	 */
394	bzero(&ze, sizeof (ze));
395	(void) strlcpy(ze.zone_name, zonename, sizeof (ze.zone_name));
396	if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK)
397		if (!force)
398			return (err);
399
400	err = zonecfg_destroy_impl(path);
401
402	/*
403	 * Treat failure to find the XML file silently, since, well, it's
404	 * gone, and with the index file cleaned up, we're done.
405	 */
406	if (err == Z_OK || err == Z_NO_ZONE)
407		return (Z_OK);
408	return (err);
409}
410
411int
412zonecfg_destroy_snapshot(const char *zonename)
413{
414	char path[MAXPATHLEN];
415
416	if (!snap_file_path(zonename, path))
417		return (Z_MISC_FS);
418	return (zonecfg_destroy_impl(path));
419}
420
421static int
422getroot(zone_dochandle_t handle, xmlNodePtr *root)
423{
424	if (zonecfg_check_handle(handle) == Z_BAD_HANDLE)
425		return (Z_BAD_HANDLE);
426
427	*root = xmlDocGetRootElement(handle->zone_dh_doc);
428
429	if (*root == NULL)
430		return (Z_EMPTY_DOCUMENT);
431
432	if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE))
433		return (Z_WRONG_DOC_TYPE);
434
435	return (Z_OK);
436}
437
438static int
439operation_prep(zone_dochandle_t handle)
440{
441	xmlNodePtr root;
442	int err;
443
444	if ((err = getroot(handle, &root)) != 0)
445		return (err);
446
447	handle->zone_dh_cur = root;
448	handle->zone_dh_top = root;
449	return (Z_OK);
450}
451
452static int
453fetchprop(xmlNodePtr cur, const xmlChar *propname, char *dst, size_t dstsize)
454{
455	xmlChar *property;
456	size_t srcsize;
457
458	if ((property = xmlGetProp(cur, propname)) == NULL)
459		return (Z_BAD_PROPERTY);
460	srcsize = strlcpy(dst, (char *)property, dstsize);
461	xmlFree(property);
462	if (srcsize >= dstsize)
463		return (Z_TOO_BIG);
464	return (Z_OK);
465}
466
467static int
468fetch_alloc_prop(xmlNodePtr cur, const xmlChar *propname, char **dst)
469{
470	xmlChar *property;
471
472	if ((property = xmlGetProp(cur, propname)) == NULL)
473		return (Z_BAD_PROPERTY);
474	if ((*dst = strdup((char *)property)) == NULL) {
475		xmlFree(property);
476		return (Z_NOMEM);
477	}
478	xmlFree(property);
479	return (Z_OK);
480}
481
482static int
483getrootattr(zone_dochandle_t handle, const xmlChar *propname,
484    char *propval, size_t propsize)
485{
486	xmlNodePtr root;
487	int err;
488
489	if ((err = getroot(handle, &root)) != 0)
490		return (err);
491
492	return (fetchprop(root, propname, propval, propsize));
493}
494
495static int
496get_alloc_rootattr(zone_dochandle_t handle, const xmlChar *propname,
497    char **propval)
498{
499	xmlNodePtr root;
500	int err;
501
502	if ((err = getroot(handle, &root)) != 0)
503		return (err);
504
505	return (fetch_alloc_prop(root, propname, propval));
506}
507
508static int
509setrootattr(zone_dochandle_t handle, const xmlChar *propname,
510    const char *propval)
511{
512	int err;
513	xmlNodePtr root;
514
515	if ((err = getroot(handle, &root)) != Z_OK)
516		return (err);
517
518	/*
519	 * If we get a null propval remove the property (ignore return since it
520	 * may not be set to begin with).
521	 */
522	if (propval == NULL) {
523		(void) xmlUnsetProp(root, propname);
524	} else {
525		if (xmlSetProp(root, propname, (const xmlChar *) propval)
526		    == NULL)
527			return (Z_INVAL);
528	}
529	return (Z_OK);
530}
531
532static void
533addcomment(zone_dochandle_t handle, const char *comment)
534{
535	xmlNodePtr node;
536	node = xmlNewComment((xmlChar *) comment);
537
538	if (node != NULL)
539		(void) xmlAddPrevSibling(handle->zone_dh_top, node);
540}
541
542static void
543stripcomments(zone_dochandle_t handle)
544{
545	xmlDocPtr top;
546	xmlNodePtr child, next;
547
548	top = handle->zone_dh_doc;
549	for (child = top->xmlChildrenNode; child != NULL; child = next) {
550		next = child->next;
551		if (child->name == NULL)
552			continue;
553		if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) {
554			next = child->next;
555			xmlUnlinkNode(child);
556			xmlFreeNode(child);
557		}
558	}
559}
560
561static void
562strip_sw_inv(zone_dochandle_t handle)
563{
564	xmlNodePtr root, child, next;
565
566	root = xmlDocGetRootElement(handle->zone_dh_doc);
567	for (child = root->xmlChildrenNode; child != NULL; child = next) {
568		next = child->next;
569		if (child->name == NULL)
570			continue;
571		if (xmlStrcmp(child->name, DTD_ELEM_PACKAGE) == 0) {
572			next = child->next;
573			xmlUnlinkNode(child);
574			xmlFreeNode(child);
575		}
576	}
577}
578
579static int
580zonecfg_get_handle_impl(const char *zonename, const char *filename,
581    zone_dochandle_t handle)
582{
583	xmlValidCtxtPtr cvp;
584	struct stat statbuf;
585	int valid;
586
587	if (zonename == NULL)
588		return (Z_NO_ZONE);
589
590	if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) {
591		/* distinguish file not found vs. found but not parsed */
592		if (stat(filename, &statbuf) == 0)
593			return (Z_INVALID_DOCUMENT);
594		return (Z_NO_ZONE);
595	}
596	if ((cvp = xmlNewValidCtxt()) == NULL)
597		return (Z_NOMEM);
598	cvp->error = zonecfg_error_func;
599	cvp->warning = zonecfg_error_func;
600	valid = xmlValidateDocument(cvp, handle->zone_dh_doc);
601	xmlFreeValidCtxt(cvp);
602	if (valid == 0)
603		return (Z_INVALID_DOCUMENT);
604
605	/* delete any comments such as inherited Sun copyright / ident str */
606	stripcomments(handle);
607	return (Z_OK);
608}
609
610int
611zonecfg_get_handle(const char *zonename, zone_dochandle_t handle)
612{
613	char path[MAXPATHLEN];
614
615	if (!config_file_path(zonename, path))
616		return (Z_MISC_FS);
617	handle->zone_dh_newzone = B_FALSE;
618
619	return (zonecfg_get_handle_impl(zonename, path, handle));
620}
621
622int
623zonecfg_get_attach_handle(const char *path, const char *fname,
624    const char *zonename, boolean_t preserve_sw, zone_dochandle_t handle)
625{
626	char		migpath[MAXPATHLEN];
627	int		err;
628	struct stat	buf;
629
630	if (snprintf(migpath, sizeof (migpath), "%s/root", path) >=
631	    sizeof (migpath))
632		return (Z_NOMEM);
633
634	if (stat(migpath, &buf) == -1 || !S_ISDIR(buf.st_mode))
635		return (Z_NO_ZONE);
636
637	if (snprintf(migpath, sizeof (migpath), "%s/%s", path, fname) >=
638	    sizeof (migpath))
639		return (Z_NOMEM);
640
641	if ((err = zonecfg_get_handle_impl(zonename, migpath, handle)) != Z_OK)
642		return (err);
643
644	if (!preserve_sw)
645		strip_sw_inv(handle);
646
647	handle->zone_dh_newzone = B_TRUE;
648	if ((err = setrootattr(handle, DTD_ATTR_ZONEPATH, path)) != Z_OK)
649		return (err);
650
651	return (setrootattr(handle, DTD_ATTR_NAME, zonename));
652}
653
654int
655zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle)
656{
657	char path[MAXPATHLEN];
658
659	if (!snap_file_path(zonename, path))
660		return (Z_MISC_FS);
661	handle->zone_dh_newzone = B_FALSE;
662	return (zonecfg_get_handle_impl(zonename, path, handle));
663}
664
665int
666zonecfg_get_template_handle(const char *template, const char *zonename,
667    zone_dochandle_t handle)
668{
669	char path[MAXPATHLEN];
670	int err;
671
672	if (!config_file_path(template, path))
673		return (Z_MISC_FS);
674
675	if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK)
676		return (err);
677	handle->zone_dh_newzone = B_TRUE;
678	return (setrootattr(handle, DTD_ATTR_NAME, zonename));
679}
680
681int
682zonecfg_get_xml_handle(const char *path, zone_dochandle_t handle)
683{
684	struct stat buf;
685	int err;
686
687	if (stat(path, &buf) == -1)
688		return (Z_MISC_FS);
689
690	if ((err = zonecfg_get_handle_impl("xml", path, handle)) != Z_OK)
691		return (err);
692	handle->zone_dh_newzone = B_TRUE;
693	return (Z_OK);
694}
695
696/*
697 * Initialize two handles from the manifest read on fd.  The rem_handle
698 * is initialized from the input file, including the sw inventory.  The
699 * local_handle is initialized with the same zone configuration but with
700 * no sw inventory.
701 */
702int
703zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle,
704    zone_dochandle_t rem_handle)
705{
706	xmlValidCtxtPtr cvp;
707	int valid;
708
709	/* load the manifest into the handle for the remote system */
710	if ((rem_handle->zone_dh_doc = xmlReadFd(fd, NULL, NULL, 0)) == NULL) {
711		return (Z_INVALID_DOCUMENT);
712	}
713	if ((cvp = xmlNewValidCtxt()) == NULL)
714		return (Z_NOMEM);
715	cvp->error = zonecfg_error_func;
716	cvp->warning = zonecfg_error_func;
717	valid = xmlValidateDocument(cvp, rem_handle->zone_dh_doc);
718	xmlFreeValidCtxt(cvp);
719	if (valid == 0)
720		return (Z_INVALID_DOCUMENT);
721
722	/* delete any comments such as inherited Sun copyright / ident str */
723	stripcomments(rem_handle);
724
725	rem_handle->zone_dh_newzone = B_TRUE;
726	rem_handle->zone_dh_sw_inv = B_TRUE;
727
728	/*
729	 * Now use the remote system handle to generate a local system handle
730	 * with an identical zones configuration but no sw inventory.
731	 */
732	if ((local_handle->zone_dh_doc = xmlCopyDoc(rem_handle->zone_dh_doc,
733	    1)) == NULL) {
734		return (Z_INVALID_DOCUMENT);
735	}
736
737	/*
738	 * We need to re-run xmlValidateDocument on local_handle to properly
739	 * update the in-core representation of the configuration.
740	 */
741	if ((cvp = xmlNewValidCtxt()) == NULL)
742		return (Z_NOMEM);
743	cvp->error = zonecfg_error_func;
744	cvp->warning = zonecfg_error_func;
745	valid = xmlValidateDocument(cvp, local_handle->zone_dh_doc);
746	xmlFreeValidCtxt(cvp);
747	if (valid == 0)
748		return (Z_INVALID_DOCUMENT);
749
750	strip_sw_inv(local_handle);
751
752	local_handle->zone_dh_newzone = B_TRUE;
753	local_handle->zone_dh_sw_inv = B_FALSE;
754
755	return (Z_OK);
756}
757
758static boolean_t
759is_renaming(zone_dochandle_t handle)
760{
761	if (handle->zone_dh_newzone)
762		return (B_FALSE);
763	if (strlen(handle->zone_dh_delete_name) > 0)
764		return (B_TRUE);
765	return (B_FALSE);
766}
767
768static boolean_t
769is_new(zone_dochandle_t handle)
770{
771	return (handle->zone_dh_newzone || handle->zone_dh_snapshot);
772}
773
774static boolean_t
775is_snapshot(zone_dochandle_t handle)
776{
777	return (handle->zone_dh_snapshot);
778}
779
780/*
781 * It would be great to be able to use libc's ctype(3c) macros, but we
782 * can't, as they are locale sensitive, and it would break our limited thread
783 * safety if this routine had to change the app locale on the fly.
784 */
785int
786zonecfg_validate_zonename(const char *zone)
787{
788	int i;
789
790	if (strcmp(zone, GLOBAL_ZONENAME) == 0)
791		return (Z_BOGUS_ZONE_NAME);
792
793	if (strlen(zone) >= ZONENAME_MAX)
794		return (Z_BOGUS_ZONE_NAME);
795
796	if (!((zone[0] >= 'a' && zone[0] <= 'z') ||
797	    (zone[0] >= 'A' && zone[0] <= 'Z') ||
798	    (zone[0] >= '0' && zone[0] <= '9')))
799		return (Z_BOGUS_ZONE_NAME);
800
801	for (i = 1; zone[i] != '\0'; i++) {
802		if (!((zone[i] >= 'a' && zone[i] <= 'z') ||
803		    (zone[i] >= 'A' && zone[i] <= 'Z') ||
804		    (zone[i] >= '0' && zone[i] <= '9') ||
805		    (zone[i] == '-') || (zone[i] == '_') || (zone[i] == '.')))
806			return (Z_BOGUS_ZONE_NAME);
807	}
808
809	return (Z_OK);
810}
811
812/*
813 * Changing the zone name requires us to track both the old and new
814 * name of the zone until commit time.
815 */
816int
817zonecfg_get_name(zone_dochandle_t handle, char *name, size_t namesize)
818{
819	return (getrootattr(handle, DTD_ATTR_NAME, name, namesize));
820}
821
822static int
823insert_admins(zone_dochandle_t handle, char *zonename)
824{
825	int err;
826	struct zone_admintab admintab;
827
828	if ((err = zonecfg_setadminent(handle)) != Z_OK) {
829		return (err);
830	}
831	while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
832		err = zonecfg_insert_userauths(handle,
833		    admintab.zone_admin_user, zonename);
834		if (err != Z_OK) {
835			(void) zonecfg_endadminent(handle);
836			return (err);
837		}
838	}
839	(void) zonecfg_endadminent(handle);
840	return (Z_OK);
841}
842
843int
844zonecfg_set_name(zone_dochandle_t handle, char *name)
845{
846	zone_state_t state;
847	char curname[ZONENAME_MAX], old_delname[ZONENAME_MAX];
848	int err;
849
850	if ((err = getrootattr(handle, DTD_ATTR_NAME, curname,
851	    sizeof (curname))) != Z_OK)
852		return (err);
853
854	if (strcmp(name, curname) == 0)
855		return (Z_OK);
856
857	/*
858	 * Switching zone names to one beginning with SUNW is not permitted.
859	 */
860	if (strncmp(name, "SUNW", 4) == 0)
861		return (Z_BOGUS_ZONE_NAME);
862
863	if ((err = zonecfg_validate_zonename(name)) != Z_OK)
864		return (err);
865
866	/*
867	 * Setting the name back to the original name (effectively a revert of
868	 * the name) is fine.  But if we carry on, we'll falsely identify the
869	 * name as "in use," so special case here.
870	 */
871	if (strcmp(name, handle->zone_dh_delete_name) == 0) {
872		err = setrootattr(handle, DTD_ATTR_NAME, name);
873		handle->zone_dh_delete_name[0] = '\0';
874		return (err);
875	}
876
877	/* Check to see if new name chosen is already in use */
878	if (zone_get_state(name, &state) != Z_NO_ZONE)
879		return (Z_NAME_IN_USE);
880
881	/*
882	 * If this isn't already "new" or in a renaming transition, then
883	 * we're initiating a rename here; so stash the "delete name"
884	 * (i.e. the name of the zone we'll be removing) for the rename.
885	 */
886	(void) strlcpy(old_delname, handle->zone_dh_delete_name,
887	    sizeof (old_delname));
888	if (!is_new(handle) && !is_renaming(handle)) {
889		/*
890		 * Name change is allowed only when the zone we're altering
891		 * is not ready or running.
892		 */
893		err = zone_get_state(curname, &state);
894		if (err == Z_OK) {
895			if (state > ZONE_STATE_INSTALLED)
896				return (Z_BAD_ZONE_STATE);
897		} else if (err != Z_NO_ZONE) {
898			return (err);
899		}
900
901		(void) strlcpy(handle->zone_dh_delete_name, curname,
902		    sizeof (handle->zone_dh_delete_name));
903		assert(is_renaming(handle));
904	} else if (is_renaming(handle)) {
905		err = zone_get_state(handle->zone_dh_delete_name, &state);
906		if (err == Z_OK) {
907			if (state > ZONE_STATE_INSTALLED)
908				return (Z_BAD_ZONE_STATE);
909		} else if (err != Z_NO_ZONE) {
910			return (err);
911		}
912	}
913
914	if ((err = setrootattr(handle, DTD_ATTR_NAME, name)) != Z_OK) {
915		/*
916		 * Restore the deletename to whatever it was at the
917		 * top of the routine, since we've had a failure.
918		 */
919		(void) strlcpy(handle->zone_dh_delete_name, old_delname,
920		    sizeof (handle->zone_dh_delete_name));
921		return (err);
922	}
923
924	/*
925	 * Record the old admins from the old zonename
926	 * so that they can be deleted when the operation is committed.
927	 */
928	if ((err = insert_admins(handle, curname)) != Z_OK)
929		return (err);
930	else
931		return (Z_OK);
932}
933
934int
935zonecfg_get_zonepath(zone_dochandle_t handle, char *path, size_t pathsize)
936{
937	size_t len;
938
939	if ((len = strlcpy(path, zonecfg_root, pathsize)) >= pathsize)
940		return (Z_TOO_BIG);
941	return (getrootattr(handle, DTD_ATTR_ZONEPATH, path + len,
942	    pathsize - len));
943}
944
945int
946zonecfg_set_zonepath(zone_dochandle_t handle, char *zonepath)
947{
948	size_t len;
949	char *modpath, *copy_mp, *curr_mp;	/* modified path ptrs */
950	char last_copied;
951	int ret;
952
953	/*
954	 * Collapse multiple contiguous slashes and remove trailing slash.
955	 */
956	modpath = strdup(zonepath);
957	if (modpath == NULL)
958		return (Z_NOMEM);
959	last_copied = '\0';
960	for (copy_mp = curr_mp = modpath; *curr_mp != '\0'; curr_mp++) {
961		if (*curr_mp != '/' || last_copied != '/') {
962			last_copied = *copy_mp = *curr_mp;
963			copy_mp++;
964		}
965	}
966	if (last_copied == '/')
967		copy_mp--;
968	*copy_mp = '\0';
969
970	/*
971	 * The user deals in absolute paths in the running global zone, but the
972	 * internal configuration files deal with boot environment relative
973	 * paths.  Strip out the alternate root when specified.
974	 */
975	len = strlen(zonecfg_root);
976	if (strncmp(modpath, zonecfg_root, len) != 0 || modpath[len] != '/') {
977		free(modpath);
978		return (Z_BAD_PROPERTY);
979	}
980	curr_mp = modpath + len;
981	ret = setrootattr(handle, DTD_ATTR_ZONEPATH, curr_mp);
982	free(modpath);
983	return (ret);
984}
985
986static int
987i_zonecfg_get_brand(zone_dochandle_t handle, char *brand, size_t brandsize,
988    boolean_t default_query)
989{
990	int ret, sz;
991
992	ret = getrootattr(handle, DTD_ATTR_BRAND, brand, brandsize);
993
994	/*
995	 * If the lookup failed, or succeeded in finding a non-null brand
996	 * string then return.
997	 */
998	if (ret != Z_OK || brand[0] != '\0')
999		return (ret);
1000
1001	if (!default_query) {
1002		/* If the zone has no brand, it is the default brand. */
1003		return (zonecfg_default_brand(brand, brandsize));
1004	}
1005
1006	/* if SUNWdefault didn't specify a brand, fallback to "native" */
1007	sz = strlcpy(brand, NATIVE_BRAND_NAME, brandsize);
1008	if (sz >= brandsize)
1009		return (Z_TOO_BIG);
1010	return (Z_OK);
1011}
1012
1013int
1014zonecfg_get_brand(zone_dochandle_t handle, char *brand, size_t brandsize)
1015{
1016	return (i_zonecfg_get_brand(handle, brand, brandsize, B_FALSE));
1017}
1018
1019int
1020zonecfg_set_brand(zone_dochandle_t handle, char *brand)
1021{
1022	return (setrootattr(handle, DTD_ATTR_BRAND, brand));
1023}
1024
1025int
1026zonecfg_get_autoboot(zone_dochandle_t handle, boolean_t *autoboot)
1027{
1028	char autobootstr[DTD_ENTITY_BOOL_LEN];
1029	int ret;
1030
1031	if ((ret = getrootattr(handle, DTD_ATTR_AUTOBOOT, autobootstr,
1032	    sizeof (autobootstr))) != Z_OK)
1033		return (ret);
1034
1035	if (strcmp(autobootstr, DTD_ENTITY_TRUE) == 0)
1036		*autoboot = B_TRUE;
1037	else if (strcmp(autobootstr, DTD_ENTITY_FALSE) == 0)
1038		*autoboot = B_FALSE;
1039	else
1040		ret = Z_BAD_PROPERTY;
1041	return (ret);
1042}
1043
1044int
1045zonecfg_set_autoboot(zone_dochandle_t handle, boolean_t autoboot)
1046{
1047	return (setrootattr(handle, DTD_ATTR_AUTOBOOT,
1048	    autoboot ? DTD_ENTITY_TRUE : DTD_ENTITY_FALSE));
1049}
1050
1051int
1052zonecfg_get_pool(zone_dochandle_t handle, char *pool, size_t poolsize)
1053{
1054	return (getrootattr(handle, DTD_ATTR_POOL, pool, poolsize));
1055}
1056
1057int
1058zonecfg_set_pool(zone_dochandle_t handle, char *pool)
1059{
1060	return (setrootattr(handle, DTD_ATTR_POOL, pool));
1061}
1062
1063int
1064zonecfg_get_limitpriv(zone_dochandle_t handle, char **limitpriv)
1065{
1066	return (get_alloc_rootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv));
1067}
1068
1069int
1070zonecfg_set_limitpriv(zone_dochandle_t handle, char *limitpriv)
1071{
1072	return (setrootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv));
1073}
1074
1075int
1076zonecfg_get_bootargs(zone_dochandle_t handle, char *bargs, size_t bargssize)
1077{
1078	return (getrootattr(handle, DTD_ATTR_BOOTARGS, bargs, bargssize));
1079}
1080
1081int
1082zonecfg_set_bootargs(zone_dochandle_t handle, char *bargs)
1083{
1084	return (setrootattr(handle, DTD_ATTR_BOOTARGS, bargs));
1085}
1086
1087int
1088zonecfg_get_sched_class(zone_dochandle_t handle, char *sched, size_t schedsize)
1089{
1090	return (getrootattr(handle, DTD_ATTR_SCHED, sched, schedsize));
1091}
1092
1093int
1094zonecfg_set_sched(zone_dochandle_t handle, char *sched)
1095{
1096	return (setrootattr(handle, DTD_ATTR_SCHED, sched));
1097}
1098
1099/*
1100 * /etc/zones/index caches a vital piece of information which is also
1101 * in the <zonename>.xml file: the path to the zone.  This is for performance,
1102 * since we need to walk all zonepath's in order to be able to detect conflicts
1103 * (see crosscheck_zonepaths() in the zoneadm command).
1104 *
1105 * An additional complexity is that when doing a rename, we'd like the entire
1106 * index update operation (rename, and potential state changes) to be atomic.
1107 * In general, the operation of this function should succeed or fail as
1108 * a unit.
1109 */
1110int
1111zonecfg_refresh_index_file(zone_dochandle_t handle)
1112{
1113	char name[ZONENAME_MAX], zonepath[MAXPATHLEN];
1114	struct zoneent ze;
1115	int err;
1116	int opcode;
1117	char *zn;
1118
1119	bzero(&ze, sizeof (ze));
1120	ze.zone_state = -1;	/* Preserve existing state in index */
1121
1122	if ((err = zonecfg_get_name(handle, name, sizeof (name))) != Z_OK)
1123		return (err);
1124	(void) strlcpy(ze.zone_name, name, sizeof (ze.zone_name));
1125
1126	if ((err = zonecfg_get_zonepath(handle, zonepath,
1127	    sizeof (zonepath))) != Z_OK)
1128		return (err);
1129	(void) strlcpy(ze.zone_path, zonepath + strlen(zonecfg_root),
1130	    sizeof (ze.zone_path));
1131
1132	if (is_renaming(handle)) {
1133		opcode = PZE_MODIFY;
1134		(void) strlcpy(ze.zone_name, handle->zone_dh_delete_name,
1135		    sizeof (ze.zone_name));
1136		(void) strlcpy(ze.zone_newname, name, sizeof (ze.zone_newname));
1137	} else if (is_new(handle)) {
1138		FILE *cookie;
1139		/*
1140		 * Be tolerant of the zone already existing in the index file,
1141		 * since we might be forcibly overwriting an existing
1142		 * configuration with a new one (for example 'create -F'
1143		 * in zonecfg).
1144		 */
1145		opcode = PZE_ADD;
1146		cookie = setzoneent();
1147		while ((zn = getzoneent(cookie)) != NULL) {
1148			if (strcmp(zn, name) == 0) {
1149				opcode = PZE_MODIFY;
1150				free(zn);
1151				break;
1152			}
1153			free(zn);
1154		}
1155		endzoneent(cookie);
1156		ze.zone_state = ZONE_STATE_CONFIGURED;
1157	} else {
1158		opcode = PZE_MODIFY;
1159	}
1160
1161	if ((err = putzoneent(&ze, opcode)) != Z_OK)
1162		return (err);
1163
1164	return (Z_OK);
1165}
1166
1167/*
1168 * The goal of this routine is to cause the index file update and the
1169 * document save to happen as an atomic operation.  We do the document
1170 * first, saving a backup copy using a hard link; if that succeeds, we go
1171 * on to the index.  If that fails, we roll the document back into place.
1172 *
1173 * Strategy:
1174 *
1175 * New zone 'foo' configuration:
1176 * 	Create tmpfile (zonecfg.xxxxxx)
1177 * 	Write XML to tmpfile
1178 * 	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
1179 * 	Add entry to index file
1180 * 	If it fails, delete foo.xml, leaving nothing behind.
1181 *
1182 * Save existing zone 'foo':
1183 * 	Make backup of foo.xml -> .backup
1184 * 	Create tmpfile (zonecfg.xxxxxx)
1185 * 	Write XML to tmpfile
1186 * 	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
1187 * 	Modify index file as needed
1188 * 	If it fails, recover from .backup -> foo.xml
1189 *
1190 * Rename 'foo' to 'bar':
1191 * 	Create tmpfile (zonecfg.xxxxxx)
1192 * 	Write XML to tmpfile
1193 * 	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml)
1194 * 	Add entry for 'bar' to index file, Remove entry for 'foo' (refresh)
1195 * 	If it fails, delete bar.xml; foo.xml is left behind.
1196 */
1197static int
1198zonecfg_save_impl(zone_dochandle_t handle, char *filename)
1199{
1200	char tmpfile[MAXPATHLEN];
1201	char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN];
1202	int tmpfd, err, valid;
1203	xmlValidCtxt cvp = { NULL };
1204	boolean_t backup;
1205
1206	(void) strlcpy(tmpfile, filename, sizeof (tmpfile));
1207	(void) dirname(tmpfile);
1208	(void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile));
1209
1210	tmpfd = mkstemp(tmpfile);
1211	if (tmpfd == -1) {
1212		(void) unlink(tmpfile);
1213		return (Z_TEMP_FILE);
1214	}
1215	(void) close(tmpfd);
1216
1217	cvp.error = zonecfg_error_func;
1218	cvp.warning = zonecfg_error_func;
1219
1220	/*
1221	 * We do a final validation of the document.  Since the library has
1222	 * malfunctioned if it fails to validate, we follow-up with an
1223	 * assert() that the doc is valid.
1224	 */
1225	valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1226	assert(valid != 0);
1227
1228	if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0)
1229		goto err;
1230
1231	(void) chmod(tmpfile, 0644);
1232
1233	/*
1234	 * In the event we are doing a standard save, hard link a copy of the
1235	 * original file in .backup.<pid>.filename so we can restore it if
1236	 * something goes wrong.
1237	 */
1238	if (!is_new(handle) && !is_renaming(handle)) {
1239		backup = B_TRUE;
1240
1241		(void) strlcpy(bakdir, filename, sizeof (bakdir));
1242		(void) strlcpy(bakbase, filename, sizeof (bakbase));
1243		(void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s",
1244		    dirname(bakdir), getpid(), basename(bakbase));
1245
1246		if (link(filename, bakfile) == -1) {
1247			err = errno;
1248			(void) unlink(tmpfile);
1249			if (errno == EACCES)
1250				return (Z_ACCES);
1251			return (Z_MISC_FS);
1252		}
1253	}
1254
1255	/*
1256	 * Move the new document over top of the old.
1257	 * i.e.:   zonecfg.XXXXXX  ->  myzone.xml
1258	 */
1259	if (rename(tmpfile, filename) == -1) {
1260		err = errno;
1261		(void) unlink(tmpfile);
1262		if (backup)
1263			(void) unlink(bakfile);
1264		if (err == EACCES)
1265			return (Z_ACCES);
1266		return (Z_MISC_FS);
1267	}
1268
1269	/*
1270	 * If this is a snapshot, we're done-- don't add an index entry.
1271	 */
1272	if (is_snapshot(handle))
1273		return (Z_OK);
1274
1275	/* now update the index file to reflect whatever we just did */
1276	if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) {
1277		if (backup) {
1278			/*
1279			 * Try to restore from our backup.
1280			 */
1281			(void) unlink(filename);
1282			(void) rename(bakfile, filename);
1283		} else {
1284			/*
1285			 * Either the zone is new, in which case we can delete
1286			 * new.xml, or we're doing a rename, so ditto.
1287			 */
1288			assert(is_new(handle) || is_renaming(handle));
1289			(void) unlink(filename);
1290		}
1291		return (Z_UPDATING_INDEX);
1292	}
1293
1294	if (backup)
1295		(void) unlink(bakfile);
1296
1297	return (Z_OK);
1298
1299err:
1300	(void) unlink(tmpfile);
1301	return (Z_SAVING_FILE);
1302}
1303
1304int
1305zonecfg_save(zone_dochandle_t handle)
1306{
1307	char zname[ZONENAME_MAX], path[MAXPATHLEN];
1308	char delpath[MAXPATHLEN];
1309	int err = Z_SAVING_FILE;
1310
1311	if (zonecfg_check_handle(handle) != Z_OK)
1312		return (Z_BAD_HANDLE);
1313
1314	/*
1315	 * We don't support saving snapshots or a tree containing a sw
1316	 * inventory at this time.
1317	 */
1318	if (handle->zone_dh_snapshot || handle->zone_dh_sw_inv)
1319		return (Z_INVAL);
1320
1321	if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK)
1322		return (err);
1323
1324	if (!config_file_path(zname, path))
1325		return (Z_MISC_FS);
1326
1327	addcomment(handle, "\n    DO NOT EDIT THIS "
1328	    "FILE.  Use zonecfg(1M) instead.\n");
1329
1330	/*
1331	 * Update user_attr first so that it will be older
1332	 * than the config file.
1333	 */
1334	(void) zonecfg_authorize_users(handle, zname);
1335	err = zonecfg_save_impl(handle, path);
1336
1337	stripcomments(handle);
1338
1339	if (err != Z_OK)
1340		return (err);
1341
1342	handle->zone_dh_newzone = B_FALSE;
1343
1344	if (is_renaming(handle)) {
1345		if (config_file_path(handle->zone_dh_delete_name, delpath))
1346			(void) unlink(delpath);
1347		handle->zone_dh_delete_name[0] = '\0';
1348	}
1349
1350	return (Z_OK);
1351}
1352
1353int
1354zonecfg_verify_save(zone_dochandle_t handle, char *filename)
1355{
1356	int valid;
1357
1358	xmlValidCtxt cvp = { NULL };
1359
1360	if (zonecfg_check_handle(handle) != Z_OK)
1361		return (Z_BAD_HANDLE);
1362
1363	cvp.error = zonecfg_error_func;
1364	cvp.warning = zonecfg_error_func;
1365
1366	/*
1367	 * We do a final validation of the document.  Since the library has
1368	 * malfunctioned if it fails to validate, we follow-up with an
1369	 * assert() that the doc is valid.
1370	 */
1371	valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1372	assert(valid != 0);
1373
1374	if (xmlSaveFormatFile(filename, handle->zone_dh_doc, 1) <= 0)
1375		return (Z_SAVING_FILE);
1376
1377	return (Z_OK);
1378}
1379
1380int
1381zonecfg_detach_save(zone_dochandle_t handle, uint_t flags)
1382{
1383	char zname[ZONENAME_MAX];
1384	char path[MAXPATHLEN];
1385	char migpath[MAXPATHLEN];
1386	xmlValidCtxt cvp = { NULL };
1387	int err = Z_SAVING_FILE;
1388	int valid;
1389
1390	if (zonecfg_check_handle(handle) != Z_OK)
1391		return (Z_BAD_HANDLE);
1392
1393	if (flags & ZONE_DRY_RUN) {
1394		(void) strlcpy(migpath, "-", sizeof (migpath));
1395	} else {
1396		if ((err = zonecfg_get_name(handle, zname, sizeof (zname)))
1397		    != Z_OK)
1398			return (err);
1399
1400		if ((err = zone_get_zonepath(zname, path, sizeof (path)))
1401		    != Z_OK)
1402			return (err);
1403
1404		if (snprintf(migpath, sizeof (migpath), "%s/%s", path,
1405		    ZONE_DETACHED) >= sizeof (migpath))
1406			return (Z_NOMEM);
1407	}
1408
1409	if ((err = operation_prep(handle)) != Z_OK)
1410		return (err);
1411
1412	addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
1413	    "Use zonecfg(1M) and zoneadm(1M) attach.\n");
1414
1415	cvp.error = zonecfg_error_func;
1416	cvp.warning = zonecfg_error_func;
1417
1418	/*
1419	 * We do a final validation of the document.  Since the library has
1420	 * malfunctioned if it fails to validate, we follow-up with an
1421	 * assert() that the doc is valid.
1422	 */
1423	valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1424	assert(valid != 0);
1425
1426	if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0)
1427		return (Z_SAVING_FILE);
1428
1429	if (!(flags & ZONE_DRY_RUN))
1430		(void) chmod(migpath, 0644);
1431
1432	stripcomments(handle);
1433
1434	handle->zone_dh_newzone = B_FALSE;
1435
1436	return (Z_OK);
1437}
1438
1439boolean_t
1440zonecfg_detached(const char *path)
1441{
1442	char		migpath[MAXPATHLEN];
1443	struct stat	buf;
1444
1445	if (snprintf(migpath, sizeof (migpath), "%s/%s", path, ZONE_DETACHED) >=
1446	    sizeof (migpath))
1447		return (B_FALSE);
1448
1449	if (stat(migpath, &buf) != -1)
1450		return (B_TRUE);
1451
1452	return (B_FALSE);
1453}
1454
1455void
1456zonecfg_rm_detached(zone_dochandle_t handle, boolean_t forced)
1457{
1458	char zname[ZONENAME_MAX];
1459	char path[MAXPATHLEN];
1460	char detached[MAXPATHLEN];
1461	char attached[MAXPATHLEN];
1462
1463	if (zonecfg_check_handle(handle) != Z_OK)
1464		return;
1465
1466	if (zonecfg_get_name(handle, zname, sizeof (zname)) != Z_OK)
1467		return;
1468
1469	if (zone_get_zonepath(zname, path, sizeof (path)) != Z_OK)
1470		return;
1471
1472	(void) snprintf(detached, sizeof (detached), "%s/%s", path,
1473	    ZONE_DETACHED);
1474	(void) snprintf(attached, sizeof (attached), "%s/%s", path,
1475	    ATTACH_FORCED);
1476
1477	if (forced) {
1478		(void) rename(detached, attached);
1479	} else {
1480		(void) unlink(attached);
1481		(void) unlink(detached);
1482	}
1483}
1484
1485/*
1486 * Special case: if access(2) fails with ENOENT, then try again using
1487 * ZONE_CONFIG_ROOT instead of config_file_path(zonename).  This is how we
1488 * work around the case of a config file which has not been created yet:
1489 * the user will need access to the directory so use that as a heuristic.
1490 */
1491
1492int
1493zonecfg_access(const char *zonename, int amode)
1494{
1495	char path[MAXPATHLEN];
1496
1497	if (!config_file_path(zonename, path))
1498		return (Z_INVAL);
1499	if (access(path, amode) == 0)
1500		return (Z_OK);
1501	if (errno == ENOENT) {
1502		if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1503		    ZONE_CONFIG_ROOT) >= sizeof (path))
1504			return (Z_INVAL);
1505		if (access(path, amode) == 0)
1506			return (Z_OK);
1507	}
1508	if (errno == EACCES)
1509		return (Z_ACCES);
1510	if (errno == EINVAL)
1511		return (Z_INVAL);
1512	return (Z_MISC_FS);
1513}
1514
1515int
1516zonecfg_create_snapshot(const char *zonename)
1517{
1518	zone_dochandle_t handle;
1519	char path[MAXPATHLEN], zonepath[MAXPATHLEN], rpath[MAXPATHLEN];
1520	int error = Z_OK, res;
1521
1522	if ((handle = zonecfg_init_handle()) == NULL) {
1523		return (Z_NOMEM);
1524	}
1525
1526	handle->zone_dh_newzone = B_TRUE;
1527	handle->zone_dh_snapshot = B_TRUE;
1528
1529	if ((error = zonecfg_get_handle(zonename, handle)) != Z_OK)
1530		goto out;
1531	if ((error = operation_prep(handle)) != Z_OK)
1532		goto out;
1533	error = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath));
1534	if (error != Z_OK)
1535		goto out;
1536	if ((res = resolvepath(zonepath, rpath, sizeof (rpath))) == -1) {
1537		error = Z_RESOLVED_PATH;
1538		goto out;
1539	}
1540	/*
1541	 * If the resolved path is not the same as the original path, then
1542	 * save the resolved path in the snapshot, thus preventing any
1543	 * potential problems down the line when zoneadmd goes to unmount
1544	 * file systems and depends on initial string matches with resolved
1545	 * paths.
1546	 */
1547	rpath[res] = '\0';
1548	if (strcmp(zonepath, rpath) != 0) {
1549		if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK)
1550			goto out;
1551	}
1552	if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1553	    ZONE_SNAPSHOT_ROOT) >= sizeof (path)) {
1554		error = Z_MISC_FS;
1555		goto out;
1556	}
1557	if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) {
1558		error = Z_MISC_FS;
1559		goto out;
1560	}
1561
1562	if (!snap_file_path(zonename, path)) {
1563		error = Z_MISC_FS;
1564		goto out;
1565	}
1566
1567	addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
1568	    "It is a snapshot of running zone state.\n");
1569
1570	error = zonecfg_save_impl(handle, path);
1571
1572	stripcomments(handle);
1573
1574out:
1575	zonecfg_fini_handle(handle);
1576	return (error);
1577}
1578
1579int
1580zonecfg_get_iptype(zone_dochandle_t handle, zone_iptype_t *iptypep)
1581{
1582	char property[10]; /* 10 is big enough for "shared"/"exclusive" */
1583	int err;
1584
1585	err = getrootattr(handle, DTD_ATTR_IPTYPE, property, sizeof (property));
1586	if (err == Z_BAD_PROPERTY) {
1587		/* Return default value */
1588		*iptypep = ZS_SHARED;
1589		return (Z_OK);
1590	} else if (err != Z_OK) {
1591		return (err);
1592	}
1593
1594	if (strlen(property) == 0 ||
1595	    strcmp(property, "shared") == 0)
1596		*iptypep = ZS_SHARED;
1597	else if (strcmp(property, "exclusive") == 0)
1598		*iptypep = ZS_EXCLUSIVE;
1599	else
1600		return (Z_INVAL);
1601
1602	return (Z_OK);
1603}
1604
1605int
1606zonecfg_set_iptype(zone_dochandle_t handle, zone_iptype_t iptype)
1607{
1608	xmlNodePtr cur;
1609
1610	if (handle == NULL)
1611		return (Z_INVAL);
1612
1613	cur = xmlDocGetRootElement(handle->zone_dh_doc);
1614	if (cur == NULL) {
1615		return (Z_EMPTY_DOCUMENT);
1616	}
1617
1618	if (xmlStrcmp(cur->name, DTD_ELEM_ZONE) != 0) {
1619		return (Z_WRONG_DOC_TYPE);
1620	}
1621	switch (iptype) {
1622	case ZS_SHARED:
1623		/*
1624		 * Since "shared" is the default, we don't write it to the
1625		 * configuration file, so that it's easier to migrate those
1626		 * zones elsewhere, eg., to systems which are not IP-Instances
1627		 * aware.
1628		 * xmlUnsetProp only fails when the attribute doesn't exist,
1629		 * which we don't care.
1630		 */
1631		(void) xmlUnsetProp(cur, DTD_ATTR_IPTYPE);
1632		break;
1633	case ZS_EXCLUSIVE:
1634		if (xmlSetProp(cur, DTD_ATTR_IPTYPE,
1635		    (const xmlChar *) "exclusive") == NULL)
1636			return (Z_INVAL);
1637		break;
1638	}
1639	return (Z_OK);
1640}
1641
1642static int
1643newprop(xmlNodePtr node, const xmlChar *attrname, char *src)
1644{
1645	xmlAttrPtr newattr;
1646
1647	newattr = xmlNewProp(node, attrname, (xmlChar *)src);
1648	if (newattr == NULL) {
1649		xmlUnlinkNode(node);
1650		xmlFreeNode(node);
1651		return (Z_BAD_PROPERTY);
1652	}
1653	return (Z_OK);
1654}
1655
1656static int
1657zonecfg_add_filesystem_core(zone_dochandle_t handle, struct zone_fstab *tabptr)
1658{
1659	xmlNodePtr newnode, cur = handle->zone_dh_cur, options_node;
1660	zone_fsopt_t *ptr;
1661	int err;
1662
1663	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_FS, NULL);
1664	if ((err = newprop(newnode, DTD_ATTR_SPECIAL,
1665	    tabptr->zone_fs_special)) != Z_OK)
1666		return (err);
1667	if (tabptr->zone_fs_raw[0] != '\0' &&
1668	    (err = newprop(newnode, DTD_ATTR_RAW, tabptr->zone_fs_raw)) != Z_OK)
1669		return (err);
1670	if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK)
1671		return (err);
1672	if ((err = newprop(newnode, DTD_ATTR_TYPE,
1673	    tabptr->zone_fs_type)) != Z_OK)
1674		return (err);
1675	if (tabptr->zone_fs_options != NULL) {
1676		for (ptr = tabptr->zone_fs_options; ptr != NULL;
1677		    ptr = ptr->zone_fsopt_next) {
1678			options_node = xmlNewTextChild(newnode, NULL,
1679			    DTD_ELEM_FSOPTION, NULL);
1680			if ((err = newprop(options_node, DTD_ATTR_NAME,
1681			    ptr->zone_fsopt_opt)) != Z_OK)
1682				return (err);
1683		}
1684	}
1685	return (Z_OK);
1686}
1687
1688int
1689zonecfg_add_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
1690{
1691	int err;
1692
1693	if (tabptr == NULL)
1694		return (Z_INVAL);
1695
1696	if ((err = operation_prep(handle)) != Z_OK)
1697		return (err);
1698
1699	if ((err = zonecfg_add_filesystem_core(handle, tabptr)) != Z_OK)
1700		return (err);
1701
1702	return (Z_OK);
1703}
1704
1705int
1706zonecfg_add_fs_option(struct zone_fstab *tabptr, char *option)
1707{
1708	zone_fsopt_t *last, *old, *new;
1709
1710	last = tabptr->zone_fs_options;
1711	for (old = last; old != NULL; old = old->zone_fsopt_next)
1712		last = old;	/* walk to the end of the list */
1713	new = (zone_fsopt_t *)malloc(sizeof (zone_fsopt_t));
1714	if (new == NULL)
1715		return (Z_NOMEM);
1716	(void) strlcpy(new->zone_fsopt_opt, option,
1717	    sizeof (new->zone_fsopt_opt));
1718	new->zone_fsopt_next = NULL;
1719	if (last == NULL)
1720		tabptr->zone_fs_options = new;
1721	else
1722		last->zone_fsopt_next = new;
1723	return (Z_OK);
1724}
1725
1726int
1727zonecfg_remove_fs_option(struct zone_fstab *tabptr, char *option)
1728{
1729	zone_fsopt_t *last, *this, *next;
1730
1731	last = tabptr->zone_fs_options;
1732	for (this = last; this != NULL; this = this->zone_fsopt_next) {
1733		if (strcmp(this->zone_fsopt_opt, option) == 0) {
1734			next = this->zone_fsopt_next;
1735			if (this == tabptr->zone_fs_options)
1736				tabptr->zone_fs_options = next;
1737			else
1738				last->zone_fsopt_next = next;
1739			free(this);
1740			return (Z_OK);
1741		} else
1742			last = this;
1743	}
1744	return (Z_NO_PROPERTY_ID);
1745}
1746
1747void
1748zonecfg_free_fs_option_list(zone_fsopt_t *list)
1749{
1750	zone_fsopt_t *this, *next;
1751
1752	for (this = list; this != NULL; this = next) {
1753		next = this->zone_fsopt_next;
1754		free(this);
1755	}
1756}
1757
1758void
1759zonecfg_free_rctl_value_list(struct zone_rctlvaltab *valtab)
1760{
1761	if (valtab == NULL)
1762		return;
1763	zonecfg_free_rctl_value_list(valtab->zone_rctlval_next);
1764	free(valtab);
1765}
1766
1767static boolean_t
1768match_prop(xmlNodePtr cur, const xmlChar *attr, char *user_prop)
1769{
1770	xmlChar *gotten_prop;
1771	int prop_result;
1772
1773	gotten_prop = xmlGetProp(cur, attr);
1774	if (gotten_prop == NULL)	/* shouldn't happen */
1775		return (B_FALSE);
1776	prop_result = xmlStrcmp(gotten_prop, (const xmlChar *) user_prop);
1777	xmlFree(gotten_prop);
1778	return ((prop_result == 0));	/* empty strings will match */
1779}
1780
1781static int
1782zonecfg_delete_filesystem_core(zone_dochandle_t handle,
1783    struct zone_fstab *tabptr)
1784{
1785	xmlNodePtr cur = handle->zone_dh_cur;
1786	boolean_t dir_match, spec_match, raw_match, type_match;
1787
1788	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1789		if (xmlStrcmp(cur->name, DTD_ELEM_FS))
1790			continue;
1791		dir_match = match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir);
1792		spec_match = match_prop(cur, DTD_ATTR_SPECIAL,
1793		    tabptr->zone_fs_special);
1794		raw_match = match_prop(cur, DTD_ATTR_RAW,
1795		    tabptr->zone_fs_raw);
1796		type_match = match_prop(cur, DTD_ATTR_TYPE,
1797		    tabptr->zone_fs_type);
1798		if (dir_match && spec_match && raw_match && type_match) {
1799			xmlUnlinkNode(cur);
1800			xmlFreeNode(cur);
1801			return (Z_OK);
1802		}
1803	}
1804	return (Z_NO_RESOURCE_ID);
1805}
1806
1807int
1808zonecfg_delete_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
1809{
1810	int err;
1811
1812	if (tabptr == NULL)
1813		return (Z_INVAL);
1814
1815	if ((err = operation_prep(handle)) != Z_OK)
1816		return (err);
1817
1818	if ((err = zonecfg_delete_filesystem_core(handle, tabptr)) != Z_OK)
1819		return (err);
1820
1821	return (Z_OK);
1822}
1823
1824int
1825zonecfg_modify_filesystem(
1826	zone_dochandle_t handle,
1827	struct zone_fstab *oldtabptr,
1828	struct zone_fstab *newtabptr)
1829{
1830	int err;
1831
1832	if (oldtabptr == NULL || newtabptr == NULL)
1833		return (Z_INVAL);
1834
1835	if ((err = operation_prep(handle)) != Z_OK)
1836		return (err);
1837
1838	if ((err = zonecfg_delete_filesystem_core(handle, oldtabptr)) != Z_OK)
1839		return (err);
1840
1841	if ((err = zonecfg_add_filesystem_core(handle, newtabptr)) != Z_OK)
1842		return (err);
1843
1844	return (Z_OK);
1845}
1846
1847int
1848zonecfg_lookup_filesystem(
1849	zone_dochandle_t handle,
1850	struct zone_fstab *tabptr)
1851{
1852	xmlNodePtr cur, options, firstmatch;
1853	int err;
1854	char dirname[MAXPATHLEN], special[MAXPATHLEN], raw[MAXPATHLEN];
1855	char type[FSTYPSZ];
1856	char options_str[MAX_MNTOPT_STR];
1857
1858	if (tabptr == NULL)
1859		return (Z_INVAL);
1860
1861	if ((err = operation_prep(handle)) != Z_OK)
1862		return (err);
1863
1864	/*
1865	 * Walk the list of children looking for matches on any properties
1866	 * specified in the fstab parameter.  If more than one resource
1867	 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return
1868	 * Z_NO_RESOURCE_ID.
1869	 */
1870	cur = handle->zone_dh_cur;
1871	firstmatch = NULL;
1872	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1873		if (xmlStrcmp(cur->name, DTD_ELEM_FS))
1874			continue;
1875		if (strlen(tabptr->zone_fs_dir) > 0) {
1876			if ((fetchprop(cur, DTD_ATTR_DIR, dirname,
1877			    sizeof (dirname)) == Z_OK) &&
1878			    (strcmp(tabptr->zone_fs_dir, dirname) == 0)) {
1879				if (firstmatch == NULL)
1880					firstmatch = cur;
1881				else
1882					return (Z_INSUFFICIENT_SPEC);
1883			}
1884		}
1885		if (strlen(tabptr->zone_fs_special) > 0) {
1886			if ((fetchprop(cur, DTD_ATTR_SPECIAL, special,
1887			    sizeof (special)) == Z_OK)) {
1888				if (strcmp(tabptr->zone_fs_special,
1889				    special) == 0) {
1890					if (firstmatch == NULL)
1891						firstmatch = cur;
1892					else if (firstmatch != cur)
1893						return (Z_INSUFFICIENT_SPEC);
1894				} else {
1895					/*
1896					 * If another property matched but this
1897					 * one doesn't then reset firstmatch.
1898					 */
1899					if (firstmatch == cur)
1900						firstmatch = NULL;
1901				}
1902			}
1903		}
1904		if (strlen(tabptr->zone_fs_raw) > 0) {
1905			if ((fetchprop(cur, DTD_ATTR_RAW, raw,
1906			    sizeof (raw)) == Z_OK)) {
1907				if (strcmp(tabptr->zone_fs_raw, raw) == 0) {
1908					if (firstmatch == NULL)
1909						firstmatch = cur;
1910					else if (firstmatch != cur)
1911						return (Z_INSUFFICIENT_SPEC);
1912				} else {
1913					/*
1914					 * If another property matched but this
1915					 * one doesn't then reset firstmatch.
1916					 */
1917					if (firstmatch == cur)
1918						firstmatch = NULL;
1919				}
1920			}
1921		}
1922		if (strlen(tabptr->zone_fs_type) > 0) {
1923			if ((fetchprop(cur, DTD_ATTR_TYPE, type,
1924			    sizeof (type)) == Z_OK)) {
1925				if (strcmp(tabptr->zone_fs_type, type) == 0) {
1926					if (firstmatch == NULL)
1927						firstmatch = cur;
1928					else if (firstmatch != cur)
1929						return (Z_INSUFFICIENT_SPEC);
1930				} else {
1931					/*
1932					 * If another property matched but this
1933					 * one doesn't then reset firstmatch.
1934					 */
1935					if (firstmatch == cur)
1936						firstmatch = NULL;
1937				}
1938			}
1939		}
1940	}
1941
1942	if (firstmatch == NULL)
1943		return (Z_NO_RESOURCE_ID);
1944
1945	cur = firstmatch;
1946
1947	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
1948	    sizeof (tabptr->zone_fs_dir))) != Z_OK)
1949		return (err);
1950
1951	if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
1952	    sizeof (tabptr->zone_fs_special))) != Z_OK)
1953		return (err);
1954
1955	if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
1956	    sizeof (tabptr->zone_fs_raw))) != Z_OK)
1957		return (err);
1958
1959	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
1960	    sizeof (tabptr->zone_fs_type))) != Z_OK)
1961		return (err);
1962
1963	/* options are optional */
1964	tabptr->zone_fs_options = NULL;
1965	for (options = cur->xmlChildrenNode; options != NULL;
1966	    options = options->next) {
1967		if ((fetchprop(options, DTD_ATTR_NAME, options_str,
1968		    sizeof (options_str)) != Z_OK))
1969			break;
1970		if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
1971			break;
1972	}
1973	return (Z_OK);
1974}
1975
1976/*
1977 * Compare two IP addresses in string form.  Allow for the possibility that
1978 * one might have "/<prefix-length>" at the end: allow a match on just the
1979 * IP address (or host name) part.
1980 */
1981
1982boolean_t
1983zonecfg_same_net_address(char *a1, char *a2)
1984{
1985	char *slashp, *slashp1, *slashp2;
1986	int result;
1987
1988	if (strcmp(a1, a2) == 0)
1989		return (B_TRUE);
1990
1991	/*
1992	 * If neither has a slash or both do, they need to match to be
1993	 * considered the same, but they did not match above, so fail.
1994	 */
1995	slashp1 = strchr(a1, '/');
1996	slashp2 = strchr(a2, '/');
1997	if ((slashp1 == NULL && slashp2 == NULL) ||
1998	    (slashp1 != NULL && slashp2 != NULL))
1999		return (B_FALSE);
2000
2001	/*
2002	 * Only one had a slash: pick that one, zero out the slash, compare
2003	 * the "address only" strings, restore the slash, and return the
2004	 * result of the comparison.
2005	 */
2006	slashp = (slashp1 == NULL) ? slashp2 : slashp1;
2007	*slashp = '\0';
2008	result = strcmp(a1, a2);
2009	*slashp = '/';
2010	return ((result == 0));
2011}
2012
2013int
2014zonecfg_valid_net_address(char *address, struct lifreq *lifr)
2015{
2016	struct sockaddr_in *sin4;
2017	struct sockaddr_in6 *sin6;
2018	struct addrinfo hints, *result;
2019	char *slashp = strchr(address, '/');
2020
2021	bzero(lifr, sizeof (struct lifreq));
2022	sin4 = (struct sockaddr_in *)&lifr->lifr_addr;
2023	sin6 = (struct sockaddr_in6 *)&lifr->lifr_addr;
2024	if (slashp != NULL)
2025		*slashp = '\0';
2026	if (inet_pton(AF_INET, address, &sin4->sin_addr) == 1) {
2027		sin4->sin_family = AF_INET;
2028	} else if (inet_pton(AF_INET6, address, &sin6->sin6_addr) == 1) {
2029		if (slashp == NULL)
2030			return (Z_IPV6_ADDR_PREFIX_LEN);
2031		sin6->sin6_family = AF_INET6;
2032	} else {
2033		/* "address" may be a host name */
2034		(void) memset(&hints, 0, sizeof (hints));
2035		hints.ai_family = PF_INET;
2036		if (getaddrinfo(address, NULL, &hints, &result) != 0)
2037			return (Z_BOGUS_ADDRESS);
2038		sin4->sin_family = result->ai_family;
2039
2040		(void) memcpy(&sin4->sin_addr,
2041		    /* LINTED E_BAD_PTR_CAST_ALIGN */
2042		    &((struct sockaddr_in *)result->ai_addr)->sin_addr,
2043		    sizeof (struct in_addr));
2044
2045		freeaddrinfo(result);
2046	}
2047	return (Z_OK);
2048}
2049
2050boolean_t
2051zonecfg_ifname_exists(sa_family_t af, char *ifname)
2052{
2053	struct lifreq lifr;
2054	int so;
2055	int save_errno;
2056
2057	(void) memset(&lifr, 0, sizeof (lifr));
2058	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
2059	lifr.lifr_addr.ss_family = af;
2060	if ((so = socket(af, SOCK_DGRAM, 0)) < 0) {
2061		/* Odd - can't tell if the ifname exists */
2062		return (B_FALSE);
2063	}
2064	if (ioctl(so, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
2065		save_errno = errno;
2066		(void) close(so);
2067		errno = save_errno;
2068		return (B_FALSE);
2069	}
2070	(void) close(so);
2071	return (B_TRUE);
2072}
2073
2074/*
2075 * Determines whether there is a net resource with the physical interface, IP
2076 * address, and default router specified by 'tabptr' in the zone configuration
2077 * to which 'handle' refers.  'tabptr' must have an interface, an address, a
2078 * default router, or a combination of the three.  This function returns Z_OK
2079 * iff there is exactly one net resource matching the query specified by
2080 * 'tabptr'.  The function returns Z_INSUFFICIENT_SPEC if there are multiple
2081 * matches or 'tabptr' does not specify a physical interface, address, or
2082 * default router.  The function returns Z_NO_RESOURCE_ID if are no matches.
2083 *
2084 * Errors might also be returned if the entry that exactly matches the
2085 * query lacks critical network resource information.
2086 *
2087 * If there is a single match, then the matching entry's physical interface, IP
2088 * address, and default router information are stored in 'tabptr'.
2089 */
2090int
2091zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2092{
2093	xmlNodePtr cur;
2094	xmlNodePtr firstmatch;
2095	int err;
2096	char address[INET6_ADDRSTRLEN];
2097	char physical[LIFNAMSIZ];
2098	size_t addrspec;		/* nonzero if tabptr has IP addr */
2099	size_t physspec;		/* nonzero if tabptr has interface */
2100	size_t defrouterspec;		/* nonzero if tabptr has def. router */
2101	size_t allowed_addrspec;
2102	zone_iptype_t iptype;
2103
2104	if (tabptr == NULL)
2105		return (Z_INVAL);
2106
2107	/*
2108	 * Determine the fields that will be searched.  There must be at least
2109	 * one.
2110	 *
2111	 * zone_nwif_address, zone_nwif_physical, and zone_nwif_defrouter are
2112	 * arrays, so no NULL checks are necessary.
2113	 */
2114	addrspec = strlen(tabptr->zone_nwif_address);
2115	physspec = strlen(tabptr->zone_nwif_physical);
2116	defrouterspec = strlen(tabptr->zone_nwif_defrouter);
2117	allowed_addrspec = strlen(tabptr->zone_nwif_allowed_address);
2118	if (addrspec != 0 && allowed_addrspec != 0)
2119		return (Z_INVAL); /* can't specify both */
2120	if (addrspec == 0 && physspec == 0 && defrouterspec == 0 &&
2121	    allowed_addrspec == 0)
2122		return (Z_INSUFFICIENT_SPEC);
2123
2124	if ((err = operation_prep(handle)) != Z_OK)
2125		return (err);
2126
2127	if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK)
2128		return (err);
2129	/*
2130	 * Iterate over the configuration's elements and look for net elements
2131	 * that match the query.
2132	 */
2133	firstmatch = NULL;
2134	cur = handle->zone_dh_cur;
2135	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2136		/* Skip non-net elements */
2137		if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2138			continue;
2139
2140		/*
2141		 * If any relevant fields don't match the query, then skip
2142		 * the current net element.
2143		 */
2144		if (physspec != 0 && (fetchprop(cur, DTD_ATTR_PHYSICAL,
2145		    physical, sizeof (physical)) != Z_OK ||
2146		    strcmp(tabptr->zone_nwif_physical, physical) != 0))
2147			continue;
2148		if (iptype == ZS_SHARED && addrspec != 0 &&
2149		    (fetchprop(cur, DTD_ATTR_ADDRESS, address,
2150		    sizeof (address)) != Z_OK ||
2151		    !zonecfg_same_net_address(tabptr->zone_nwif_address,
2152		    address)))
2153			continue;
2154		if (iptype == ZS_EXCLUSIVE && allowed_addrspec != 0 &&
2155		    (fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS, address,
2156		    sizeof (address)) != Z_OK ||
2157		    !zonecfg_same_net_address(tabptr->zone_nwif_allowed_address,
2158		    address)))
2159			continue;
2160		if (defrouterspec != 0 && (fetchprop(cur, DTD_ATTR_DEFROUTER,
2161		    address, sizeof (address)) != Z_OK ||
2162		    !zonecfg_same_net_address(tabptr->zone_nwif_defrouter,
2163		    address)))
2164			continue;
2165
2166		/*
2167		 * The current net element matches the query.  Select it if
2168		 * it's the first match; otherwise, abort the search.
2169		 */
2170		if (firstmatch == NULL)
2171			firstmatch = cur;
2172		else
2173			return (Z_INSUFFICIENT_SPEC);
2174	}
2175	if (firstmatch == NULL)
2176		return (Z_NO_RESOURCE_ID);
2177
2178	cur = firstmatch;
2179
2180	if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
2181	    sizeof (tabptr->zone_nwif_physical))) != Z_OK)
2182		return (err);
2183
2184	if (iptype == ZS_SHARED &&
2185	    (err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
2186	    sizeof (tabptr->zone_nwif_address))) != Z_OK)
2187		return (err);
2188
2189	if (iptype == ZS_EXCLUSIVE &&
2190	    (err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
2191	    tabptr->zone_nwif_allowed_address,
2192	    sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK)
2193		return (err);
2194
2195	if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
2196	    tabptr->zone_nwif_defrouter,
2197	    sizeof (tabptr->zone_nwif_defrouter))) != Z_OK)
2198		return (err);
2199
2200	return (Z_OK);
2201}
2202
2203static int
2204zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2205{
2206	xmlNodePtr newnode, cur = handle->zone_dh_cur;
2207	int err;
2208
2209	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL);
2210	if (strlen(tabptr->zone_nwif_address) > 0 &&
2211	    (err = newprop(newnode, DTD_ATTR_ADDRESS,
2212	    tabptr->zone_nwif_address)) != Z_OK)
2213		return (err);
2214	if (strlen(tabptr->zone_nwif_allowed_address) > 0 &&
2215	    (err = newprop(newnode, DTD_ATTR_ALLOWED_ADDRESS,
2216	    tabptr->zone_nwif_allowed_address)) != Z_OK)
2217		return (err);
2218	if ((err = newprop(newnode, DTD_ATTR_PHYSICAL,
2219	    tabptr->zone_nwif_physical)) != Z_OK)
2220		return (err);
2221	/*
2222	 * Do not add this property when it is not set, for backwards
2223	 * compatibility and because it is optional.
2224	 */
2225	if ((strlen(tabptr->zone_nwif_defrouter) > 0) &&
2226	    ((err = newprop(newnode, DTD_ATTR_DEFROUTER,
2227	    tabptr->zone_nwif_defrouter)) != Z_OK))
2228		return (err);
2229	return (Z_OK);
2230}
2231
2232int
2233zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2234{
2235	int err;
2236
2237	if (tabptr == NULL)
2238		return (Z_INVAL);
2239
2240	if ((err = operation_prep(handle)) != Z_OK)
2241		return (err);
2242
2243	if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK)
2244		return (err);
2245
2246	return (Z_OK);
2247}
2248
2249static int
2250zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2251{
2252	xmlNodePtr cur = handle->zone_dh_cur;
2253	boolean_t addr_match, phys_match, allowed_addr_match;
2254
2255	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2256		if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2257			continue;
2258
2259		addr_match = match_prop(cur, DTD_ATTR_ADDRESS,
2260		    tabptr->zone_nwif_address);
2261		allowed_addr_match = match_prop(cur, DTD_ATTR_ALLOWED_ADDRESS,
2262		    tabptr->zone_nwif_allowed_address);
2263		phys_match = match_prop(cur, DTD_ATTR_PHYSICAL,
2264		    tabptr->zone_nwif_physical);
2265
2266		if (addr_match && allowed_addr_match && phys_match) {
2267			xmlUnlinkNode(cur);
2268			xmlFreeNode(cur);
2269			return (Z_OK);
2270		}
2271	}
2272	return (Z_NO_RESOURCE_ID);
2273}
2274
2275int
2276zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2277{
2278	int err;
2279
2280	if (tabptr == NULL)
2281		return (Z_INVAL);
2282
2283	if ((err = operation_prep(handle)) != Z_OK)
2284		return (err);
2285
2286	if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK)
2287		return (err);
2288
2289	return (Z_OK);
2290}
2291
2292int
2293zonecfg_modify_nwif(
2294	zone_dochandle_t handle,
2295	struct zone_nwiftab *oldtabptr,
2296	struct zone_nwiftab *newtabptr)
2297{
2298	int err;
2299
2300	if (oldtabptr == NULL || newtabptr == NULL)
2301		return (Z_INVAL);
2302
2303	if ((err = operation_prep(handle)) != Z_OK)
2304		return (err);
2305
2306	if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK)
2307		return (err);
2308
2309	if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK)
2310		return (err);
2311
2312	return (Z_OK);
2313}
2314
2315/*
2316 * Must be a comma-separated list of alpha-numeric file system names.
2317 */
2318static int
2319zonecfg_valid_fs_allowed(const char *fsallowedp)
2320{
2321	char tmp[ZONE_FS_ALLOWED_MAX];
2322	char *cp = tmp;
2323	char *p;
2324
2325	if (strlen(fsallowedp) > ZONE_FS_ALLOWED_MAX)
2326		return (Z_TOO_BIG);
2327
2328	(void) strlcpy(tmp, fsallowedp, sizeof (tmp));
2329
2330	while (*cp != '\0') {
2331		p = cp;
2332		while (*p != '\0' && *p != ',') {
2333			if (!isalnum(*p) && *p != '-')
2334				return (Z_INVALID_PROPERTY);
2335			p++;
2336		}
2337
2338		if (*p == ',') {
2339			if (p == cp)
2340				return (Z_INVALID_PROPERTY);
2341
2342			p++;
2343
2344			if (*p == '\0')
2345				return (Z_INVALID_PROPERTY);
2346		}
2347
2348		cp = p;
2349	}
2350
2351	return (Z_OK);
2352}
2353
2354int
2355zonecfg_get_fs_allowed(zone_dochandle_t handle, char *bufp, size_t buflen)
2356{
2357	int err;
2358
2359	if ((err = getrootattr(handle, DTD_ATTR_FS_ALLOWED,
2360	    bufp, buflen)) != Z_OK)
2361		return (err);
2362	if (bufp[0] == '\0')
2363		return (Z_BAD_PROPERTY);
2364	return (zonecfg_valid_fs_allowed(bufp));
2365}
2366
2367int
2368zonecfg_set_fs_allowed(zone_dochandle_t handle, const char *bufp)
2369{
2370	int err;
2371
2372	if (bufp == NULL || (err = zonecfg_valid_fs_allowed(bufp)) == Z_OK)
2373		return (setrootattr(handle, DTD_ATTR_FS_ALLOWED, bufp));
2374	return (err);
2375}
2376
2377/*
2378 * Determines if the specified string is a valid hostid string.  This function
2379 * returns Z_OK if the string is a valid hostid string.  It returns Z_INVAL if
2380 * 'hostidp' is NULL, Z_TOO_BIG if 'hostidp' refers to a string buffer
2381 * containing a hex string with more than 8 digits, and Z_INVALID_PROPERTY if
2382 * the string has an invalid format.
2383 */
2384static int
2385zonecfg_valid_hostid(const char *hostidp)
2386{
2387	char *currentp;
2388	u_longlong_t hostidval;
2389	size_t len;
2390
2391	if (hostidp == NULL)
2392		return (Z_INVAL);
2393
2394	/* Empty strings and strings with whitespace are invalid. */
2395	if (*hostidp == '\0')
2396		return (Z_INVALID_PROPERTY);
2397	for (currentp = (char *)hostidp; *currentp != '\0'; ++currentp) {
2398		if (isspace(*currentp))
2399			return (Z_INVALID_PROPERTY);
2400	}
2401	len = (size_t)(currentp - hostidp);
2402
2403	/*
2404	 * The caller might pass a hostid that is larger than the maximum
2405	 * unsigned 32-bit integral value.  Check for this!  Also, make sure
2406	 * that the whole string is converted (this helps us find illegal
2407	 * characters) and that the whole string fits within a buffer of size
2408	 * HW_HOSTID_LEN.
2409	 */
2410	currentp = (char *)hostidp;
2411	if (strncmp(hostidp, "0x", 2) == 0 || strncmp(hostidp, "0X", 2) == 0)
2412		currentp += 2;
2413	hostidval = strtoull(currentp, &currentp, 16);
2414	if ((size_t)(currentp - hostidp) >= HW_HOSTID_LEN)
2415		return (Z_TOO_BIG);
2416	if (hostidval > UINT_MAX || hostidval == HW_INVALID_HOSTID ||
2417	    currentp != hostidp + len)
2418		return (Z_INVALID_PROPERTY);
2419	return (Z_OK);
2420}
2421
2422/*
2423 * Gets the zone hostid string stored in the specified zone configuration
2424 * document.  This function returns Z_OK on success.  Z_BAD_PROPERTY is returned
2425 * if the config file doesn't specify a hostid or if the hostid is blank.
2426 *
2427 * Note that buflen should be at least HW_HOSTID_LEN.
2428 */
2429int
2430zonecfg_get_hostid(zone_dochandle_t handle, char *bufp, size_t buflen)
2431{
2432	int err;
2433
2434	if ((err = getrootattr(handle, DTD_ATTR_HOSTID, bufp, buflen)) != Z_OK)
2435		return (err);
2436	if (bufp[0] == '\0')
2437		return (Z_BAD_PROPERTY);
2438	return (zonecfg_valid_hostid(bufp));
2439}
2440
2441/*
2442 * Sets the hostid string in the specified zone config document to the given
2443 * string value.  If 'hostidp' is NULL, then the config document's hostid
2444 * attribute is cleared.  Non-NULL hostids are validated.  This function returns
2445 * Z_OK on success.  Any other return value indicates failure.
2446 */
2447int
2448zonecfg_set_hostid(zone_dochandle_t handle, const char *hostidp)
2449{
2450	int err;
2451
2452	/*
2453	 * A NULL hostid string is interpreted as a request to clear the
2454	 * hostid.
2455	 */
2456	if (hostidp == NULL || (err = zonecfg_valid_hostid(hostidp)) == Z_OK)
2457		return (setrootattr(handle, DTD_ATTR_HOSTID, hostidp));
2458	return (err);
2459}
2460
2461int
2462zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2463{
2464	xmlNodePtr cur, firstmatch;
2465	int err;
2466	char match[MAXPATHLEN];
2467
2468	if (tabptr == NULL)
2469		return (Z_INVAL);
2470
2471	if ((err = operation_prep(handle)) != Z_OK)
2472		return (err);
2473
2474	cur = handle->zone_dh_cur;
2475	firstmatch = NULL;
2476	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2477		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2478			continue;
2479		if (strlen(tabptr->zone_dev_match) == 0)
2480			continue;
2481
2482		if ((fetchprop(cur, DTD_ATTR_MATCH, match,
2483		    sizeof (match)) == Z_OK)) {
2484			if (strcmp(tabptr->zone_dev_match,
2485			    match) == 0) {
2486				if (firstmatch == NULL)
2487					firstmatch = cur;
2488				else if (firstmatch != cur)
2489					return (Z_INSUFFICIENT_SPEC);
2490			} else {
2491				/*
2492				 * If another property matched but this
2493				 * one doesn't then reset firstmatch.
2494				 */
2495				if (firstmatch == cur)
2496					firstmatch = NULL;
2497			}
2498		}
2499	}
2500	if (firstmatch == NULL)
2501		return (Z_NO_RESOURCE_ID);
2502
2503	cur = firstmatch;
2504
2505	if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
2506	    sizeof (tabptr->zone_dev_match))) != Z_OK)
2507		return (err);
2508
2509	return (Z_OK);
2510}
2511
2512static int
2513zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
2514{
2515	xmlNodePtr newnode, cur = handle->zone_dh_cur;
2516	int err;
2517
2518	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL);
2519
2520	if ((err = newprop(newnode, DTD_ATTR_MATCH,
2521	    tabptr->zone_dev_match)) != Z_OK)
2522		return (err);
2523
2524	return (Z_OK);
2525}
2526
2527int
2528zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2529{
2530	int err;
2531
2532	if (tabptr == NULL)
2533		return (Z_INVAL);
2534
2535	if ((err = operation_prep(handle)) != Z_OK)
2536		return (err);
2537
2538	if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK)
2539		return (err);
2540
2541	return (Z_OK);
2542}
2543
2544static int
2545zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
2546{
2547	xmlNodePtr cur = handle->zone_dh_cur;
2548	int match_match;
2549
2550	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2551		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2552			continue;
2553
2554		match_match = match_prop(cur, DTD_ATTR_MATCH,
2555		    tabptr->zone_dev_match);
2556
2557		if (match_match) {
2558			xmlUnlinkNode(cur);
2559			xmlFreeNode(cur);
2560			return (Z_OK);
2561		}
2562	}
2563	return (Z_NO_RESOURCE_ID);
2564}
2565
2566int
2567zonecfg_delete_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2568{
2569	int err;
2570
2571	if (tabptr == NULL)
2572		return (Z_INVAL);
2573
2574	if ((err = operation_prep(handle)) != Z_OK)
2575		return (err);
2576
2577	if ((err = zonecfg_delete_dev_core(handle, tabptr)) != Z_OK)
2578		return (err);
2579
2580	return (Z_OK);
2581}
2582
2583int
2584zonecfg_modify_dev(
2585	zone_dochandle_t handle,
2586	struct zone_devtab *oldtabptr,
2587	struct zone_devtab *newtabptr)
2588{
2589	int err;
2590
2591	if (oldtabptr == NULL || newtabptr == NULL)
2592		return (Z_INVAL);
2593
2594	if ((err = operation_prep(handle)) != Z_OK)
2595		return (err);
2596
2597	if ((err = zonecfg_delete_dev_core(handle, oldtabptr)) != Z_OK)
2598		return (err);
2599
2600	if ((err = zonecfg_add_dev_core(handle, newtabptr)) != Z_OK)
2601		return (err);
2602
2603	return (Z_OK);
2604}
2605
2606static int
2607zonecfg_add_auth_core(zone_dochandle_t handle, struct zone_admintab *tabptr,
2608    char *zonename)
2609{
2610	xmlNodePtr newnode, cur = handle->zone_dh_cur;
2611	int err;
2612
2613	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ADMIN, NULL);
2614	err = newprop(newnode, DTD_ATTR_USER, tabptr->zone_admin_user);
2615	if (err != Z_OK)
2616		return (err);
2617	err = newprop(newnode, DTD_ATTR_AUTHS, tabptr->zone_admin_auths);
2618	if (err != Z_OK)
2619		return (err);
2620	if ((err = zonecfg_remove_userauths(
2621	    handle, tabptr->zone_admin_user, zonename, B_FALSE)) != Z_OK)
2622		return (err);
2623	return (Z_OK);
2624}
2625
2626int
2627zonecfg_add_admin(zone_dochandle_t handle, struct zone_admintab *tabptr,
2628    char *zonename)
2629{
2630	int err;
2631
2632	if (tabptr == NULL)
2633		return (Z_INVAL);
2634
2635	if ((err = operation_prep(handle)) != Z_OK)
2636		return (err);
2637
2638	if ((err = zonecfg_add_auth_core(handle, tabptr,
2639	    zonename)) != Z_OK)
2640		return (err);
2641
2642	return (Z_OK);
2643}
2644
2645static int
2646zonecfg_delete_auth_core(zone_dochandle_t handle, struct zone_admintab *tabptr,
2647    char *zonename)
2648{
2649	xmlNodePtr cur = handle->zone_dh_cur;
2650	boolean_t auth_match;
2651	int err;
2652
2653	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2654		if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
2655			continue;
2656		auth_match = match_prop(cur, DTD_ATTR_USER,
2657		    tabptr->zone_admin_user);
2658		if (auth_match) {
2659			if ((err = zonecfg_insert_userauths(
2660			    handle, tabptr->zone_admin_user,
2661			    zonename)) != Z_OK)
2662				return (err);
2663			xmlUnlinkNode(cur);
2664			xmlFreeNode(cur);
2665			return (Z_OK);
2666		}
2667	}
2668	return (Z_NO_RESOURCE_ID);
2669}
2670
2671int
2672zonecfg_delete_admin(zone_dochandle_t handle, struct zone_admintab *tabptr,
2673    char *zonename)
2674{
2675	int err;
2676
2677	if (tabptr == NULL)
2678		return (Z_INVAL);
2679
2680	if ((err = operation_prep(handle)) != Z_OK)
2681		return (err);
2682
2683	if ((err = zonecfg_delete_auth_core(handle, tabptr, zonename)) != Z_OK)
2684		return (err);
2685
2686	return (Z_OK);
2687}
2688
2689int
2690zonecfg_modify_admin(zone_dochandle_t handle, struct zone_admintab *oldtabptr,
2691    struct zone_admintab *newtabptr, char *zonename)
2692{
2693	int err;
2694
2695	if (oldtabptr == NULL || newtabptr == NULL)
2696		return (Z_INVAL);
2697
2698	if ((err = operation_prep(handle)) != Z_OK)
2699		return (err);
2700
2701	if ((err = zonecfg_delete_auth_core(handle, oldtabptr, zonename))
2702	    != Z_OK)
2703		return (err);
2704
2705	if ((err = zonecfg_add_auth_core(handle, newtabptr,
2706	    zonename)) != Z_OK)
2707		return (err);
2708
2709	return (Z_OK);
2710}
2711
2712int
2713zonecfg_lookup_admin(zone_dochandle_t handle, struct zone_admintab *tabptr)
2714{
2715	xmlNodePtr cur, firstmatch;
2716	int err;
2717	char user[MAXUSERNAME];
2718
2719	if (tabptr == NULL)
2720		return (Z_INVAL);
2721
2722	if ((err = operation_prep(handle)) != Z_OK)
2723		return (err);
2724
2725	cur = handle->zone_dh_cur;
2726	firstmatch = NULL;
2727	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2728		if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
2729			continue;
2730		if (strlen(tabptr->zone_admin_user) > 0) {
2731			if ((fetchprop(cur, DTD_ATTR_USER, user,
2732			    sizeof (user)) == Z_OK) &&
2733			    (strcmp(tabptr->zone_admin_user, user) == 0)) {
2734				if (firstmatch == NULL)
2735					firstmatch = cur;
2736				else
2737					return (Z_INSUFFICIENT_SPEC);
2738			}
2739		}
2740	}
2741	if (firstmatch == NULL)
2742		return (Z_NO_RESOURCE_ID);
2743
2744	cur = firstmatch;
2745
2746	if ((err = fetchprop(cur, DTD_ATTR_USER, tabptr->zone_admin_user,
2747	    sizeof (tabptr->zone_admin_user))) != Z_OK)
2748		return (err);
2749
2750	if ((err = fetchprop(cur, DTD_ATTR_AUTHS, tabptr->zone_admin_auths,
2751	    sizeof (tabptr->zone_admin_auths))) != Z_OK)
2752		return (err);
2753
2754	return (Z_OK);
2755}
2756
2757static int
2758zonecfg_add_secflags_core(zone_dochandle_t handle,
2759    struct zone_secflagstab *tabptr)
2760{
2761	xmlNodePtr newnode, cur = handle->zone_dh_cur;
2762	int err;
2763
2764	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_SECFLAGS, NULL);
2765	err = newprop(newnode, DTD_ATTR_DEFAULT, tabptr->zone_secflags_default);
2766	if (err != Z_OK)
2767		return (err);
2768	err = newprop(newnode, DTD_ATTR_LOWER, tabptr->zone_secflags_lower);
2769	if (err != Z_OK)
2770		return (err);
2771	err = newprop(newnode, DTD_ATTR_UPPER, tabptr->zone_secflags_upper);
2772	if (err != Z_OK)
2773		return (err);
2774
2775	return (Z_OK);
2776}
2777
2778int
2779zonecfg_add_secflags(zone_dochandle_t handle, struct zone_secflagstab *tabptr)
2780{
2781	int err;
2782
2783
2784	if (tabptr == NULL)
2785		return (Z_INVAL);
2786
2787	if ((err = operation_prep(handle)) != Z_OK)
2788		return (err);
2789
2790	if ((err = zonecfg_add_secflags_core(handle, tabptr)) != Z_OK)
2791		return (err);
2792
2793	return (Z_OK);
2794}
2795
2796static int
2797zonecfg_delete_secflags_core(zone_dochandle_t handle,
2798    struct zone_secflagstab *tabptr)
2799{
2800	xmlNodePtr cur = handle->zone_dh_cur;
2801	boolean_t def_match, low_match, up_match;
2802
2803	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2804		if (xmlStrcmp(cur->name, DTD_ELEM_SECFLAGS) != 0)
2805			continue;
2806
2807		def_match = match_prop(cur, DTD_ATTR_DEFAULT,
2808		    tabptr->zone_secflags_default);
2809		low_match = match_prop(cur, DTD_ATTR_LOWER,
2810		    tabptr->zone_secflags_lower);
2811		up_match = match_prop(cur, DTD_ATTR_UPPER,
2812		    tabptr->zone_secflags_upper);
2813
2814		if (def_match && low_match && up_match) {
2815			xmlUnlinkNode(cur);
2816			xmlFreeNode(cur);
2817			return (Z_OK);
2818		}
2819
2820	}
2821	return (Z_NO_RESOURCE_ID);
2822}
2823
2824int
2825zonecfg_delete_secflags(zone_dochandle_t handle,
2826    struct zone_secflagstab *tabptr)
2827{
2828	int err;
2829
2830	if (tabptr == NULL)
2831		return (Z_INVAL);
2832
2833	if ((err = operation_prep(handle)) != Z_OK)
2834		return (err);
2835
2836	if ((err = zonecfg_delete_secflags_core(handle, tabptr)) != Z_OK)
2837		return (err);
2838
2839	return (Z_OK);
2840}
2841
2842int
2843zonecfg_modify_secflags(zone_dochandle_t handle,
2844    struct zone_secflagstab *oldtabptr,
2845    struct zone_secflagstab *newtabptr)
2846{
2847	int err;
2848
2849	if (oldtabptr == NULL || newtabptr == NULL)
2850		return (Z_INVAL);
2851
2852	if ((err = operation_prep(handle)) != Z_OK)
2853		return (err);
2854
2855	if ((err = zonecfg_delete_secflags_core(handle, oldtabptr))
2856	    != Z_OK)
2857		return (err);
2858
2859	if ((err = zonecfg_add_secflags_core(handle, newtabptr)) != Z_OK)
2860		return (err);
2861
2862	return (Z_OK);
2863}
2864
2865int
2866zonecfg_lookup_secflags(zone_dochandle_t handle,
2867    struct zone_secflagstab *tabptr)
2868{
2869	xmlNodePtr cur;
2870	int err;
2871
2872	if (tabptr == NULL)
2873		return (Z_INVAL);
2874
2875	if ((err = operation_prep(handle)) != Z_OK)
2876		return (err);
2877
2878	cur = handle->zone_dh_cur;
2879
2880	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2881		if (xmlStrcmp(cur->name, DTD_ELEM_SECFLAGS) != 0)
2882			continue;
2883
2884		if ((err = fetchprop(cur, DTD_ATTR_DEFAULT,
2885		    tabptr->zone_secflags_default,
2886		    sizeof (tabptr->zone_secflags_default))) != Z_OK) {
2887			handle->zone_dh_cur = handle->zone_dh_top;
2888			return (err);
2889		}
2890
2891		if ((err = fetchprop(cur, DTD_ATTR_LOWER,
2892		    tabptr->zone_secflags_lower,
2893		    sizeof (tabptr->zone_secflags_lower))) != Z_OK) {
2894			handle->zone_dh_cur = handle->zone_dh_top;
2895			return (err);
2896		}
2897
2898		if ((err = fetchprop(cur, DTD_ATTR_UPPER,
2899		    tabptr->zone_secflags_upper,
2900		    sizeof (tabptr->zone_secflags_upper))) != Z_OK) {
2901			handle->zone_dh_cur = handle->zone_dh_top;
2902			return (err);
2903		}
2904
2905		return (Z_OK);
2906	}
2907
2908	return (Z_NO_ENTRY);
2909}
2910
2911/* Lock to serialize all devwalks */
2912static pthread_mutex_t zonecfg_devwalk_lock = PTHREAD_MUTEX_INITIALIZER;
2913/*
2914 * Global variables used to pass data from zonecfg_dev_manifest to the nftw
2915 * call-back (zonecfg_devwalk_cb).  g_devwalk_data is really the void*
2916 * parameter and g_devwalk_cb is really the *cb parameter from
2917 * zonecfg_dev_manifest.
2918 */
2919typedef struct __g_devwalk_data *g_devwalk_data_t;
2920static g_devwalk_data_t g_devwalk_data;
2921static int (*g_devwalk_cb)(const char *, uid_t, gid_t, mode_t, const char *,
2922    void *);
2923static size_t g_devwalk_skip_prefix;
2924
2925/*
2926 * zonecfg_dev_manifest call-back function used during detach to generate the
2927 * dev info in the manifest.
2928 */
2929static int
2930get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode,
2931    const char *acl, void *hdl)
2932{
2933	zone_dochandle_t handle = (zone_dochandle_t)hdl;
2934	xmlNodePtr newnode;
2935	xmlNodePtr cur;
2936	int err;
2937	char buf[128];
2938
2939	if ((err = operation_prep(handle)) != Z_OK)
2940		return (err);
2941
2942	cur = handle->zone_dh_cur;
2943	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL);
2944	if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK)
2945		return (err);
2946	(void) snprintf(buf, sizeof (buf), "%lu", uid);
2947	if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK)
2948		return (err);
2949	(void) snprintf(buf, sizeof (buf), "%lu", gid);
2950	if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK)
2951		return (err);
2952	(void) snprintf(buf, sizeof (buf), "%o", mode);
2953	if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK)
2954		return (err);
2955	if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK)
2956		return (err);
2957	return (Z_OK);
2958}
2959
2960/*
2961 * This is the nftw call-back function used by zonecfg_dev_manifest.  It is
2962 * responsible for calling the actual call-back.
2963 */
2964/* ARGSUSED2 */
2965static int
2966zonecfg_devwalk_cb(const char *path, const struct stat *st, int f,
2967    struct FTW *ftw)
2968{
2969	acl_t *acl;
2970	char *acl_txt = NULL;
2971
2972	/* skip all but character and block devices */
2973	if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode))
2974		return (0);
2975
2976	if ((acl_get(path, ACL_NO_TRIVIAL, &acl) == 0) &&
2977	    acl != NULL) {
2978		acl_txt = acl_totext(acl, ACL_NORESOLVE);
2979		acl_free(acl);
2980	}
2981
2982	if (strlen(path) <= g_devwalk_skip_prefix)
2983		return (0);
2984
2985	(void) g_devwalk_cb(path + g_devwalk_skip_prefix, st->st_uid,
2986	    st->st_gid, st->st_mode & S_IAMB, acl_txt != NULL ? acl_txt : "",
2987	    g_devwalk_data);
2988	free(acl_txt);
2989	return (0);
2990}
2991
2992/*
2993 * Walk the dev tree for the zone specified by hdl and call the
2994 * get_detach_dev_entry call-back function for each entry in the tree.  The
2995 * call-back will be passed the name, uid, gid, mode, acl string and the
2996 * handle input parameter for each dev entry.
2997 *
2998 * Data is passed to get_detach_dev_entry through the global variables
2999 * g_devwalk_data, *g_devwalk_cb, and g_devwalk_skip_prefix.  The
3000 * zonecfg_devwalk_cb function will actually call get_detach_dev_entry.
3001 */
3002int
3003zonecfg_dev_manifest(zone_dochandle_t hdl)
3004{
3005	char path[MAXPATHLEN];
3006	int ret;
3007
3008	if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK)
3009		return (ret);
3010
3011	if (strlcat(path, "/dev", sizeof (path)) >= sizeof (path))
3012		return (Z_TOO_BIG);
3013
3014	/*
3015	 * We have to serialize all devwalks in the same process
3016	 * (which should be fine), since nftw() is so badly designed.
3017	 */
3018	(void) pthread_mutex_lock(&zonecfg_devwalk_lock);
3019
3020	g_devwalk_skip_prefix = strlen(path) + 1;
3021	g_devwalk_data = (g_devwalk_data_t)hdl;
3022	g_devwalk_cb = get_detach_dev_entry;
3023	(void) nftw(path, zonecfg_devwalk_cb, 0, FTW_PHYS);
3024
3025	(void) pthread_mutex_unlock(&zonecfg_devwalk_lock);
3026	return (Z_OK);
3027}
3028
3029/*
3030 * Update the owner, group, mode and acl on the specified dev (inpath) for
3031 * the zone (hdl).  This function can be used to fix up the dev tree after
3032 * attaching a migrated zone.
3033 */
3034int
3035zonecfg_devperms_apply(zone_dochandle_t hdl, const char *inpath, uid_t owner,
3036    gid_t group, mode_t mode, const char *acltxt)
3037{
3038	int ret;
3039	char path[MAXPATHLEN];
3040	struct stat st;
3041	acl_t *aclp;
3042
3043	if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK)
3044		return (ret);
3045
3046	if (strlcat(path, "/dev/", sizeof (path)) >= sizeof (path))
3047		return (Z_TOO_BIG);
3048	if (strlcat(path, inpath, sizeof (path)) >= sizeof (path))
3049		return (Z_TOO_BIG);
3050
3051	if (stat(path, &st) == -1)
3052		return (Z_INVAL);
3053
3054	/* make sure we're only touching device nodes */
3055	if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode))
3056		return (Z_INVAL);
3057
3058	if (chown(path, owner, group) == -1)
3059		return (Z_SYSTEM);
3060
3061	if (chmod(path, mode) == -1)
3062		return (Z_SYSTEM);
3063
3064	if ((acltxt == NULL) || (strcmp(acltxt, "") == 0))
3065		return (Z_OK);
3066
3067	if (acl_fromtext(acltxt, &aclp) != 0) {
3068		errno = EINVAL;
3069		return (Z_SYSTEM);
3070	}
3071
3072	errno = 0;
3073	if (acl_set(path, aclp) == -1) {
3074		free(aclp);
3075		return (Z_SYSTEM);
3076	}
3077
3078	free(aclp);
3079	return (Z_OK);
3080}
3081
3082/*
3083 * This function finds everything mounted under a zone's rootpath.
3084 * This returns the number of mounts under rootpath, or -1 on error.
3085 * callback is called once per mount found with the first argument
3086 * pointing to a mnttab structure containing the mount's information.
3087 *
3088 * If the callback function returns non-zero zonecfg_find_mounts
3089 * aborts with an error.
3090 */
3091int
3092zonecfg_find_mounts(char *rootpath, int (*callback)(const struct mnttab *,
3093    void *), void *priv)
3094{
3095	FILE *mnttab;
3096	struct mnttab m;
3097	size_t l;
3098	int zfsl;
3099	int rv = 0;
3100	char zfs_path[MAXPATHLEN];
3101
3102	assert(rootpath != NULL);
3103
3104	if ((zfsl = snprintf(zfs_path, sizeof (zfs_path), "%s/.zfs/", rootpath))
3105	    >= sizeof (zfs_path))
3106		return (-1);
3107
3108	l = strlen(rootpath);
3109
3110	mnttab = fopen("/etc/mnttab", "r");
3111
3112	if (mnttab == NULL)
3113		return (-1);
3114
3115	if (ioctl(fileno(mnttab), MNTIOC_SHOWHIDDEN, NULL) < 0)  {
3116		rv = -1;
3117		goto out;
3118	}
3119
3120	while (!getmntent(mnttab, &m)) {
3121		if ((strncmp(rootpath, m.mnt_mountp, l) == 0) &&
3122		    (m.mnt_mountp[l] == '/') &&
3123		    (strncmp(zfs_path, m.mnt_mountp, zfsl) != 0)) {
3124			rv++;
3125			if (callback == NULL)
3126				continue;
3127			if (callback(&m, priv)) {
3128				rv = -1;
3129				goto out;
3130
3131			}
3132		}
3133	}
3134
3135out:
3136	(void) fclose(mnttab);
3137	return (rv);
3138}
3139
3140int
3141zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3142{
3143	xmlNodePtr cur, firstmatch;
3144	int err;
3145	char name[MAXNAMELEN], type[MAXNAMELEN], value[MAXNAMELEN];
3146
3147	if (tabptr == NULL)
3148		return (Z_INVAL);
3149
3150	if ((err = operation_prep(handle)) != Z_OK)
3151		return (err);
3152
3153	cur = handle->zone_dh_cur;
3154	firstmatch = NULL;
3155	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
3156		if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
3157			continue;
3158		if (strlen(tabptr->zone_attr_name) > 0) {
3159			if ((fetchprop(cur, DTD_ATTR_NAME, name,
3160			    sizeof (name)) == Z_OK) &&
3161			    (strcmp(tabptr->zone_attr_name, name) == 0)) {
3162				if (firstmatch == NULL)
3163					firstmatch = cur;
3164				else
3165					return (Z_INSUFFICIENT_SPEC);
3166			}
3167		}
3168		if (strlen(tabptr->zone_attr_type) > 0) {
3169			if ((fetchprop(cur, DTD_ATTR_TYPE, type,
3170			    sizeof (type)) == Z_OK)) {
3171				if (strcmp(tabptr->zone_attr_type, type) == 0) {
3172					if (firstmatch == NULL)
3173						firstmatch = cur;
3174					else if (firstmatch != cur)
3175						return (Z_INSUFFICIENT_SPEC);
3176				} else {
3177					/*
3178					 * If another property matched but this
3179					 * one doesn't then reset firstmatch.
3180					 */
3181					if (firstmatch == cur)
3182						firstmatch = NULL;
3183				}
3184			}
3185		}
3186		if (strlen(tabptr->zone_attr_value) > 0) {
3187			if ((fetchprop(cur, DTD_ATTR_VALUE, value,
3188			    sizeof (value)) == Z_OK)) {
3189				if (strcmp(tabptr->zone_attr_value, value) ==
3190				    0) {
3191					if (firstmatch == NULL)
3192						firstmatch = cur;
3193					else if (firstmatch != cur)
3194						return (Z_INSUFFICIENT_SPEC);
3195				} else {
3196					/*
3197					 * If another property matched but this
3198					 * one doesn't then reset firstmatch.
3199					 */
3200					if (firstmatch == cur)
3201						firstmatch = NULL;
3202				}
3203			}
3204		}
3205	}
3206	if (firstmatch == NULL)
3207		return (Z_NO_RESOURCE_ID);
3208
3209	cur = firstmatch;
3210
3211	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
3212	    sizeof (tabptr->zone_attr_name))) != Z_OK)
3213		return (err);
3214
3215	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
3216	    sizeof (tabptr->zone_attr_type))) != Z_OK)
3217		return (err);
3218
3219	if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
3220	    sizeof (tabptr->zone_attr_value))) != Z_OK)
3221		return (err);
3222
3223	return (Z_OK);
3224}
3225
3226static int
3227zonecfg_add_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3228{
3229	xmlNodePtr newnode, cur = handle->zone_dh_cur;
3230	int err;
3231
3232	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ATTR, NULL);
3233	err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_attr_name);
3234	if (err != Z_OK)
3235		return (err);
3236	err = newprop(newnode, DTD_ATTR_TYPE, tabptr->zone_attr_type);
3237	if (err != Z_OK)
3238		return (err);
3239	err = newprop(newnode, DTD_ATTR_VALUE, tabptr->zone_attr_value);
3240	if (err != Z_OK)
3241		return (err);
3242	return (Z_OK);
3243}
3244
3245int
3246zonecfg_add_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3247{
3248	int err;
3249
3250	if (tabptr == NULL)
3251		return (Z_INVAL);
3252
3253	if ((err = operation_prep(handle)) != Z_OK)
3254		return (err);
3255
3256	if ((err = zonecfg_add_attr_core(handle, tabptr)) != Z_OK)
3257		return (err);
3258
3259	return (Z_OK);
3260}
3261
3262static int
3263zonecfg_delete_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3264{
3265	xmlNodePtr cur = handle->zone_dh_cur;
3266	int name_match, type_match, value_match;
3267
3268	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
3269		if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
3270			continue;
3271
3272		name_match = match_prop(cur, DTD_ATTR_NAME,
3273		    tabptr->zone_attr_name);
3274		type_match = match_prop(cur, DTD_ATTR_TYPE,
3275		    tabptr->zone_attr_type);
3276		value_match = match_prop(cur, DTD_ATTR_VALUE,
3277		    tabptr->zone_attr_value);
3278
3279		if (name_match && type_match && value_match) {
3280			xmlUnlinkNode(cur);
3281			xmlFreeNode(cur);
3282			return (Z_OK);
3283		}
3284	}
3285	return (Z_NO_RESOURCE_ID);
3286}
3287
3288int
3289zonecfg_delete_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3290{
3291	int err;
3292
3293	if (tabptr == NULL)
3294		return (Z_INVAL);
3295
3296	if ((err = operation_prep(handle)) != Z_OK)
3297		return (err);
3298
3299	if ((err = zonecfg_delete_attr_core(handle, tabptr)) != Z_OK)
3300		return (err);
3301
3302	return (Z_OK);
3303}
3304
3305int
3306zonecfg_modify_attr(
3307	zone_dochandle_t handle,
3308	struct zone_attrtab *oldtabptr,
3309	struct zone_attrtab *newtabptr)
3310{
3311	int err;
3312
3313	if (oldtabptr == NULL || newtabptr == NULL)
3314		return (Z_INVAL);
3315
3316	if ((err = operation_prep(handle)) != Z_OK)
3317		return (err);
3318
3319	if ((err = zonecfg_delete_attr_core(handle, oldtabptr)) != Z_OK)
3320		return (err);
3321
3322	if ((err = zonecfg_add_attr_core(handle, newtabptr)) != Z_OK)
3323		return (err);
3324
3325	return (Z_OK);
3326}
3327
3328int
3329zonecfg_get_attr_boolean(const struct zone_attrtab *attr, boolean_t *value)
3330{
3331	if (attr == NULL)
3332		return (Z_INVAL);
3333
3334	if (strcmp(attr->zone_attr_type, DTD_ENTITY_BOOLEAN) != 0)
3335		return (Z_INVAL);
3336
3337	if (strcmp(attr->zone_attr_value, DTD_ENTITY_TRUE) == 0) {
3338		*value = B_TRUE;
3339		return (Z_OK);
3340	}
3341	if (strcmp(attr->zone_attr_value, DTD_ENTITY_FALSE) == 0) {
3342		*value = B_FALSE;
3343		return (Z_OK);
3344	}
3345	return (Z_INVAL);
3346}
3347
3348int
3349zonecfg_get_attr_int(const struct zone_attrtab *attr, int64_t *value)
3350{
3351	long long result;
3352	char *endptr;
3353
3354	if (attr == NULL)
3355		return (Z_INVAL);
3356
3357	if (strcmp(attr->zone_attr_type, DTD_ENTITY_INT) != 0)
3358		return (Z_INVAL);
3359
3360	errno = 0;
3361	result = strtoll(attr->zone_attr_value, &endptr, 10);
3362	if (errno != 0 || *endptr != '\0')
3363		return (Z_INVAL);
3364	*value = result;
3365	return (Z_OK);
3366}
3367
3368int
3369zonecfg_get_attr_string(const struct zone_attrtab *attr, char *value,
3370    size_t val_sz)
3371{
3372	if (attr == NULL)
3373		return (Z_INVAL);
3374
3375	if (strcmp(attr->zone_attr_type, DTD_ENTITY_STRING) != 0)
3376		return (Z_INVAL);
3377
3378	if (strlcpy(value, attr->zone_attr_value, val_sz) >= val_sz)
3379		return (Z_TOO_BIG);
3380	return (Z_OK);
3381}
3382
3383int
3384zonecfg_get_attr_uint(const struct zone_attrtab *attr, uint64_t *value)
3385{
3386	unsigned long long result;
3387	long long neg_result;
3388	char *endptr;
3389
3390	if (attr == NULL)
3391		return (Z_INVAL);
3392
3393	if (strcmp(attr->zone_attr_type, DTD_ENTITY_UINT) != 0)
3394		return (Z_INVAL);
3395
3396	errno = 0;
3397	result = strtoull(attr->zone_attr_value, &endptr, 10);
3398	if (errno != 0 || *endptr != '\0')
3399		return (Z_INVAL);
3400	errno = 0;
3401	neg_result = strtoll(attr->zone_attr_value, &endptr, 10);
3402	/*
3403	 * Incredibly, strtoull("<negative number>", ...) will not fail but
3404	 * return whatever (negative) number cast as a u_longlong_t, so we
3405	 * need to look for this here.
3406	 */
3407	if (errno == 0 && neg_result < 0)
3408		return (Z_INVAL);
3409	*value = result;
3410	return (Z_OK);
3411}
3412
3413int
3414zonecfg_lookup_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3415{
3416	xmlNodePtr cur, val;
3417	char savedname[MAXNAMELEN];
3418	struct zone_rctlvaltab *valptr;
3419	int err;
3420
3421	if (strlen(tabptr->zone_rctl_name) == 0)
3422		return (Z_INVAL);
3423
3424	if ((err = operation_prep(handle)) != Z_OK)
3425		return (err);
3426
3427	cur = handle->zone_dh_cur;
3428	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
3429		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL))
3430			continue;
3431		if ((fetchprop(cur, DTD_ATTR_NAME, savedname,
3432		    sizeof (savedname)) == Z_OK) &&
3433		    (strcmp(savedname, tabptr->zone_rctl_name) == 0)) {
3434			tabptr->zone_rctl_valptr = NULL;
3435			for (val = cur->xmlChildrenNode; val != NULL;
3436			    val = val->next) {
3437				valptr = (struct zone_rctlvaltab *)malloc(
3438				    sizeof (struct zone_rctlvaltab));
3439				if (valptr == NULL)
3440					return (Z_NOMEM);
3441				if ((fetchprop(val, DTD_ATTR_PRIV,
3442				    valptr->zone_rctlval_priv,
3443				    sizeof (valptr->zone_rctlval_priv)) !=
3444				    Z_OK))
3445					break;
3446				if ((fetchprop(val, DTD_ATTR_LIMIT,
3447				    valptr->zone_rctlval_limit,
3448				    sizeof (valptr->zone_rctlval_limit)) !=
3449				    Z_OK))
3450					break;
3451				if ((fetchprop(val, DTD_ATTR_ACTION,
3452				    valptr->zone_rctlval_action,
3453				    sizeof (valptr->zone_rctlval_action)) !=
3454				    Z_OK))
3455					break;
3456				if (zonecfg_add_rctl_value(tabptr, valptr) !=
3457				    Z_OK)
3458					break;
3459			}
3460			return (Z_OK);
3461		}
3462	}
3463	return (Z_NO_RESOURCE_ID);
3464}
3465
3466static int
3467zonecfg_add_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3468{
3469	xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode;
3470	struct zone_rctlvaltab *valptr;
3471	int err;
3472
3473	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_RCTL, NULL);
3474	err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_rctl_name);
3475	if (err != Z_OK)
3476		return (err);
3477	for (valptr = tabptr->zone_rctl_valptr; valptr != NULL;
3478	    valptr = valptr->zone_rctlval_next) {
3479		valnode = xmlNewTextChild(newnode, NULL,
3480		    DTD_ELEM_RCTLVALUE, NULL);
3481		err = newprop(valnode, DTD_ATTR_PRIV,
3482		    valptr->zone_rctlval_priv);
3483		if (err != Z_OK)
3484			return (err);
3485		err = newprop(valnode, DTD_ATTR_LIMIT,
3486		    valptr->zone_rctlval_limit);
3487		if (err != Z_OK)
3488			return (err);
3489		err = newprop(valnode, DTD_ATTR_ACTION,
3490		    valptr->zone_rctlval_action);
3491		if (err != Z_OK)
3492			return (err);
3493	}
3494	return (Z_OK);
3495}
3496
3497int
3498zonecfg_add_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3499{
3500	int err;
3501
3502	if (tabptr == NULL)
3503		return (Z_INVAL);
3504
3505	if ((err = operation_prep(handle)) != Z_OK)
3506		return (err);
3507
3508	if ((err = zonecfg_add_rctl_core(handle, tabptr)) != Z_OK)
3509		return (err);
3510
3511	return (Z_OK);
3512}
3513
3514static int
3515zonecfg_delete_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3516{
3517	xmlNodePtr cur = handle->zone_dh_cur;
3518	xmlChar *savedname;
3519	int name_result;
3520
3521	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
3522		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL))
3523			continue;
3524
3525		savedname = xmlGetProp(cur, DTD_ATTR_NAME);
3526		if (savedname == NULL)	/* shouldn't happen */
3527			continue;
3528		name_result = xmlStrcmp(savedname,
3529		    (const xmlChar *) tabptr->zone_rctl_name);
3530		xmlFree(savedname);
3531
3532		if (name_result == 0) {
3533			xmlUnlinkNode(cur);
3534			xmlFreeNode(cur);
3535			return (Z_OK);
3536		}
3537	}
3538	return (Z_NO_RESOURCE_ID);
3539}
3540
3541int
3542zonecfg_delete_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3543{
3544	int err;
3545
3546	if (tabptr == NULL)
3547		return (Z_INVAL);
3548
3549	if ((err = operation_prep(handle)) != Z_OK)
3550		return (err);
3551
3552	if ((err = zonecfg_delete_rctl_core(handle, tabptr)) != Z_OK)
3553		return (err);
3554
3555	return (Z_OK);
3556}
3557
3558int
3559zonecfg_modify_rctl(
3560	zone_dochandle_t handle,
3561	struct zone_rctltab *oldtabptr,
3562	struct zone_rctltab *newtabptr)
3563{
3564	int err;
3565
3566	if (oldtabptr == NULL || newtabptr == NULL)
3567		return (Z_INVAL);
3568
3569	if ((err = operation_prep(handle)) != Z_OK)
3570		return (err);
3571
3572	if ((err = zonecfg_delete_rctl_core(handle, oldtabptr)) != Z_OK)
3573		return (err);
3574
3575	if ((err = zonecfg_add_rctl_core(handle, newtabptr)) != Z_OK)
3576		return (err);
3577
3578	return (Z_OK);
3579}
3580
3581int
3582zonecfg_add_rctl_value(
3583	struct zone_rctltab *tabptr,
3584	struct zone_rctlvaltab *valtabptr)
3585{
3586	struct zone_rctlvaltab *last, *old, *new;
3587	rctlblk_t *rctlblk = alloca(rctlblk_size());
3588
3589	last = tabptr->zone_rctl_valptr;
3590	for (old = last; old != NULL; old = old->zone_rctlval_next)
3591		last = old;	/* walk to the end of the list */
3592	new = valtabptr;	/* alloc'd by caller */
3593	new->zone_rctlval_next = NULL;
3594	if (zonecfg_construct_rctlblk(valtabptr, rctlblk) != Z_OK)
3595		return (Z_INVAL);
3596	if (!zonecfg_valid_rctlblk(rctlblk))
3597		return (Z_INVAL);
3598	if (last == NULL)
3599		tabptr->zone_rctl_valptr = new;
3600	else
3601		last->zone_rctlval_next = new;
3602	return (Z_OK);
3603}
3604
3605int
3606zonecfg_remove_rctl_value(
3607	struct zone_rctltab *tabptr,
3608	struct zone_rctlvaltab *valtabptr)
3609{
3610	struct zone_rctlvaltab *last, *this, *next;
3611
3612	last = tabptr->zone_rctl_valptr;
3613	for (this = last; this != NULL; this = this->zone_rctlval_next) {
3614		if (strcmp(this->zone_rctlval_priv,
3615		    valtabptr->zone_rctlval_priv) == 0 &&
3616		    strcmp(this->zone_rctlval_limit,
3617		    valtabptr->zone_rctlval_limit) == 0 &&
3618		    strcmp(this->zone_rctlval_action,
3619		    valtabptr->zone_rctlval_action) == 0) {
3620			next = this->zone_rctlval_next;
3621			if (this == tabptr->zone_rctl_valptr)
3622				tabptr->zone_rctl_valptr = next;
3623			else
3624				last->zone_rctlval_next = next;
3625			free(this);
3626			return (Z_OK);
3627		} else
3628			last = this;
3629	}
3630	return (Z_NO_PROPERTY_ID);
3631}
3632
3633void
3634zonecfg_set_swinv(zone_dochandle_t handle)
3635{
3636	handle->zone_dh_sw_inv = B_TRUE;
3637}
3638
3639/*
3640 * Add the pkg to the sw inventory on the handle.
3641 */
3642int
3643zonecfg_add_pkg(zone_dochandle_t handle, char *name, char *version)
3644{
3645	xmlNodePtr newnode;
3646	xmlNodePtr cur;
3647	int err;
3648
3649	if ((err = operation_prep(handle)) != Z_OK)
3650		return (err);
3651
3652	cur = handle->zone_dh_cur;
3653	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL);
3654	if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK)
3655		return (err);
3656	if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK)
3657		return (err);
3658	return (Z_OK);
3659}
3660
3661char *
3662zonecfg_strerror(int errnum)
3663{
3664	switch (errnum) {
3665	case Z_OK:
3666		return (dgettext(TEXT_DOMAIN, "OK"));
3667	case Z_EMPTY_DOCUMENT:
3668		return (dgettext(TEXT_DOMAIN, "Empty document"));
3669	case Z_WRONG_DOC_TYPE:
3670		return (dgettext(TEXT_DOMAIN, "Wrong document type"));
3671	case Z_BAD_PROPERTY:
3672		return (dgettext(TEXT_DOMAIN, "Bad document property"));
3673	case Z_TEMP_FILE:
3674		return (dgettext(TEXT_DOMAIN,
3675		    "Problem creating temporary file"));
3676	case Z_SAVING_FILE:
3677		return (dgettext(TEXT_DOMAIN, "Problem saving file"));
3678	case Z_NO_ENTRY:
3679		return (dgettext(TEXT_DOMAIN, "No such entry"));
3680	case Z_BOGUS_ZONE_NAME:
3681		return (dgettext(TEXT_DOMAIN, "Bogus zone name"));
3682	case Z_REQD_RESOURCE_MISSING:
3683		return (dgettext(TEXT_DOMAIN, "Required resource missing"));
3684	case Z_REQD_PROPERTY_MISSING:
3685		return (dgettext(TEXT_DOMAIN, "Required property missing"));
3686	case Z_BAD_HANDLE:
3687		return (dgettext(TEXT_DOMAIN, "Bad handle"));
3688	case Z_NOMEM:
3689		return (dgettext(TEXT_DOMAIN, "Out of memory"));
3690	case Z_INVAL:
3691		return (dgettext(TEXT_DOMAIN, "Invalid argument"));
3692	case Z_ACCES:
3693		return (dgettext(TEXT_DOMAIN, "Permission denied"));
3694	case Z_TOO_BIG:
3695		return (dgettext(TEXT_DOMAIN, "Argument list too long"));
3696	case Z_MISC_FS:
3697		return (dgettext(TEXT_DOMAIN,
3698		    "Miscellaneous file system error"));
3699	case Z_NO_ZONE:
3700		return (dgettext(TEXT_DOMAIN, "No such zone configured"));
3701	case Z_NO_RESOURCE_TYPE:
3702		return (dgettext(TEXT_DOMAIN, "No such resource type"));
3703	case Z_NO_RESOURCE_ID:
3704		return (dgettext(TEXT_DOMAIN, "No such resource with that id"));
3705	case Z_NO_PROPERTY_TYPE:
3706		return (dgettext(TEXT_DOMAIN, "No such property type"));
3707	case Z_NO_PROPERTY_ID:
3708		return (dgettext(TEXT_DOMAIN, "No such property with that id"));
3709	case Z_BAD_ZONE_STATE:
3710		return (dgettext(TEXT_DOMAIN,
3711		    "Zone state is invalid for the requested operation"));
3712	case Z_INVALID_DOCUMENT:
3713		return (dgettext(TEXT_DOMAIN, "Invalid document"));
3714	case Z_NAME_IN_USE:
3715		return (dgettext(TEXT_DOMAIN, "Zone name already in use"));
3716	case Z_NO_SUCH_ID:
3717		return (dgettext(TEXT_DOMAIN, "No such zone ID"));
3718	case Z_UPDATING_INDEX:
3719		return (dgettext(TEXT_DOMAIN, "Problem updating index file"));
3720	case Z_LOCKING_FILE:
3721		return (dgettext(TEXT_DOMAIN, "Locking index file"));
3722	case Z_UNLOCKING_FILE:
3723		return (dgettext(TEXT_DOMAIN, "Unlocking index file"));
3724	case Z_INSUFFICIENT_SPEC:
3725		return (dgettext(TEXT_DOMAIN, "Insufficient specification"));
3726	case Z_RESOLVED_PATH:
3727		return (dgettext(TEXT_DOMAIN, "Resolved path mismatch"));
3728	case Z_IPV6_ADDR_PREFIX_LEN:
3729		return (dgettext(TEXT_DOMAIN,
3730		    "IPv6 address missing required prefix length"));
3731	case Z_BOGUS_ADDRESS:
3732		return (dgettext(TEXT_DOMAIN,
3733		    "Neither an IPv4 nor an IPv6 address nor a host name"));
3734	case Z_PRIV_PROHIBITED:
3735		return (dgettext(TEXT_DOMAIN,
3736		    "Specified privilege is prohibited"));
3737	case Z_PRIV_REQUIRED:
3738		return (dgettext(TEXT_DOMAIN,
3739		    "Required privilege is missing"));
3740	case Z_PRIV_UNKNOWN:
3741		return (dgettext(TEXT_DOMAIN,
3742		    "Specified privilege is unknown"));
3743	case Z_BRAND_ERROR:
3744		return (dgettext(TEXT_DOMAIN,
3745		    "Brand-specific error"));
3746	case Z_INCOMPATIBLE:
3747		return (dgettext(TEXT_DOMAIN, "Incompatible settings"));
3748	case Z_ALIAS_DISALLOW:
3749		return (dgettext(TEXT_DOMAIN,
3750		    "An incompatible rctl already exists for this property"));
3751	case Z_CLEAR_DISALLOW:
3752		return (dgettext(TEXT_DOMAIN,
3753		    "Clearing this property is not allowed"));
3754	case Z_POOL:
3755		return (dgettext(TEXT_DOMAIN, "libpool(3LIB) error"));
3756	case Z_POOLS_NOT_ACTIVE:
3757		return (dgettext(TEXT_DOMAIN, "Pools facility not active; "
3758		    "zone will not be bound to pool"));
3759	case Z_POOL_ENABLE:
3760		return (dgettext(TEXT_DOMAIN,
3761		    "Could not enable pools facility"));
3762	case Z_NO_POOL:
3763		return (dgettext(TEXT_DOMAIN,
3764		    "Pool not found; using default pool"));
3765	case Z_POOL_CREATE:
3766		return (dgettext(TEXT_DOMAIN,
3767		    "Could not create a temporary pool"));
3768	case Z_POOL_BIND:
3769		return (dgettext(TEXT_DOMAIN, "Could not bind zone to pool"));
3770	case Z_INVALID_PROPERTY:
3771		return (dgettext(TEXT_DOMAIN, "Specified property is invalid"));
3772	case Z_SYSTEM:
3773		return (strerror(errno));
3774	default:
3775		return (dgettext(TEXT_DOMAIN, "Unknown error"));
3776	}
3777}
3778
3779/*
3780 * Note that the zonecfg_setXent() and zonecfg_endXent() calls are all the
3781 * same, as they just turn around and call zonecfg_setent() / zonecfg_endent().
3782 */
3783
3784static int
3785zonecfg_setent(zone_dochandle_t handle)
3786{
3787	xmlNodePtr cur;
3788	int err;
3789
3790	if (handle == NULL)
3791		return (Z_INVAL);
3792
3793	if ((err = operation_prep(handle)) != Z_OK) {
3794		handle->zone_dh_cur = NULL;
3795		return (err);
3796	}
3797	cur = handle->zone_dh_cur;
3798	cur = cur->xmlChildrenNode;
3799	handle->zone_dh_cur = cur;
3800	return (Z_OK);
3801}
3802
3803static int
3804zonecfg_endent(zone_dochandle_t handle)
3805{
3806	if (handle == NULL)
3807		return (Z_INVAL);
3808
3809	handle->zone_dh_cur = handle->zone_dh_top;
3810	return (Z_OK);
3811}
3812
3813/*
3814 * Do the work required to manipulate a process through libproc.
3815 * If grab_process() returns no errors (0), then release_process()
3816 * must eventually be called.
3817 *
3818 * Return values:
3819 *      0 Successful creation of agent thread
3820 *      1 Error grabbing
3821 *      2 Error creating agent
3822 */
3823static int
3824grab_process(pr_info_handle_t *p)
3825{
3826	int ret;
3827
3828	if ((p->pr = Pgrab(p->pid, 0, &ret)) != NULL) {
3829
3830		if (Psetflags(p->pr, PR_RLC) != 0) {
3831			Prelease(p->pr, 0);
3832			return (1);
3833		}
3834		if (Pcreate_agent(p->pr) == 0) {
3835			return (0);
3836
3837		} else {
3838			Prelease(p->pr, 0);
3839			return (2);
3840		}
3841	} else {
3842		return (1);
3843	}
3844}
3845
3846/*
3847 * Release the specified process. This destroys the agent
3848 * and releases the process. If the process is NULL, nothing
3849 * is done. This function should only be called if grab_process()
3850 * has previously been called and returned success.
3851 *
3852 * This function is Pgrab-safe.
3853 */
3854static void
3855release_process(struct ps_prochandle *Pr)
3856{
3857	if (Pr == NULL)
3858		return;
3859
3860	Pdestroy_agent(Pr);
3861	Prelease(Pr, 0);
3862}
3863
3864static boolean_t
3865grab_zone_proc(char *zonename, pr_info_handle_t *p)
3866{
3867	DIR *dirp;
3868	struct dirent *dentp;
3869	zoneid_t zoneid;
3870	int pid_self;
3871	psinfo_t psinfo;
3872
3873	if (zone_get_id(zonename, &zoneid) != 0)
3874		return (B_FALSE);
3875
3876	pid_self = getpid();
3877
3878	if ((dirp = opendir("/proc")) == NULL)
3879		return (B_FALSE);
3880
3881	while (dentp = readdir(dirp)) {
3882		p->pid = atoi(dentp->d_name);
3883
3884		/* Skip self */
3885		if (p->pid == pid_self)
3886			continue;
3887
3888		if (proc_get_psinfo(p->pid, &psinfo) != 0)
3889			continue;
3890
3891		if (psinfo.pr_zoneid != zoneid)
3892			continue;
3893
3894		/* attempt to grab process */
3895		if (grab_process(p) != 0)
3896			continue;
3897
3898		if (pr_getzoneid(p->pr) != zoneid) {
3899			release_process(p->pr);
3900			continue;
3901		}
3902
3903		(void) closedir(dirp);
3904		return (B_TRUE);
3905	}
3906
3907	(void) closedir(dirp);
3908	return (B_FALSE);
3909}
3910
3911static boolean_t
3912get_priv_rctl(struct ps_prochandle *pr, char *name, rctlblk_t *rblk)
3913{
3914	if (pr_getrctl(pr, name, NULL, rblk, RCTL_FIRST))
3915		return (B_FALSE);
3916
3917	if (rctlblk_get_privilege(rblk) == RCPRIV_PRIVILEGED)
3918		return (B_TRUE);
3919
3920	while (pr_getrctl(pr, name, rblk, rblk, RCTL_NEXT) == 0) {
3921		if (rctlblk_get_privilege(rblk) == RCPRIV_PRIVILEGED)
3922			return (B_TRUE);
3923	}
3924
3925	return (B_FALSE);
3926}
3927
3928/*
3929 * Apply the current rctl settings to the specified, running zone.
3930 */
3931int
3932zonecfg_apply_rctls(char *zone_name, zone_dochandle_t handle)
3933{
3934	int err;
3935	int res = Z_OK;
3936	rctlblk_t *rblk;
3937	pr_info_handle_t p;
3938	struct zone_rctltab rctl;
3939
3940	if ((err = zonecfg_setrctlent(handle)) != Z_OK)
3941		return (err);
3942
3943	if ((rblk = (rctlblk_t *)malloc(rctlblk_size())) == NULL) {
3944		(void) zonecfg_endrctlent(handle);
3945		return (Z_NOMEM);
3946	}
3947
3948	if (!grab_zone_proc(zone_name, &p)) {
3949		(void) zonecfg_endrctlent(handle);
3950		free(rblk);
3951		return (Z_SYSTEM);
3952	}
3953
3954	while (zonecfg_getrctlent(handle, &rctl) == Z_OK) {
3955		char *rname;
3956		struct zone_rctlvaltab *valptr;
3957
3958		rname = rctl.zone_rctl_name;
3959
3960		/* first delete all current privileged settings for this rctl */
3961		while (get_priv_rctl(p.pr, rname, rblk)) {
3962			if (pr_setrctl(p.pr, rname, NULL, rblk, RCTL_DELETE) !=
3963			    0) {
3964				res = Z_SYSTEM;
3965				goto done;
3966			}
3967		}
3968
3969		/* now set each new value for the rctl */
3970		for (valptr = rctl.zone_rctl_valptr; valptr != NULL;
3971		    valptr = valptr->zone_rctlval_next) {
3972			if ((err = zonecfg_construct_rctlblk(valptr, rblk))
3973			    != Z_OK) {
3974				res = errno = err;
3975				goto done;
3976			}
3977
3978			if (pr_setrctl(p.pr, rname, NULL, rblk, RCTL_INSERT)) {
3979				res = Z_SYSTEM;
3980				goto done;
3981			}
3982		}
3983	}
3984
3985done:
3986	release_process(p.pr);
3987	free(rblk);
3988	(void) zonecfg_endrctlent(handle);
3989
3990	return (res);
3991}
3992
3993static const xmlChar *
3994nm_to_dtd(char *nm)
3995{
3996	if (strcmp(nm, "device") == 0)
3997		return (DTD_ELEM_DEVICE);
3998	if (strcmp(nm, "fs") == 0)
3999		return (DTD_ELEM_FS);
4000	if (strcmp(nm, "net") == 0)
4001		return (DTD_ELEM_NET);
4002	if (strcmp(nm, "attr") == 0)
4003		return (DTD_ELEM_ATTR);
4004	if (strcmp(nm, "rctl") == 0)
4005		return (DTD_ELEM_RCTL);
4006	if (strcmp(nm, "dataset") == 0)
4007		return (DTD_ELEM_DATASET);
4008	if (strcmp(nm, "admin") == 0)
4009		return (DTD_ELEM_ADMIN);
4010
4011	return (NULL);
4012}
4013
4014int
4015zonecfg_num_resources(zone_dochandle_t handle, char *rsrc)
4016{
4017	int num = 0;
4018	const xmlChar *dtd;
4019	xmlNodePtr cur;
4020
4021	if ((dtd = nm_to_dtd(rsrc)) == NULL)
4022		return (num);
4023
4024	if (zonecfg_setent(handle) != Z_OK)
4025		return (num);
4026
4027	for (cur = handle->zone_dh_cur; cur != NULL; cur = cur->next)
4028		if (xmlStrcmp(cur->name, dtd) == 0)
4029			num++;
4030
4031	(void) zonecfg_endent(handle);
4032
4033	return (num);
4034}
4035
4036int
4037zonecfg_del_all_resources(zone_dochandle_t handle, char *rsrc)
4038{
4039	int err;
4040	const xmlChar *dtd;
4041	xmlNodePtr cur;
4042
4043	if ((dtd = nm_to_dtd(rsrc)) == NULL)
4044		return (Z_NO_RESOURCE_TYPE);
4045
4046	if ((err = zonecfg_setent(handle)) != Z_OK)
4047		return (err);
4048
4049	cur = handle->zone_dh_cur;
4050	while (cur != NULL) {
4051		xmlNodePtr tmp;
4052
4053		if (xmlStrcmp(cur->name, dtd)) {
4054			cur = cur->next;
4055			continue;
4056		}
4057
4058		tmp = cur->next;
4059		xmlUnlinkNode(cur);
4060		xmlFreeNode(cur);
4061		cur = tmp;
4062	}
4063
4064	(void) zonecfg_endent(handle);
4065	return (Z_OK);
4066}
4067
4068static boolean_t
4069valid_uint(char *s, uint64_t *n)
4070{
4071	char *endp;
4072
4073	/* strtoull accepts '-'?! so we want to flag that as an error */
4074	if (strchr(s, '-') != NULL)
4075		return (B_FALSE);
4076
4077	errno = 0;
4078	*n = strtoull(s, &endp, 10);
4079
4080	if (errno != 0 || *endp != '\0')
4081		return (B_FALSE);
4082	return (B_TRUE);
4083}
4084
4085/*
4086 * Convert a string representing a number (possibly a fraction) into an integer.
4087 * The string can have a modifier (K, M, G or T).   The modifiers are treated
4088 * as powers of two (not 10).
4089 */
4090int
4091zonecfg_str_to_bytes(char *str, uint64_t *bytes)
4092{
4093	long double val;
4094	char *unitp;
4095	uint64_t scale;
4096
4097	if ((val = strtold(str, &unitp)) < 0)
4098		return (-1);
4099
4100	/* remove any leading white space from units string */
4101	while (isspace(*unitp) != 0)
4102		++unitp;
4103
4104	/* if no units explicitly set, error */
4105	if (unitp == NULL || *unitp == '\0') {
4106		scale = 1;
4107	} else {
4108		int i;
4109		char *units[] = {"K", "M", "G", "T", NULL};
4110
4111		scale = 1024;
4112
4113		/* update scale based on units */
4114		for (i = 0; units[i] != NULL; i++) {
4115			if (strcasecmp(unitp, units[i]) == 0)
4116				break;
4117			scale <<= 10;
4118		}
4119
4120		if (units[i] == NULL)
4121			return (-1);
4122	}
4123
4124	*bytes = (uint64_t)(val * scale);
4125	return (0);
4126}
4127
4128boolean_t
4129zonecfg_valid_ncpus(char *lowstr, char *highstr)
4130{
4131	uint64_t low, high;
4132
4133	if (!valid_uint(lowstr, &low) || !valid_uint(highstr, &high) ||
4134	    low < 1 || low > high)
4135		return (B_FALSE);
4136
4137	return (B_TRUE);
4138}
4139
4140boolean_t
4141zonecfg_valid_importance(char *impstr)
4142{
4143	uint64_t num;
4144
4145	if (!valid_uint(impstr, &num))
4146		return (B_FALSE);
4147
4148	return (B_TRUE);
4149}
4150
4151boolean_t
4152zonecfg_valid_alias_limit(char *name, char *limitstr, uint64_t *limit)
4153{
4154	int i;
4155
4156	for (i = 0; aliases[i].shortname != NULL; i++)
4157		if (strcmp(name, aliases[i].shortname) == 0)
4158			break;
4159
4160	if (aliases[i].shortname == NULL)
4161		return (B_FALSE);
4162
4163	if (!valid_uint(limitstr, limit) || *limit < aliases[i].low_limit)
4164		return (B_FALSE);
4165
4166	return (B_TRUE);
4167}
4168
4169boolean_t
4170zonecfg_valid_memlimit(char *memstr, uint64_t *mem_val)
4171{
4172	if (zonecfg_str_to_bytes(memstr, mem_val) != 0)
4173		return (B_FALSE);
4174
4175	return (B_TRUE);
4176}
4177
4178static int
4179zerr_pool(char *pool_err, int err_size, int res)
4180{
4181	(void) strlcpy(pool_err, pool_strerror(pool_error()), err_size);
4182	return (res);
4183}
4184
4185static int
4186create_tmp_pset(char *pool_err, int err_size, pool_conf_t *pconf, pool_t *pool,
4187    char *name, int min, int max)
4188{
4189	pool_resource_t *res;
4190	pool_elem_t *elem;
4191	pool_value_t *val;
4192
4193	if ((res = pool_resource_create(pconf, "pset", name)) == NULL)
4194		return (zerr_pool(pool_err, err_size, Z_POOL));
4195
4196	if (pool_associate(pconf, pool, res) != PO_SUCCESS)
4197		return (zerr_pool(pool_err, err_size, Z_POOL));
4198
4199	if ((elem = pool_resource_to_elem(pconf, res)) == NULL)
4200		return (zerr_pool(pool_err, err_size, Z_POOL));
4201
4202	if ((val = pool_value_alloc()) == NULL)
4203		return (zerr_pool(pool_err, err_size, Z_POOL));
4204
4205	/* set the maximum number of cpus for the pset */
4206	pool_value_set_uint64(val, (uint64_t)max);
4207
4208	if (pool_put_property(pconf, elem, "pset.max", val) != PO_SUCCESS) {
4209		pool_value_free(val);
4210		return (zerr_pool(pool_err, err_size, Z_POOL));
4211	}
4212
4213	/* set the minimum number of cpus for the pset */
4214	pool_value_set_uint64(val, (uint64_t)min);
4215
4216	if (pool_put_property(pconf, elem, "pset.min", val) != PO_SUCCESS) {
4217		pool_value_free(val);
4218		return (zerr_pool(pool_err, err_size, Z_POOL));
4219	}
4220
4221	pool_value_free(val);
4222
4223	return (Z_OK);
4224}
4225
4226static int
4227create_tmp_pool(char *pool_err, int err_size, pool_conf_t *pconf, char *name,
4228    struct zone_psettab *pset_tab)
4229{
4230	pool_t *pool;
4231	int res = Z_OK;
4232
4233	/* create a temporary pool configuration */
4234	if (pool_conf_open(pconf, NULL, PO_TEMP) != PO_SUCCESS) {
4235		res = zerr_pool(pool_err, err_size, Z_POOL);
4236		return (res);
4237	}
4238
4239	if ((pool = pool_create(pconf, name)) == NULL) {
4240		res = zerr_pool(pool_err, err_size, Z_POOL_CREATE);
4241		goto done;
4242	}
4243
4244	/* set pool importance */
4245	if (pset_tab->zone_importance[0] != '\0') {
4246		pool_elem_t *elem;
4247		pool_value_t *val;
4248
4249		if ((elem = pool_to_elem(pconf, pool)) == NULL) {
4250			res = zerr_pool(pool_err, err_size, Z_POOL);
4251			goto done;
4252		}
4253
4254		if ((val = pool_value_alloc()) == NULL) {
4255			res = zerr_pool(pool_err, err_size, Z_POOL);
4256			goto done;
4257		}
4258
4259		pool_value_set_int64(val,
4260		    (int64_t)atoi(pset_tab->zone_importance));
4261
4262		if (pool_put_property(pconf, elem, "pool.importance", val)
4263		    != PO_SUCCESS) {
4264			res = zerr_pool(pool_err, err_size, Z_POOL);
4265			pool_value_free(val);
4266			goto done;
4267		}
4268
4269		pool_value_free(val);
4270	}
4271
4272	if ((res = create_tmp_pset(pool_err, err_size, pconf, pool, name,
4273	    atoi(pset_tab->zone_ncpu_min),
4274	    atoi(pset_tab->zone_ncpu_max))) != Z_OK)
4275		goto done;
4276
4277	/* validation */
4278	if (pool_conf_status(pconf) == POF_INVALID) {
4279		res = zerr_pool(pool_err, err_size, Z_POOL);
4280		goto done;
4281	}
4282
4283	/*
4284	 * This validation is the one we expect to fail if the user specified
4285	 * an invalid configuration (too many cpus) for this system.
4286	 */
4287	if (pool_conf_validate(pconf, POV_RUNTIME) != PO_SUCCESS) {
4288		res = zerr_pool(pool_err, err_size, Z_POOL_CREATE);
4289		goto done;
4290	}
4291
4292	/*
4293	 * Commit the dynamic configuration but not the pool configuration
4294	 * file.
4295	 */
4296	if (pool_conf_commit(pconf, 1) != PO_SUCCESS)
4297		res = zerr_pool(pool_err, err_size, Z_POOL);
4298
4299done:
4300	(void) pool_conf_close(pconf);
4301	return (res);
4302}
4303
4304static int
4305get_running_tmp_pset(pool_conf_t *pconf, pool_t *pool, pool_resource_t *pset,
4306    struct zone_psettab *pset_tab)
4307{
4308	int nfound = 0;
4309	pool_elem_t *pe;
4310	pool_value_t *pv = pool_value_alloc();
4311	uint64_t val_uint;
4312
4313	if (pool != NULL) {
4314		pe = pool_to_elem(pconf, pool);
4315		if (pool_get_property(pconf, pe, "pool.importance", pv)
4316		    != POC_INVAL) {
4317			int64_t val_int;
4318
4319			(void) pool_value_get_int64(pv, &val_int);
4320			(void) snprintf(pset_tab->zone_importance,
4321			    sizeof (pset_tab->zone_importance), "%d", val_int);
4322			nfound++;
4323		}
4324	}
4325
4326	if (pset != NULL) {
4327		pe = pool_resource_to_elem(pconf, pset);
4328		if (pool_get_property(pconf, pe, "pset.min", pv) != POC_INVAL) {
4329			(void) pool_value_get_uint64(pv, &val_uint);
4330			(void) snprintf(pset_tab->zone_ncpu_min,
4331			    sizeof (pset_tab->zone_ncpu_min), "%u", val_uint);
4332			nfound++;
4333		}
4334
4335		if (pool_get_property(pconf, pe, "pset.max", pv) != POC_INVAL) {
4336			(void) pool_value_get_uint64(pv, &val_uint);
4337			(void) snprintf(pset_tab->zone_ncpu_max,
4338			    sizeof (pset_tab->zone_ncpu_max), "%u", val_uint);
4339			nfound++;
4340		}
4341	}
4342
4343	pool_value_free(pv);
4344
4345	if (nfound == 3)
4346		return (PO_SUCCESS);
4347
4348	return (PO_FAIL);
4349}
4350
4351/*
4352 * Determine if a tmp pool is configured and if so, if the configuration is
4353 * still valid or if it has been changed since the tmp pool was created.
4354 * If the tmp pool configuration is no longer valid, delete the tmp pool.
4355 *
4356 * Set *valid=B_TRUE if there is an existing, valid tmp pool configuration.
4357 */
4358static int
4359verify_del_tmp_pool(pool_conf_t *pconf, char *tmp_name, char *pool_err,
4360    int err_size, struct zone_psettab *pset_tab, boolean_t *exists)
4361{
4362	int res = Z_OK;
4363	pool_t *pool;
4364	pool_resource_t *pset;
4365	struct zone_psettab pset_current;
4366
4367	*exists = B_FALSE;
4368
4369	if (pool_conf_open(pconf, pool_dynamic_location(), PO_RDWR)
4370	    != PO_SUCCESS) {
4371		res = zerr_pool(pool_err, err_size, Z_POOL);
4372		return (res);
4373	}
4374
4375	pool = pool_get_pool(pconf, tmp_name);
4376	pset = pool_get_resource(pconf, "pset", tmp_name);
4377
4378	if (pool == NULL && pset == NULL) {
4379		/* no tmp pool configured */
4380		goto done;
4381	}
4382
4383	/*
4384	 * If an existing tmp pool for this zone is configured with the proper
4385	 * settings, then the tmp pool is valid.
4386	 */
4387	if (get_running_tmp_pset(pconf, pool, pset, &pset_current)
4388	    == PO_SUCCESS &&
4389	    strcmp(pset_tab->zone_ncpu_min,
4390	    pset_current.zone_ncpu_min) == 0 &&
4391	    strcmp(pset_tab->zone_ncpu_max,
4392	    pset_current.zone_ncpu_max) == 0 &&
4393	    strcmp(pset_tab->zone_importance,
4394	    pset_current.zone_importance) == 0) {
4395		*exists = B_TRUE;
4396
4397	} else {
4398		/*
4399		 * An out-of-date tmp pool configuration exists.  Delete it
4400		 * so that we can create the correct tmp pool config.
4401		 */
4402		if (pset != NULL &&
4403		    pool_resource_destroy(pconf, pset) != PO_SUCCESS) {
4404			res = zerr_pool(pool_err, err_size, Z_POOL);
4405			goto done;
4406		}
4407
4408		if (pool != NULL &&
4409		    pool_destroy(pconf, pool) != PO_SUCCESS) {
4410			res = zerr_pool(pool_err, err_size, Z_POOL);
4411			goto done;
4412		}
4413
4414		/* commit dynamic config */
4415		if (pool_conf_commit(pconf, 0) != PO_SUCCESS)
4416			res = zerr_pool(pool_err, err_size, Z_POOL);
4417	}
4418
4419done:
4420	(void) pool_conf_close(pconf);
4421
4422	return (res);
4423}
4424
4425/*
4426 * Destroy any existing tmp pool.
4427 */
4428int
4429zonecfg_destroy_tmp_pool(char *zone_name, char *pool_err, int err_size)
4430{
4431	int status;
4432	int res = Z_OK;
4433	pool_conf_t *pconf;
4434	pool_t *pool;
4435	pool_resource_t *pset;
4436	char tmp_name[MAX_TMP_POOL_NAME];
4437
4438	/* if pools not enabled then nothing to do */
4439	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
4440		return (Z_OK);
4441
4442	if ((pconf = pool_conf_alloc()) == NULL)
4443		return (zerr_pool(pool_err, err_size, Z_POOL));
4444
4445	(void) snprintf(tmp_name, sizeof (tmp_name), TMP_POOL_NAME, zone_name);
4446
4447	if (pool_conf_open(pconf, pool_dynamic_location(), PO_RDWR)
4448	    != PO_SUCCESS) {
4449		res = zerr_pool(pool_err, err_size, Z_POOL);
4450		pool_conf_free(pconf);
4451		return (res);
4452	}
4453
4454	pool = pool_get_pool(pconf, tmp_name);
4455	pset = pool_get_resource(pconf, "pset", tmp_name);
4456
4457	if (pool == NULL && pset == NULL) {
4458		/* nothing to destroy, we're done */
4459		goto done;
4460	}
4461
4462	if (pset != NULL && pool_resource_destroy(pconf, pset) != PO_SUCCESS) {
4463		res = zerr_pool(pool_err, err_size, Z_POOL);
4464		goto done;
4465	}
4466
4467	if (pool != NULL && pool_destroy(pconf, pool) != PO_SUCCESS) {
4468		res = zerr_pool(pool_err, err_size, Z_POOL);
4469		goto done;
4470	}
4471
4472	/* commit dynamic config */
4473	if (pool_conf_commit(pconf, 0) != PO_SUCCESS)
4474		res = zerr_pool(pool_err, err_size, Z_POOL);
4475
4476done:
4477	(void) pool_conf_close(pconf);
4478	pool_conf_free(pconf);
4479
4480	return (res);
4481}
4482
4483/*
4484 * Attempt to bind to a tmp pool for this zone.  If there is no tmp pool
4485 * configured, we just return Z_OK.
4486 *
4487 * We either attempt to create the tmp pool for this zone or rebind to an
4488 * existing tmp pool for this zone.
4489 *
4490 * Rebinding is used when a zone with a tmp pool reboots so that we don't have
4491 * to recreate the tmp pool.  To do this we need to be sure we work correctly
4492 * for the following cases:
4493 *
4494 *	- there is an existing, properly configured tmp pool.
4495 *	- zonecfg added tmp pool after zone was booted, must now create.
4496 *	- zonecfg updated tmp pool config after zone was booted, in this case
4497 *	  we destroy the old tmp pool and create a new one.
4498 */
4499int
4500zonecfg_bind_tmp_pool(zone_dochandle_t handle, zoneid_t zoneid, char *pool_err,
4501    int err_size)
4502{
4503	struct zone_psettab pset_tab;
4504	int err;
4505	int status;
4506	pool_conf_t *pconf;
4507	boolean_t exists;
4508	char zone_name[ZONENAME_MAX];
4509	char tmp_name[MAX_TMP_POOL_NAME];
4510
4511	(void) getzonenamebyid(zoneid, zone_name, sizeof (zone_name));
4512
4513	err = zonecfg_lookup_pset(handle, &pset_tab);
4514
4515	/* if no temporary pool configured, we're done */
4516	if (err == Z_NO_ENTRY)
4517		return (Z_OK);
4518
4519	/*
4520	 * importance might not have a value but we need to validate it here,
4521	 * so set the default.
4522	 */
4523	if (pset_tab.zone_importance[0] == '\0')
4524		(void) strlcpy(pset_tab.zone_importance, "1",
4525		    sizeof (pset_tab.zone_importance));
4526
4527	/* if pools not enabled, enable them now */
4528	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) {
4529		if (pool_set_status(POOL_ENABLED) != PO_SUCCESS)
4530			return (Z_POOL_ENABLE);
4531	}
4532
4533	if ((pconf = pool_conf_alloc()) == NULL)
4534		return (zerr_pool(pool_err, err_size, Z_POOL));
4535
4536	(void) snprintf(tmp_name, sizeof (tmp_name), TMP_POOL_NAME, zone_name);
4537
4538	/*
4539	 * Check if a valid tmp pool/pset already exists.  If so, we just
4540	 * reuse it.
4541	 */
4542	if ((err = verify_del_tmp_pool(pconf, tmp_name, pool_err, err_size,
4543	    &pset_tab, &exists)) != Z_OK) {
4544		pool_conf_free(pconf);
4545		return (err);
4546	}
4547
4548	if (!exists)
4549		err = create_tmp_pool(pool_err, err_size, pconf, tmp_name,
4550		    &pset_tab);
4551
4552	pool_conf_free(pconf);
4553
4554	if (err != Z_OK)
4555		return (err);
4556
4557	/* Bind the zone to the pool. */
4558	if (pool_set_binding(tmp_name, P_ZONEID, zoneid) != PO_SUCCESS)
4559		return (zerr_pool(pool_err, err_size, Z_POOL_BIND));
4560
4561	return (Z_OK);
4562}
4563
4564/*
4565 * Attempt to bind to a permanent pool for this zone.  If there is no
4566 * permanent pool configured, we just return Z_OK.
4567 */
4568int
4569zonecfg_bind_pool(zone_dochandle_t handle, zoneid_t zoneid, char *pool_err,
4570    int err_size)
4571{
4572	pool_conf_t *poolconf;
4573	pool_t *pool;
4574	char poolname[MAXPATHLEN];
4575	int status;
4576	int error;
4577
4578	/*
4579	 * Find the pool mentioned in the zone configuration, and bind to it.
4580	 */
4581	error = zonecfg_get_pool(handle, poolname, sizeof (poolname));
4582	if (error == Z_NO_ENTRY || (error == Z_OK && strlen(poolname) == 0)) {
4583		/*
4584		 * The property is not set on the zone, so the pool
4585		 * should be bound to the default pool.  But that's
4586		 * already done by the kernel, so we can just return.
4587		 */
4588		return (Z_OK);
4589	}
4590	if (error != Z_OK) {
4591		/*
4592		 * Not an error, even though it shouldn't be happening.
4593		 */
4594		return (Z_OK);
4595	}
4596	/*
4597	 * Don't do anything if pools aren't enabled.
4598	 */
4599	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
4600		return (Z_POOLS_NOT_ACTIVE);
4601
4602	/*
4603	 * Try to provide a sane error message if the requested pool doesn't
4604	 * exist.
4605	 */
4606	if ((poolconf = pool_conf_alloc()) == NULL)
4607		return (zerr_pool(pool_err, err_size, Z_POOL));
4608
4609	if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) !=
4610	    PO_SUCCESS) {
4611		pool_conf_free(poolconf);
4612		return (zerr_pool(pool_err, err_size, Z_POOL));
4613	}
4614	pool = pool_get_pool(poolconf, poolname);
4615	(void) pool_conf_close(poolconf);
4616	pool_conf_free(poolconf);
4617	if (pool == NULL)
4618		return (Z_NO_POOL);
4619
4620	/*
4621	 * Bind the zone to the pool.
4622	 */
4623	if (pool_set_binding(poolname, P_ZONEID, zoneid) != PO_SUCCESS) {
4624		/* if bind fails, return poolname for the error msg */
4625		(void) strlcpy(pool_err, poolname, err_size);
4626		return (Z_POOL_BIND);
4627	}
4628
4629	return (Z_OK);
4630}
4631
4632int
4633zonecfg_get_poolname(zone_dochandle_t handle, char *zone, char *pool,
4634    size_t poolsize)
4635{
4636	int err;
4637	struct zone_psettab pset_tab;
4638
4639	err = zonecfg_lookup_pset(handle, &pset_tab);
4640	if ((err != Z_NO_ENTRY) && (err != Z_OK))
4641		return (err);
4642
4643	/* pset was found so a temporary pool was created */
4644	if (err == Z_OK) {
4645		(void) snprintf(pool, poolsize, TMP_POOL_NAME, zone);
4646		return (Z_OK);
4647	}
4648
4649	/* lookup the poolname in zonecfg */
4650	return (zonecfg_get_pool(handle, pool, poolsize));
4651}
4652
4653static boolean_t
4654svc_enabled(char *svc_name)
4655{
4656	scf_simple_prop_t	*prop;
4657	boolean_t		found = B_FALSE;
4658
4659	prop = scf_simple_prop_get(NULL, svc_name, SCF_PG_GENERAL,
4660	    SCF_PROPERTY_ENABLED);
4661
4662	if (scf_simple_prop_numvalues(prop) == 1 &&
4663	    *scf_simple_prop_next_boolean(prop) != 0)
4664		found = B_TRUE;
4665
4666	scf_simple_prop_free(prop);
4667
4668	return (found);
4669}
4670
4671/*
4672 * If the zone has capped-memory, make sure the rcap service is enabled.
4673 */
4674int
4675zonecfg_enable_rcapd(char *err, int size)
4676{
4677	if (!svc_enabled(RCAP_SERVICE) &&
4678	    smf_enable_instance(RCAP_SERVICE, 0) == -1) {
4679		(void) strlcpy(err, scf_strerror(scf_error()), size);
4680		return (Z_SYSTEM);
4681	}
4682
4683	return (Z_OK);
4684}
4685
4686/*
4687 * Return true if pset has cpu range specified and poold is not enabled.
4688 */
4689boolean_t
4690zonecfg_warn_poold(zone_dochandle_t handle)
4691{
4692	struct zone_psettab pset_tab;
4693	int min, max;
4694	int err;
4695
4696	err = zonecfg_lookup_pset(handle, &pset_tab);
4697
4698	/* if no temporary pool configured, we're done */
4699	if (err == Z_NO_ENTRY)
4700		return (B_FALSE);
4701
4702	min = atoi(pset_tab.zone_ncpu_min);
4703	max = atoi(pset_tab.zone_ncpu_max);
4704
4705	/* range not specified, no need for poold */
4706	if (min == max)
4707		return (B_FALSE);
4708
4709	/* we have a range, check if poold service is enabled */
4710	if (svc_enabled(POOLD_SERVICE))
4711		return (B_FALSE);
4712
4713	return (B_TRUE);
4714}
4715
4716/*
4717 * Retrieve the specified pool's thread scheduling class.  'poolname' must
4718 * refer to the name of a configured resource pool.  The thread scheduling
4719 * class specified by the pool will be stored in the buffer to which 'class'
4720 * points.  'clsize' is the byte size of the buffer to which 'class' points.
4721 *
4722 * This function returns Z_OK if it successfully stored the specified pool's
4723 * thread scheduling class into the buffer to which 'class' points.  It returns
4724 * Z_NO_POOL if resource pools are not enabled, the function is unable to
4725 * access the system's resource pools configuration, or the specified pool
4726 * does not exist.  The function returns Z_TOO_BIG if the buffer to which
4727 * 'class' points is not large enough to contain the thread scheduling class'
4728 * name.  The function returns Z_NO_ENTRY if the pool does not specify a thread
4729 * scheduling class.
4730 */
4731static int
4732get_pool_sched_class(char *poolname, char *class, int clsize)
4733{
4734	int status;
4735	pool_conf_t *poolconf;
4736	pool_t *pool;
4737	pool_elem_t *pe;
4738	pool_value_t *pv = pool_value_alloc();
4739	const char *sched_str;
4740
4741	if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
4742		return (Z_NO_POOL);
4743
4744	if ((poolconf = pool_conf_alloc()) == NULL)
4745		return (Z_NO_POOL);
4746
4747	if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) !=
4748	    PO_SUCCESS) {
4749		pool_conf_free(poolconf);
4750		return (Z_NO_POOL);
4751	}
4752
4753	if ((pool = pool_get_pool(poolconf, poolname)) == NULL) {
4754		(void) pool_conf_close(poolconf);
4755		pool_conf_free(poolconf);
4756		return (Z_NO_POOL);
4757	}
4758
4759	pe = pool_to_elem(poolconf, pool);
4760	if (pool_get_property(poolconf, pe, "pool.scheduler", pv) !=
4761	    POC_STRING) {
4762		(void) pool_conf_close(poolconf);
4763		pool_conf_free(poolconf);
4764		return (Z_NO_ENTRY);
4765	}
4766	(void) pool_value_get_string(pv, &sched_str);
4767	(void) pool_conf_close(poolconf);
4768	pool_conf_free(poolconf);
4769	if (strlcpy(class, sched_str, clsize) >= clsize)
4770		return (Z_TOO_BIG);
4771	return (Z_OK);
4772}
4773
4774/*
4775 * Get the default scheduling class for the zone.  This will either be the
4776 * class set on the zone's pool or the system default scheduling class.
4777 */
4778int
4779zonecfg_get_dflt_sched_class(zone_dochandle_t handle, char *class, int clsize)
4780{
4781	char poolname[MAXPATHLEN];
4782
4783	if (zonecfg_get_pool(handle, poolname, sizeof (poolname)) == Z_OK) {
4784		/* check if the zone's pool specified a sched class */
4785		if (get_pool_sched_class(poolname, class, clsize) == Z_OK)
4786			return (Z_OK);
4787	}
4788
4789	if (priocntl(0, 0, PC_GETDFLCL, class, (uint64_t)clsize) == -1)
4790		return (Z_TOO_BIG);
4791
4792	return (Z_OK);
4793}
4794
4795int
4796zonecfg_setfsent(zone_dochandle_t handle)
4797{
4798	return (zonecfg_setent(handle));
4799}
4800
4801int
4802zonecfg_getfsent(zone_dochandle_t handle, struct zone_fstab *tabptr)
4803{
4804	xmlNodePtr cur, options;
4805	char options_str[MAX_MNTOPT_STR];
4806	int err;
4807
4808	if (handle == NULL)
4809		return (Z_INVAL);
4810
4811	if ((cur = handle->zone_dh_cur) == NULL)
4812		return (Z_NO_ENTRY);
4813
4814	for (; cur != NULL; cur = cur->next)
4815		if (!xmlStrcmp(cur->name, DTD_ELEM_FS))
4816			break;
4817	if (cur == NULL) {
4818		handle->zone_dh_cur = handle->zone_dh_top;
4819		return (Z_NO_ENTRY);
4820	}
4821
4822	if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
4823	    sizeof (tabptr->zone_fs_special))) != Z_OK) {
4824		handle->zone_dh_cur = handle->zone_dh_top;
4825		return (err);
4826	}
4827
4828	if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
4829	    sizeof (tabptr->zone_fs_raw))) != Z_OK) {
4830		handle->zone_dh_cur = handle->zone_dh_top;
4831		return (err);
4832	}
4833
4834	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
4835	    sizeof (tabptr->zone_fs_dir))) != Z_OK) {
4836		handle->zone_dh_cur = handle->zone_dh_top;
4837		return (err);
4838	}
4839
4840	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
4841	    sizeof (tabptr->zone_fs_type))) != Z_OK) {
4842		handle->zone_dh_cur = handle->zone_dh_top;
4843		return (err);
4844	}
4845
4846	/* OK for options to be NULL */
4847	tabptr->zone_fs_options = NULL;
4848	for (options = cur->xmlChildrenNode; options != NULL;
4849	    options = options->next) {
4850		if (fetchprop(options, DTD_ATTR_NAME, options_str,
4851		    sizeof (options_str)) != Z_OK)
4852			break;
4853		if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
4854			break;
4855	}
4856
4857	handle->zone_dh_cur = cur->next;
4858	return (Z_OK);
4859}
4860
4861int
4862zonecfg_endfsent(zone_dochandle_t handle)
4863{
4864	return (zonecfg_endent(handle));
4865}
4866
4867int
4868zonecfg_setnwifent(zone_dochandle_t handle)
4869{
4870	return (zonecfg_setent(handle));
4871}
4872
4873int
4874zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
4875{
4876	xmlNodePtr cur;
4877	int err;
4878
4879	if (handle == NULL)
4880		return (Z_INVAL);
4881
4882	if ((cur = handle->zone_dh_cur) == NULL)
4883		return (Z_NO_ENTRY);
4884
4885	for (; cur != NULL; cur = cur->next)
4886		if (!xmlStrcmp(cur->name, DTD_ELEM_NET))
4887			break;
4888	if (cur == NULL) {
4889		handle->zone_dh_cur = handle->zone_dh_top;
4890		return (Z_NO_ENTRY);
4891	}
4892
4893	if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
4894	    sizeof (tabptr->zone_nwif_address))) != Z_OK) {
4895		handle->zone_dh_cur = handle->zone_dh_top;
4896		return (err);
4897	}
4898
4899	if ((err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
4900	    tabptr->zone_nwif_allowed_address,
4901	    sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK) {
4902		handle->zone_dh_cur = handle->zone_dh_top;
4903		return (err);
4904	}
4905
4906	if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
4907	    sizeof (tabptr->zone_nwif_physical))) != Z_OK) {
4908		handle->zone_dh_cur = handle->zone_dh_top;
4909		return (err);
4910	}
4911
4912	if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
4913	    tabptr->zone_nwif_defrouter,
4914	    sizeof (tabptr->zone_nwif_defrouter))) != Z_OK) {
4915		handle->zone_dh_cur = handle->zone_dh_top;
4916		return (err);
4917	}
4918
4919	handle->zone_dh_cur = cur->next;
4920	return (Z_OK);
4921}
4922
4923int
4924zonecfg_endnwifent(zone_dochandle_t handle)
4925{
4926	return (zonecfg_endent(handle));
4927}
4928
4929int
4930zonecfg_setdevent(zone_dochandle_t handle)
4931{
4932	return (zonecfg_setent(handle));
4933}
4934
4935int
4936zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr)
4937{
4938	xmlNodePtr cur;
4939	int err;
4940
4941	if (handle == NULL)
4942		return (Z_INVAL);
4943
4944	if ((cur = handle->zone_dh_cur) == NULL)
4945		return (Z_NO_ENTRY);
4946
4947	for (; cur != NULL; cur = cur->next)
4948		if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
4949			break;
4950	if (cur == NULL) {
4951		handle->zone_dh_cur = handle->zone_dh_top;
4952		return (Z_NO_ENTRY);
4953	}
4954
4955	if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
4956	    sizeof (tabptr->zone_dev_match))) != Z_OK) {
4957		handle->zone_dh_cur = handle->zone_dh_top;
4958		return (err);
4959	}
4960
4961	handle->zone_dh_cur = cur->next;
4962	return (Z_OK);
4963}
4964
4965int
4966zonecfg_enddevent(zone_dochandle_t handle)
4967{
4968	return (zonecfg_endent(handle));
4969}
4970
4971int
4972zonecfg_setrctlent(zone_dochandle_t handle)
4973{
4974	return (zonecfg_setent(handle));
4975}
4976
4977int
4978zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr)
4979{
4980	xmlNodePtr cur, val;
4981	struct zone_rctlvaltab *valptr;
4982	int err;
4983
4984	if (handle == NULL)
4985		return (Z_INVAL);
4986
4987	if ((cur = handle->zone_dh_cur) == NULL)
4988		return (Z_NO_ENTRY);
4989
4990	for (; cur != NULL; cur = cur->next)
4991		if (!xmlStrcmp(cur->name, DTD_ELEM_RCTL))
4992			break;
4993	if (cur == NULL) {
4994		handle->zone_dh_cur = handle->zone_dh_top;
4995		return (Z_NO_ENTRY);
4996	}
4997
4998	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_rctl_name,
4999	    sizeof (tabptr->zone_rctl_name))) != Z_OK) {
5000		handle->zone_dh_cur = handle->zone_dh_top;
5001		return (err);
5002	}
5003
5004	tabptr->zone_rctl_valptr = NULL;
5005	for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
5006		valptr = (struct zone_rctlvaltab *)malloc(
5007		    sizeof (struct zone_rctlvaltab));
5008		if (valptr == NULL)
5009			return (Z_NOMEM);
5010		if (fetchprop(val, DTD_ATTR_PRIV, valptr->zone_rctlval_priv,
5011		    sizeof (valptr->zone_rctlval_priv)) != Z_OK)
5012			break;
5013		if (fetchprop(val, DTD_ATTR_LIMIT, valptr->zone_rctlval_limit,
5014		    sizeof (valptr->zone_rctlval_limit)) != Z_OK)
5015			break;
5016		if (fetchprop(val, DTD_ATTR_ACTION, valptr->zone_rctlval_action,
5017		    sizeof (valptr->zone_rctlval_action)) != Z_OK)
5018			break;
5019		if (zonecfg_add_rctl_value(tabptr, valptr) != Z_OK)
5020			break;
5021	}
5022
5023	handle->zone_dh_cur = cur->next;
5024	return (Z_OK);
5025}
5026
5027int
5028zonecfg_endrctlent(zone_dochandle_t handle)
5029{
5030	return (zonecfg_endent(handle));
5031}
5032
5033int
5034zonecfg_setattrent(zone_dochandle_t handle)
5035{
5036	return (zonecfg_setent(handle));
5037}
5038
5039int
5040zonecfg_getattrent(zone_dochandle_t handle, struct zone_attrtab *tabptr)
5041{
5042	xmlNodePtr cur;
5043	int err;
5044
5045	if (handle == NULL)
5046		return (Z_INVAL);
5047
5048	if ((cur = handle->zone_dh_cur) == NULL)
5049		return (Z_NO_ENTRY);
5050
5051	for (; cur != NULL; cur = cur->next)
5052		if (!xmlStrcmp(cur->name, DTD_ELEM_ATTR))
5053			break;
5054	if (cur == NULL) {
5055		handle->zone_dh_cur = handle->zone_dh_top;
5056		return (Z_NO_ENTRY);
5057	}
5058
5059	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
5060	    sizeof (tabptr->zone_attr_name))) != Z_OK) {
5061		handle->zone_dh_cur = handle->zone_dh_top;
5062		return (err);
5063	}
5064
5065	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
5066	    sizeof (tabptr->zone_attr_type))) != Z_OK) {
5067		handle->zone_dh_cur = handle->zone_dh_top;
5068		return (err);
5069	}
5070
5071	if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
5072	    sizeof (tabptr->zone_attr_value))) != Z_OK) {
5073		handle->zone_dh_cur = handle->zone_dh_top;
5074		return (err);
5075	}
5076
5077	handle->zone_dh_cur = cur->next;
5078	return (Z_OK);
5079}
5080
5081int
5082zonecfg_endattrent(zone_dochandle_t handle)
5083{
5084	return (zonecfg_endent(handle));
5085}
5086
5087int
5088zonecfg_setadminent(zone_dochandle_t handle)
5089{
5090	return (zonecfg_setent(handle));
5091}
5092
5093int
5094zonecfg_getadminent(zone_dochandle_t handle, struct zone_admintab *tabptr)
5095{
5096	xmlNodePtr cur;
5097	int err;
5098
5099	if (handle == NULL)
5100		return (Z_INVAL);
5101
5102	if ((cur = handle->zone_dh_cur) == NULL)
5103		return (Z_NO_ENTRY);
5104
5105	for (; cur != NULL; cur = cur->next)
5106		if (!xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
5107			break;
5108	if (cur == NULL) {
5109		handle->zone_dh_cur = handle->zone_dh_top;
5110		return (Z_NO_ENTRY);
5111	}
5112
5113	if ((err = fetchprop(cur, DTD_ATTR_USER, tabptr->zone_admin_user,
5114	    sizeof (tabptr->zone_admin_user))) != Z_OK) {
5115		handle->zone_dh_cur = handle->zone_dh_top;
5116		return (err);
5117	}
5118
5119
5120	if ((err = fetchprop(cur, DTD_ATTR_AUTHS, tabptr->zone_admin_auths,
5121	    sizeof (tabptr->zone_admin_auths))) != Z_OK) {
5122		handle->zone_dh_cur = handle->zone_dh_top;
5123		return (err);
5124	}
5125
5126	handle->zone_dh_cur = cur->next;
5127	return (Z_OK);
5128}
5129
5130int
5131zonecfg_endadminent(zone_dochandle_t handle)
5132{
5133	return (zonecfg_endent(handle));
5134}
5135
5136/*
5137 * The privileges available on the system and described in privileges(5)
5138 * fall into four categories with respect to non-global zones:
5139 *
5140 *      Default set of privileges considered safe for all non-global
5141 *      zones.  These privileges are "safe" in the sense that a
5142 *      privileged process in the zone cannot affect processes in any
5143 *      other zone on the system.
5144 *
5145 *      Set of privileges not currently permitted within a non-global
5146 *      zone.  These privileges are considered by default, "unsafe,"
5147 *      and include ones which affect global resources (such as the
5148 *      system clock or physical memory) or are overly broad and cover
5149 *      more than one mechanism in the system.  In other cases, there
5150 *      has not been sufficient virtualization in the parts of the
5151 *      system the privilege covers to allow its use within a
5152 *      non-global zone.
5153 *
5154 *      Set of privileges required in order to get a zone booted and
5155 *      init(1M) started.  These cannot be removed from the zone's
5156 *      privilege set.
5157 *
5158 * All other privileges are optional and are potentially useful for
5159 * processes executing inside a non-global zone.
5160 *
5161 * When privileges are added to the system, a determination needs to be
5162 * made as to which category the privilege belongs to.  Ideally,
5163 * privileges should be fine-grained enough and the mechanisms they cover
5164 * virtualized enough so that they can be made available to non-global
5165 * zones.
5166 */
5167
5168/*
5169 * Define some of the tokens that priv_str_to_set(3C) recognizes.  Since
5170 * the privilege string separator can be any character, although it is
5171 * usually a comma character, define these here as well in the event that
5172 * they change or are augmented in the future.
5173 */
5174#define	BASIC_TOKEN		"basic"
5175#define	DEFAULT_TOKEN		"default"
5176#define	ZONE_TOKEN		"zone"
5177#define	TOKEN_PRIV_CHAR		','
5178#define	TOKEN_PRIV_STR		","
5179
5180typedef struct priv_node {
5181	struct priv_node	*pn_next;	/* Next privilege */
5182	char			*pn_priv;	/* Privileges name */
5183} priv_node_t;
5184
5185/* Privileges lists can differ across brands */
5186typedef struct priv_lists {
5187	/* Privileges considered safe for all non-global zones of a brand */
5188	struct priv_node	*pl_default;
5189
5190	/* Privileges not permitted for all non-global zones of a brand */
5191	struct priv_node	*pl_prohibited;
5192
5193	/* Privileges required for all non-global zones of a brand */
5194	struct priv_node	*pl_required;
5195
5196	/*
5197	 * ip-type of the zone these privileges lists apply to.
5198	 * It is used to pass ip-type to the callback function,
5199	 * priv_lists_cb, which has no way of getting the ip-type.
5200	 */
5201	const char		*pl_iptype;
5202} priv_lists_t;
5203
5204static int
5205priv_lists_cb(void *data, priv_iter_t *priv_iter)
5206{
5207	priv_lists_t *plp = (priv_lists_t *)data;
5208	priv_node_t *pnp;
5209
5210	/* Skip this privilege if ip-type does not match */
5211	if ((strcmp(priv_iter->pi_iptype, "all") != 0) &&
5212	    (strcmp(priv_iter->pi_iptype, plp->pl_iptype) != 0))
5213		return (0);
5214
5215	/* Allocate a new priv list node. */
5216	if ((pnp = malloc(sizeof (*pnp))) == NULL)
5217		return (-1);
5218	if ((pnp->pn_priv = strdup(priv_iter->pi_name)) == NULL) {
5219		free(pnp);
5220		return (-1);
5221	}
5222
5223	/* Insert the new priv list node into the right list */
5224	if (strcmp(priv_iter->pi_set, "default") == 0) {
5225		pnp->pn_next = plp->pl_default;
5226		plp->pl_default = pnp;
5227	} else if (strcmp(priv_iter->pi_set, "prohibited") == 0) {
5228		pnp->pn_next = plp->pl_prohibited;
5229		plp->pl_prohibited = pnp;
5230	} else if (strcmp(priv_iter->pi_set, "required") == 0) {
5231		pnp->pn_next = plp->pl_required;
5232		plp->pl_required = pnp;
5233	} else {
5234		free(pnp->pn_priv);
5235		free(pnp);
5236		return (-1);
5237	}
5238	return (0);
5239}
5240
5241static void
5242priv_lists_destroy(priv_lists_t *plp)
5243{
5244	priv_node_t *pnp;
5245
5246	assert(plp != NULL);
5247
5248	while ((pnp = plp->pl_default) != NULL) {
5249		plp->pl_default = pnp->pn_next;
5250		free(pnp->pn_priv);
5251		free(pnp);
5252	}
5253	while ((pnp = plp->pl_prohibited) != NULL) {
5254		plp->pl_prohibited = pnp->pn_next;
5255		free(pnp->pn_priv);
5256		free(pnp);
5257	}
5258	while ((pnp = plp->pl_required) != NULL) {
5259		plp->pl_required = pnp->pn_next;
5260		free(pnp->pn_priv);
5261		free(pnp);
5262	}
5263	free(plp);
5264}
5265
5266static int
5267priv_lists_create(zone_dochandle_t handle, char *brand, priv_lists_t **plpp,
5268    const char *curr_iptype)
5269{
5270	priv_lists_t *plp;
5271	brand_handle_t bh;
5272	char brand_str[MAXNAMELEN];
5273
5274	/* handle or brand must be set, but never both */
5275	assert((handle != NULL) || (brand != NULL));
5276	assert((handle == NULL) || (brand == NULL));
5277
5278	if (handle != NULL) {
5279		brand = brand_str;
5280		if (zonecfg_get_brand(handle, brand, sizeof (brand_str)) != 0)
5281			return (Z_BRAND_ERROR);
5282	}
5283
5284	if ((bh = brand_open(brand)) == NULL)
5285		return (Z_BRAND_ERROR);
5286
5287	if ((plp = calloc(1, sizeof (priv_lists_t))) == NULL) {
5288		brand_close(bh);
5289		return (Z_NOMEM);
5290	}
5291
5292	plp->pl_iptype = curr_iptype;
5293
5294	/* construct the privilege lists */
5295	if (brand_config_iter_privilege(bh, priv_lists_cb, plp) != 0) {
5296		priv_lists_destroy(plp);
5297		brand_close(bh);
5298		return (Z_BRAND_ERROR);
5299	}
5300
5301	brand_close(bh);
5302	*plpp = plp;
5303	return (Z_OK);
5304}
5305
5306static int
5307get_default_privset(priv_set_t *privs, priv_lists_t *plp)
5308{
5309	priv_node_t *pnp;
5310	priv_set_t *basic;
5311
5312	basic = priv_str_to_set(BASIC_TOKEN, TOKEN_PRIV_STR, NULL);
5313	if (basic == NULL)
5314		return (errno == ENOMEM ? Z_NOMEM : Z_INVAL);
5315
5316	priv_union(basic, privs);
5317	priv_freeset(basic);
5318
5319	for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) {
5320		if (priv_addset(privs, pnp->pn_priv) != 0)
5321			return (Z_INVAL);
5322	}
5323
5324	return (Z_OK);
5325}
5326
5327int
5328zonecfg_default_brand(char *brand, size_t brandsize)
5329{
5330	zone_dochandle_t handle;
5331	int myzoneid = getzoneid();
5332	int ret;
5333
5334	/*
5335	 * If we're running within a zone, then the default brand is the
5336	 * current zone's brand.
5337	 */
5338	if (myzoneid != GLOBAL_ZONEID) {
5339		ret = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brand, brandsize);
5340		if (ret < 0)
5341			return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL);
5342		return (Z_OK);
5343	}
5344
5345	if ((handle = zonecfg_init_handle()) == NULL)
5346		return (Z_NOMEM);
5347	if ((ret = zonecfg_get_handle("SUNWdefault", handle)) == Z_OK) {
5348		ret = i_zonecfg_get_brand(handle, brand, brandsize, B_TRUE);
5349		zonecfg_fini_handle(handle);
5350		return (ret);
5351	}
5352	return (ret);
5353}
5354
5355int
5356zonecfg_default_privset(priv_set_t *privs, const char *curr_iptype)
5357{
5358	priv_lists_t *plp;
5359	char buf[MAXNAMELEN];
5360	int ret;
5361
5362	if ((ret = zonecfg_default_brand(buf, sizeof (buf))) != Z_OK)
5363		return (ret);
5364	if ((ret = priv_lists_create(NULL, buf, &plp, curr_iptype)) != Z_OK)
5365		return (ret);
5366	ret = get_default_privset(privs, plp);
5367	priv_lists_destroy(plp);
5368	return (ret);
5369}
5370
5371void
5372append_priv_token(char *priv, char *str, size_t strlen)
5373{
5374	if (*str != '\0')
5375		(void) strlcat(str, TOKEN_PRIV_STR, strlen);
5376	(void) strlcat(str, priv, strlen);
5377}
5378
5379/*
5380 * Verify that the supplied string is a valid privilege limit set for a
5381 * non-global zone.  This string must not only be acceptable to
5382 * priv_str_to_set(3C) which parses it, but it also must resolve to a
5383 * privilege set that includes certain required privileges and lacks
5384 * certain prohibited privileges.
5385 */
5386static int
5387verify_privset(char *privbuf, priv_set_t *privs, char **privname,
5388    boolean_t add_default, priv_lists_t *plp)
5389{
5390	priv_node_t *pnp;
5391	char *tmp, *cp, *lasts;
5392	size_t len;
5393	priv_set_t *mergeset;
5394	const char *token;
5395
5396	/*
5397	 * The verification of the privilege string occurs in several
5398	 * phases.  In the first phase, the supplied string is scanned for
5399	 * the ZONE_TOKEN token which is not support as part of the
5400	 * "limitpriv" property.
5401	 *
5402	 * Duplicate the supplied privilege string since strtok_r(3C)
5403	 * tokenizes its input by null-terminating the tokens.
5404	 */
5405	if ((tmp = strdup(privbuf)) == NULL)
5406		return (Z_NOMEM);
5407	for (cp = strtok_r(tmp, TOKEN_PRIV_STR, &lasts); cp != NULL;
5408	    cp = strtok_r(NULL, TOKEN_PRIV_STR, &lasts)) {
5409		if (strcmp(cp, ZONE_TOKEN) == 0) {
5410			free(tmp);
5411			if ((*privname = strdup(ZONE_TOKEN)) == NULL)
5412				return (Z_NOMEM);
5413			else
5414				return (Z_PRIV_UNKNOWN);
5415		}
5416	}
5417	free(tmp);
5418
5419	if (add_default) {
5420		/*
5421		 * If DEFAULT_TOKEN was specified, a string needs to be
5422		 * built containing the privileges from the default, safe
5423		 * set along with those of the "limitpriv" property.
5424		 */
5425		len = strlen(privbuf) + sizeof (BASIC_TOKEN) + 2;
5426
5427		for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next)
5428			len += strlen(pnp->pn_priv) + 1;
5429		tmp = alloca(len);
5430		*tmp = '\0';
5431
5432		append_priv_token(BASIC_TOKEN, tmp, len);
5433		for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next)
5434			append_priv_token(pnp->pn_priv, tmp, len);
5435		(void) strlcat(tmp, TOKEN_PRIV_STR, len);
5436		(void) strlcat(tmp, privbuf, len);
5437	} else {
5438		tmp = privbuf;
5439	}
5440
5441
5442	/*
5443	 * In the next phase, attempt to convert the merged privilege
5444	 * string into a privilege set.  In the case of an error, either
5445	 * there was a memory allocation failure or there was an invalid
5446	 * privilege token in the string.  In either case, return an
5447	 * appropriate error code but in the event of an invalid token,
5448	 * allocate a string containing its name and return that back to
5449	 * the caller.
5450	 */
5451	mergeset = priv_str_to_set(tmp, TOKEN_PRIV_STR, &token);
5452	if (mergeset == NULL) {
5453		if (token == NULL)
5454			return (Z_NOMEM);
5455		if ((cp = strchr(token, TOKEN_PRIV_CHAR)) != NULL)
5456			*cp = '\0';
5457		if ((*privname = strdup(token)) == NULL)
5458			return (Z_NOMEM);
5459		else
5460			return (Z_PRIV_UNKNOWN);
5461	}
5462
5463	/*
5464	 * Next, verify that none of the prohibited zone privileges are
5465	 * present in the merged privilege set.
5466	 */
5467	for (pnp = plp->pl_prohibited; pnp != NULL; pnp = pnp->pn_next) {
5468		if (priv_ismember(mergeset, pnp->pn_priv)) {
5469			priv_freeset(mergeset);
5470			if ((*privname = strdup(pnp->pn_priv)) == NULL)
5471				return (Z_NOMEM);
5472			else
5473				return (Z_PRIV_PROHIBITED);
5474		}
5475	}
5476
5477	/*
5478	 * Finally, verify that all of the required zone privileges are
5479	 * present in the merged privilege set.
5480	 */
5481	for (pnp = plp->pl_required; pnp != NULL; pnp = pnp->pn_next) {
5482		if (!priv_ismember(mergeset, pnp->pn_priv)) {
5483			priv_freeset(mergeset);
5484			if ((*privname = strdup(pnp->pn_priv)) == NULL)
5485				return (Z_NOMEM);
5486			else
5487				return (Z_PRIV_REQUIRED);
5488		}
5489	}
5490
5491	priv_copyset(mergeset, privs);
5492	priv_freeset(mergeset);
5493	return (Z_OK);
5494}
5495
5496/*
5497 * Fill in the supplied privilege set with either the default, safe set of
5498 * privileges suitable for a non-global zone, or one based on the
5499 * "limitpriv" property in the zone's configuration.
5500 *
5501 * In the event of an invalid privilege specification in the
5502 * configuration, a string is allocated and returned containing the
5503 * "privilege" causing the issue.  It is the caller's responsibility to
5504 * free this memory when it is done with it.
5505 */
5506int
5507zonecfg_get_privset(zone_dochandle_t handle, priv_set_t *privs,
5508    char **privname)
5509{
5510	priv_lists_t *plp;
5511	char *cp, *limitpriv = NULL;
5512	int err, limitlen;
5513	zone_iptype_t iptype;
5514	const char *curr_iptype;
5515
5516	/*
5517	 * Attempt to lookup the "limitpriv" property.  If it does not
5518	 * exist or matches the string DEFAULT_TOKEN exactly, then the
5519	 * default, safe privilege set is returned.
5520	 */
5521	if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) != Z_OK)
5522		return (err);
5523
5524	if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK)
5525		return (err);
5526
5527	switch (iptype) {
5528	case ZS_SHARED:
5529		curr_iptype = "shared";
5530		break;
5531	case ZS_EXCLUSIVE:
5532		curr_iptype = "exclusive";
5533		break;
5534	}
5535
5536	if ((err = priv_lists_create(handle, NULL, &plp, curr_iptype)) != Z_OK)
5537		return (err);
5538
5539	limitlen = strlen(limitpriv);
5540	if (limitlen == 0 || strcmp(limitpriv, DEFAULT_TOKEN) == 0) {
5541		free(limitpriv);
5542		err = get_default_privset(privs, plp);
5543		priv_lists_destroy(plp);
5544		return (err);
5545	}
5546
5547	/*
5548	 * Check if the string DEFAULT_TOKEN is the first token in a list
5549	 * of privileges.
5550	 */
5551	cp = strchr(limitpriv, TOKEN_PRIV_CHAR);
5552	if (cp != NULL &&
5553	    strncmp(limitpriv, DEFAULT_TOKEN, cp - limitpriv) == 0)
5554		err = verify_privset(cp + 1, privs, privname, B_TRUE, plp);
5555	else
5556		err = verify_privset(limitpriv, privs, privname, B_FALSE, plp);
5557
5558	free(limitpriv);
5559	priv_lists_destroy(plp);
5560	return (err);
5561}
5562
5563int
5564zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz)
5565{
5566	zone_dochandle_t handle;
5567	boolean_t found = B_FALSE;
5568	struct zoneent *ze;
5569	FILE *cookie;
5570	int err;
5571	char *cp;
5572
5573	if (zone_name == NULL)
5574		return (Z_INVAL);
5575
5576	(void) strlcpy(zonepath, zonecfg_root, rp_sz);
5577	cp = zonepath + strlen(zonepath);
5578	while (cp > zonepath && cp[-1] == '/')
5579		*--cp = '\0';
5580
5581	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) {
5582		if (zonepath[0] == '\0')
5583			(void) strlcpy(zonepath, "/", rp_sz);
5584		return (Z_OK);
5585	}
5586
5587	/*
5588	 * First check the index file.  Because older versions did not have
5589	 * a copy of the zone path, allow for it to be zero length, in which
5590	 * case we ignore this result and fall back to the XML files.
5591	 */
5592	cookie = setzoneent();
5593	while ((ze = getzoneent_private(cookie)) != NULL) {
5594		if (strcmp(ze->zone_name, zone_name) == 0) {
5595			found = B_TRUE;
5596			if (ze->zone_path[0] != '\0')
5597				(void) strlcpy(cp, ze->zone_path,
5598				    rp_sz - (cp - zonepath));
5599		}
5600		free(ze);
5601		if (found)
5602			break;
5603	}
5604	endzoneent(cookie);
5605	if (found && *cp != '\0')
5606		return (Z_OK);
5607
5608	/* Fall back to the XML files. */
5609	if ((handle = zonecfg_init_handle()) == NULL)
5610		return (Z_NOMEM);
5611
5612	/*
5613	 * Check the snapshot first: if a zone is running, its zonepath
5614	 * may have changed.
5615	 */
5616	if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
5617		if ((err = zonecfg_get_handle(zone_name, handle)) != Z_OK) {
5618			zonecfg_fini_handle(handle);
5619			return (err);
5620		}
5621	}
5622	err = zonecfg_get_zonepath(handle, zonepath, rp_sz);
5623	zonecfg_fini_handle(handle);
5624	return (err);
5625}
5626
5627int
5628zone_get_rootpath(char *zone_name, char *rootpath, size_t rp_sz)
5629{
5630	int err;
5631
5632	/* This function makes sense for non-global zones only. */
5633	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
5634		return (Z_BOGUS_ZONE_NAME);
5635	if ((err = zone_get_zonepath(zone_name, rootpath, rp_sz)) != Z_OK)
5636		return (err);
5637	if (strlcat(rootpath, "/root", rp_sz) >= rp_sz)
5638		return (Z_TOO_BIG);
5639	return (Z_OK);
5640}
5641
5642int
5643zone_get_brand(char *zone_name, char *brandname, size_t rp_sz)
5644{
5645	int err;
5646	zone_dochandle_t handle;
5647	char myzone[MAXNAMELEN];
5648	int myzoneid = getzoneid();
5649
5650	/*
5651	 * If we are not in the global zone, then we don't have the zone
5652	 * .xml files with the brand name available.  Thus, we are going to
5653	 * have to ask the kernel for the information.
5654	 */
5655	if (myzoneid != GLOBAL_ZONEID) {
5656		if (is_system_labeled()) {
5657			(void) strlcpy(brandname, NATIVE_BRAND_NAME, rp_sz);
5658			return (Z_OK);
5659		}
5660		if (zone_getattr(myzoneid, ZONE_ATTR_NAME, myzone,
5661		    sizeof (myzone)) < 0)
5662			return (Z_NO_ZONE);
5663		if (!zonecfg_is_scratch(myzone)) {
5664			if (strncmp(zone_name, myzone, MAXNAMELEN) != 0)
5665				return (Z_NO_ZONE);
5666		}
5667		err = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brandname, rp_sz);
5668		if (err < 0)
5669			return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL);
5670
5671		return (Z_OK);
5672	}
5673
5674	if (strcmp(zone_name, "global") == 0)
5675		return (zonecfg_default_brand(brandname, rp_sz));
5676
5677	if ((handle = zonecfg_init_handle()) == NULL)
5678		return (Z_NOMEM);
5679
5680	err = zonecfg_get_handle((char *)zone_name, handle);
5681	if (err == Z_OK)
5682		err = zonecfg_get_brand(handle, brandname, rp_sz);
5683
5684	zonecfg_fini_handle(handle);
5685	return (err);
5686}
5687
5688/*
5689 * Return the appropriate root for the active /dev.
5690 * For normal zone, the path is $ZONEPATH/root;
5691 * for scratch zone, the dev path is $ZONEPATH/lu.
5692 */
5693int
5694zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz)
5695{
5696	int err;
5697	char *suffix;
5698	zone_state_t state;
5699
5700	/* This function makes sense for non-global zones only. */
5701	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
5702		return (Z_BOGUS_ZONE_NAME);
5703	if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK)
5704		return (err);
5705
5706	if (zone_get_state(zone_name, &state) == Z_OK &&
5707	    state == ZONE_STATE_MOUNTED)
5708		suffix = "/lu";
5709	else
5710		suffix = "/root";
5711	if (strlcat(devroot, suffix, rp_sz) >= rp_sz)
5712		return (Z_TOO_BIG);
5713	return (Z_OK);
5714}
5715
5716static zone_state_t
5717kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state)
5718{
5719	char zoneroot[MAXPATHLEN];
5720	size_t zlen;
5721
5722	assert(kernel_state <= ZONE_MAX_STATE);
5723	switch (kernel_state) {
5724		case ZONE_IS_UNINITIALIZED:
5725		case ZONE_IS_INITIALIZED:
5726			/* The kernel will not return these two states */
5727			return (ZONE_STATE_READY);
5728		case ZONE_IS_READY:
5729			/*
5730			 * If the zone's root is mounted on $ZONEPATH/lu, then
5731			 * it's a mounted scratch zone.
5732			 */
5733			if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot,
5734			    sizeof (zoneroot)) >= 0) {
5735				zlen = strlen(zoneroot);
5736				if (zlen > 3 &&
5737				    strcmp(zoneroot + zlen - 3, "/lu") == 0)
5738					return (ZONE_STATE_MOUNTED);
5739			}
5740			return (ZONE_STATE_READY);
5741		case ZONE_IS_BOOTING:
5742		case ZONE_IS_RUNNING:
5743			return (ZONE_STATE_RUNNING);
5744		case ZONE_IS_SHUTTING_DOWN:
5745		case ZONE_IS_EMPTY:
5746			return (ZONE_STATE_SHUTTING_DOWN);
5747		case ZONE_IS_DOWN:
5748		case ZONE_IS_DYING:
5749		case ZONE_IS_DEAD:
5750		default:
5751			return (ZONE_STATE_DOWN);
5752	}
5753	/* NOTREACHED */
5754}
5755
5756int
5757zone_get_state(char *zone_name, zone_state_t *state_num)
5758{
5759	zone_status_t status;
5760	zoneid_t zone_id;
5761	struct zoneent *ze;
5762	boolean_t found = B_FALSE;
5763	FILE *cookie;
5764	char kernzone[ZONENAME_MAX];
5765	FILE *fp;
5766
5767	if (zone_name == NULL)
5768		return (Z_INVAL);
5769
5770	/*
5771	 * If we're looking at an alternate root, then we need to query the
5772	 * kernel using the scratch zone name.
5773	 */
5774	zone_id = -1;
5775	if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) {
5776		if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) {
5777			if (zonecfg_find_scratch(fp, zone_name, zonecfg_root,
5778			    kernzone, sizeof (kernzone)) == 0)
5779				zone_id = getzoneidbyname(kernzone);
5780			zonecfg_close_scratch(fp);
5781		}
5782	} else {
5783		zone_id = getzoneidbyname(zone_name);
5784	}
5785
5786	/* check to see if zone is running */
5787	if (zone_id != -1 &&
5788	    zone_getattr(zone_id, ZONE_ATTR_STATUS, &status,
5789	    sizeof (status)) >= 0) {
5790		*state_num = kernel_state_to_user_state(zone_id, status);
5791		return (Z_OK);
5792	}
5793
5794	cookie = setzoneent();
5795	while ((ze = getzoneent_private(cookie)) != NULL) {
5796		if (strcmp(ze->zone_name, zone_name) == 0) {
5797			found = B_TRUE;
5798			*state_num = ze->zone_state;
5799		}
5800		free(ze);
5801		if (found)
5802			break;
5803	}
5804	endzoneent(cookie);
5805	return ((found) ? Z_OK : Z_NO_ZONE);
5806}
5807
5808int
5809zone_set_state(char *zone, zone_state_t state)
5810{
5811	struct zoneent ze;
5812
5813	if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED &&
5814	    state != ZONE_STATE_INCOMPLETE)
5815		return (Z_INVAL);
5816
5817	bzero(&ze, sizeof (ze));
5818	(void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name));
5819	ze.zone_state = state;
5820	(void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path));
5821	return (putzoneent(&ze, PZE_MODIFY));
5822}
5823
5824/*
5825 * Get id (if any) for specified zone.  There are four possible outcomes:
5826 * - If the string corresponds to the numeric id of an active (booted)
5827 *   zone, sets *zip to the zone id and returns 0.
5828 * - If the string corresponds to the name of an active (booted) zone,
5829 *   sets *zip to the zone id and returns 0.
5830 * - If the string is a name in the configuration but is not booted,
5831 *   sets *zip to ZONE_ID_UNDEFINED and returns 0.
5832 * - Otherwise, leaves *zip unchanged and returns -1.
5833 *
5834 * This function acts as an auxiliary filter on the function of the same
5835 * name in libc; the linker binds to this version if libzonecfg exists,
5836 * and the libc version if it doesn't.  Any changes to this version of
5837 * the function should probably be reflected in the libc version as well.
5838 */
5839int
5840zone_get_id(const char *str, zoneid_t *zip)
5841{
5842	zone_dochandle_t hdl;
5843	zoneid_t zoneid;
5844	char *cp;
5845	int err;
5846
5847	/* first try looking for active zone by id */
5848	errno = 0;
5849	zoneid = (zoneid_t)strtol(str, &cp, 0);
5850	if (errno == 0 && cp != str && *cp == '\0' &&
5851	    getzonenamebyid(zoneid, NULL, 0) != -1) {
5852		*zip = zoneid;
5853		return (0);
5854	}
5855
5856	/* then look for active zone by name */
5857	if ((zoneid = getzoneidbyname(str)) != -1) {
5858		*zip = zoneid;
5859		return (0);
5860	}
5861
5862	/* if in global zone, try looking up name in configuration database */
5863	if (getzoneid() != GLOBAL_ZONEID ||
5864	    (hdl = zonecfg_init_handle()) == NULL)
5865		return (-1);
5866
5867	if (zonecfg_get_handle(str, hdl) == Z_OK) {
5868		/* zone exists but isn't active */
5869		*zip = ZONE_ID_UNDEFINED;
5870		err = 0;
5871	} else {
5872		err = -1;
5873	}
5874
5875	zonecfg_fini_handle(hdl);
5876	return (err);
5877}
5878
5879char *
5880zone_state_str(zone_state_t state_num)
5881{
5882	switch (state_num) {
5883	case ZONE_STATE_CONFIGURED:
5884		return (ZONE_STATE_STR_CONFIGURED);
5885	case ZONE_STATE_INCOMPLETE:
5886		return (ZONE_STATE_STR_INCOMPLETE);
5887	case ZONE_STATE_INSTALLED:
5888		return (ZONE_STATE_STR_INSTALLED);
5889	case ZONE_STATE_READY:
5890		return (ZONE_STATE_STR_READY);
5891	case ZONE_STATE_MOUNTED:
5892		return (ZONE_STATE_STR_MOUNTED);
5893	case ZONE_STATE_RUNNING:
5894		return (ZONE_STATE_STR_RUNNING);
5895	case ZONE_STATE_SHUTTING_DOWN:
5896		return (ZONE_STATE_STR_SHUTTING_DOWN);
5897	case ZONE_STATE_DOWN:
5898		return (ZONE_STATE_STR_DOWN);
5899	default:
5900		return ("unknown");
5901	}
5902}
5903
5904/*
5905 * Given a UUID value, find an associated zone name.  This is intended to be
5906 * used by callers who set up some 'default' name (corresponding to the
5907 * expected name for the zone) in the zonename buffer, and thus the function
5908 * doesn't touch this buffer on failure.
5909 */
5910int
5911zonecfg_get_name_by_uuid(const uuid_t uuidin, char *zonename, size_t namelen)
5912{
5913	FILE *fp;
5914	struct zoneent *ze;
5915	uchar_t *uuid;
5916
5917	/*
5918	 * A small amount of subterfuge via casts is necessary here because
5919	 * libuuid doesn't use const correctly, but we don't want to export
5920	 * this brokenness to our clients.
5921	 */
5922	uuid = (uchar_t *)uuidin;
5923	if (uuid_is_null(uuid))
5924		return (Z_NO_ZONE);
5925	if ((fp = setzoneent()) == NULL)
5926		return (Z_NO_ZONE);
5927	while ((ze = getzoneent_private(fp)) != NULL) {
5928		if (uuid_compare(uuid, ze->zone_uuid) == 0)
5929			break;
5930		free(ze);
5931	}
5932	endzoneent(fp);
5933	if (ze != NULL) {
5934		(void) strlcpy(zonename, ze->zone_name, namelen);
5935		free(ze);
5936		return (Z_OK);
5937	} else {
5938		return (Z_NO_ZONE);
5939	}
5940}
5941
5942/*
5943 * Given a zone name, get its UUID.  Returns a "NULL" UUID value if the zone
5944 * exists but the file doesn't have a value set yet.  Returns an error if the
5945 * zone cannot be located.
5946 */
5947int
5948zonecfg_get_uuid(const char *zonename, uuid_t uuid)
5949{
5950	FILE *fp;
5951	struct zoneent *ze;
5952
5953	if ((fp = setzoneent()) == NULL)
5954		return (Z_NO_ZONE);
5955	while ((ze = getzoneent_private(fp)) != NULL) {
5956		if (strcmp(ze->zone_name, zonename) == 0)
5957			break;
5958		free(ze);
5959	}
5960	endzoneent(fp);
5961	if (ze != NULL) {
5962		uuid_copy(uuid, ze->zone_uuid);
5963		free(ze);
5964		return (Z_OK);
5965	} else {
5966		return (Z_NO_ZONE);
5967	}
5968}
5969
5970/*
5971 * File-system convenience functions.
5972 */
5973boolean_t
5974zonecfg_valid_fs_type(const char *type)
5975{
5976	/*
5977	 * We already know which FS types don't work.
5978	 */
5979	if (strcmp(type, "proc") == 0 ||
5980	    strcmp(type, "mntfs") == 0 ||
5981	    strcmp(type, "autofs") == 0 ||
5982	    strncmp(type, "nfs", sizeof ("nfs") - 1) == 0)
5983		return (B_FALSE);
5984	/*
5985	 * The caller may do more detailed verification to make sure other
5986	 * aspects of this filesystem type make sense.
5987	 */
5988	return (B_TRUE);
5989}
5990
5991/*
5992 * Generally uninteresting rctl convenience functions.
5993 */
5994
5995int
5996zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval,
5997    rctlblk_t *rctlblk)
5998{
5999	unsigned long long ull;
6000	char *endp;
6001	rctl_priv_t priv;
6002	rctl_qty_t limit;
6003	uint_t action;
6004
6005	/* Get the privilege */
6006	if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) {
6007		priv = RCPRIV_BASIC;
6008	} else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) {
6009		priv = RCPRIV_PRIVILEGED;
6010	} else {
6011		/* Invalid privilege */
6012		return (Z_INVAL);
6013	}
6014
6015	/* deal with negative input; strtoull(3c) doesn't do what we want */
6016	if (rctlval->zone_rctlval_limit[0] == '-')
6017		return (Z_INVAL);
6018	/* Get the limit */
6019	errno = 0;
6020	ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0);
6021	if (errno != 0 || *endp != '\0') {
6022		/* parse failed */
6023		return (Z_INVAL);
6024	}
6025	limit = (rctl_qty_t)ull;
6026
6027	/* Get the action */
6028	if (strcmp(rctlval->zone_rctlval_action, "none") == 0) {
6029		action = RCTL_LOCAL_NOACTION;
6030	} else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) {
6031		action = RCTL_LOCAL_SIGNAL;
6032	} else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) {
6033		action = RCTL_LOCAL_DENY;
6034	} else {
6035		/* Invalid Action */
6036		return (Z_INVAL);
6037	}
6038	rctlblk_set_local_action(rctlblk, action, 0);
6039	rctlblk_set_privilege(rctlblk, priv);
6040	rctlblk_set_value(rctlblk, limit);
6041	return (Z_OK);
6042}
6043
6044static int
6045rctl_check(const char *rctlname, void *arg)
6046{
6047	const char *attrname = arg;
6048
6049	/*
6050	 * Returning 1 here is our signal to zonecfg_is_rctl() that it is
6051	 * indeed an rctl name recognized by the system.
6052	 */
6053	return (strcmp(rctlname, attrname) == 0 ? 1 : 0);
6054}
6055
6056boolean_t
6057zonecfg_is_rctl(const char *name)
6058{
6059	return (rctl_walk(rctl_check, (void *)name) == 1);
6060}
6061
6062boolean_t
6063zonecfg_valid_rctlname(const char *name)
6064{
6065	const char *c;
6066
6067	if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0)
6068		return (B_FALSE);
6069	if (strlen(name) == sizeof ("zone.") - 1)
6070		return (B_FALSE);
6071	for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) {
6072		if (!isalpha(*c) && *c != '-')
6073			return (B_FALSE);
6074	}
6075	return (B_TRUE);
6076}
6077
6078boolean_t
6079zonecfg_valid_rctlblk(const rctlblk_t *rctlblk)
6080{
6081	rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk);
6082	uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
6083
6084	if (priv != RCPRIV_PRIVILEGED)
6085		return (B_FALSE);
6086	if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY)
6087		return (B_FALSE);
6088	return (B_TRUE);
6089}
6090
6091boolean_t
6092zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk)
6093{
6094	rctlblk_t *current, *next;
6095	rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk);
6096	uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
6097	uint_t global_flags;
6098
6099	if (!zonecfg_valid_rctlblk(rctlblk))
6100		return (B_FALSE);
6101	if (!zonecfg_valid_rctlname(name))
6102		return (B_FALSE);
6103
6104	current = alloca(rctlblk_size());
6105	if (getrctl(name, NULL, current, RCTL_FIRST) != 0)
6106		return (B_TRUE);	/* not an rctl on this system */
6107	/*
6108	 * Make sure the proposed value isn't greater than the current system
6109	 * value.
6110	 */
6111	next = alloca(rctlblk_size());
6112	while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) {
6113		rctlblk_t *tmp;
6114
6115		if (getrctl(name, current, next, RCTL_NEXT) != 0)
6116			return (B_FALSE);	/* shouldn't happen */
6117		tmp = current;
6118		current = next;
6119		next = tmp;
6120	}
6121	if (limit > rctlblk_get_value(current))
6122		return (B_FALSE);
6123
6124	/*
6125	 * Make sure the proposed action is allowed.
6126	 */
6127	global_flags = rctlblk_get_global_flags(current);
6128	if ((global_flags & RCTL_GLOBAL_DENY_NEVER) &&
6129	    action == RCTL_LOCAL_DENY)
6130		return (B_FALSE);
6131	if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) &&
6132	    action == RCTL_LOCAL_NOACTION)
6133		return (B_FALSE);
6134
6135	return (B_TRUE);
6136}
6137
6138/*
6139 * There is always a race condition between reading the initial copy of
6140 * a zones state and its state changing.  We address this by providing
6141 * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions.
6142 * When zonecfg_critical_enter is called, sets the state field to LOCKED
6143 * and aquires biglock. Biglock protects against other threads executing
6144 * critical_enter and the state field protects against state changes during
6145 * the critical period.
6146 *
6147 * If any state changes occur, zn_cb will set the failed field of the znotify
6148 * structure.  This will cause the critical_exit function to re-lock the
6149 * channel and return an error. Since evsnts may be delayed, the critical_exit
6150 * function "flushes" the queue by putting an event on the queue and waiting for
6151 * zn_cb to notify critical_exit that it received the ping event.
6152 */
6153static const char *
6154string_get_tok(const char *in, char delim, int num)
6155{
6156	int i = 0;
6157
6158	for (; i < num; in++) {
6159		if (*in == delim)
6160			i++;
6161		if (*in == 0)
6162			return (NULL);
6163	}
6164	return (in);
6165}
6166
6167static boolean_t
6168is_ping(sysevent_t *ev)
6169{
6170	if (strcmp(sysevent_get_subclass_name(ev),
6171	    ZONE_EVENT_PING_SUBCLASS) == 0) {
6172		return (B_TRUE);
6173	} else {
6174		return (B_FALSE);
6175	}
6176}
6177
6178static boolean_t
6179is_my_ping(sysevent_t *ev)
6180{
6181	const char *sender;
6182	char mypid[sizeof (pid_t) * 3 + 1];
6183
6184	(void) snprintf(mypid, sizeof (mypid), "%i", getpid());
6185	sender = string_get_tok(sysevent_get_pub(ev), ':', 3);
6186	if (sender == NULL)
6187		return (B_FALSE);
6188	if (strcmp(sender, mypid) != 0)
6189		return (B_FALSE);
6190	return (B_TRUE);
6191}
6192
6193static int
6194do_callback(struct znotify *zevtchan, sysevent_t *ev)
6195{
6196	nvlist_t *l;
6197	int zid;
6198	char *zonename;
6199	char *newstate;
6200	char *oldstate;
6201	int ret;
6202	hrtime_t when;
6203
6204	if (strcmp(sysevent_get_subclass_name(ev),
6205	    ZONE_EVENT_STATUS_SUBCLASS) == 0) {
6206
6207		if (sysevent_get_attr_list(ev, &l) != 0) {
6208			if (errno == ENOMEM) {
6209				zevtchan->zn_failure_count++;
6210				return (EAGAIN);
6211			}
6212			return (0);
6213		}
6214		ret = 0;
6215
6216		if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) &&
6217		    (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate)
6218		    == 0) &&
6219		    (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate)
6220		    == 0) &&
6221		    (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP,
6222		    (uint64_t *)&when) == 0) &&
6223		    (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) {
6224			ret = zevtchan->zn_callback(zonename, zid, newstate,
6225			    oldstate, when, zevtchan->zn_private);
6226		}
6227
6228		zevtchan->zn_failure_count = 0;
6229		nvlist_free(l);
6230		return (ret);
6231	} else {
6232		/*
6233		 * We have received an event in an unknown subclass. Ignore.
6234		 */
6235		zevtchan->zn_failure_count = 0;
6236		return (0);
6237	}
6238}
6239
6240static int
6241zn_cb(sysevent_t *ev, void *p)
6242{