1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2014 Gary Mills
24  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
25  * Copyright (c) 2018, Joyent, Inc.
26  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
27  * Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
28  */
29 
30 #include <libsysevent.h>
31 #include <pthread.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <fnmatch.h>
35 #include <strings.h>
36 #include <unistd.h>
37 #include <assert.h>
38 #include <libgen.h>
39 #include <libintl.h>
40 #include <alloca.h>
41 #include <ctype.h>
42 #include <sys/acl.h>
43 #include <sys/stat.h>
44 #include <sys/brand.h>
45 #include <sys/mntio.h>
46 #include <sys/mnttab.h>
47 #include <sys/nvpair.h>
48 #include <sys/types.h>
49 #include <sys/sockio.h>
50 #include <sys/systeminfo.h>
51 #include <ftw.h>
52 #include <pool.h>
53 #include <libscf.h>
54 #include <libproc.h>
55 #include <sys/priocntl.h>
56 #include <libuutil.h>
57 #include <wait.h>
58 #include <bsm/adt.h>
59 #include <auth_attr.h>
60 #include <auth_list.h>
61 #include <secdb.h>
62 #include <user_attr.h>
63 #include <prof_attr.h>
64 #include <definit.h>
65 
66 #include <arpa/inet.h>
67 #include <netdb.h>
68 
69 #include <libxml/xmlmemory.h>
70 #include <libxml/parser.h>
71 
72 #include <libdevinfo.h>
73 #include <uuid/uuid.h>
74 #include <dirent.h>
75 #include <libbrand.h>
76 
77 #include <libzonecfg.h>
78 #include "zonecfg_impl.h"
79 
80 #define	_PATH_TMPFILE	"/zonecfg.XXXXXX"
81 #define	ZONE_CB_RETRY_COUNT		10
82 #define	ZONE_EVENT_PING_SUBCLASS	"ping"
83 #define	ZONE_EVENT_PING_PUBLISHER	"solaris"
84 
85 /* Hard-code the DTD element/attribute/entity names just once, here. */
86 #define	DTD_ELEM_ATTR		(const xmlChar *) "attr"
87 #define	DTD_ELEM_COMMENT	(const xmlChar *) "comment"
88 #define	DTD_ELEM_DEVICE		(const xmlChar *) "device"
89 #define	DTD_ELEM_FS		(const xmlChar *) "filesystem"
90 #define	DTD_ELEM_FSOPTION	(const xmlChar *) "fsoption"
91 #define	DTD_ELEM_NET		(const xmlChar *) "network"
92 #define	DTD_ELEM_RCTL		(const xmlChar *) "rctl"
93 #define	DTD_ELEM_RCTLVALUE	(const xmlChar *) "rctl-value"
94 #define	DTD_ELEM_ZONE		(const xmlChar *) "zone"
95 #define	DTD_ELEM_DATASET	(const xmlChar *) "dataset"
96 #define	DTD_ELEM_TMPPOOL	(const xmlChar *) "tmp_pool"
97 #define	DTD_ELEM_PSET		(const xmlChar *) "pset"
98 #define	DTD_ELEM_MCAP		(const xmlChar *) "mcap"
99 #define	DTD_ELEM_PACKAGE	(const xmlChar *) "package"
100 #define	DTD_ELEM_OBSOLETES	(const xmlChar *) "obsoletes"
101 #define	DTD_ELEM_DEV_PERM	(const xmlChar *) "dev-perm"
102 #define	DTD_ELEM_ADMIN		(const xmlChar *) "admin"
103 #define	DTD_ELEM_SECFLAGS	(const xmlChar *) "security-flags"
104 
105 #define	DTD_ATTR_ACTION		(const xmlChar *) "action"
106 #define	DTD_ATTR_ADDRESS	(const xmlChar *) "address"
107 #define	DTD_ATTR_ALLOWED_ADDRESS	(const xmlChar *) "allowed-address"
108 #define	DTD_ATTR_AUTOBOOT	(const xmlChar *) "autoboot"
109 #define	DTD_ATTR_IPTYPE		(const xmlChar *) "ip-type"
110 #define	DTD_ATTR_DEFROUTER	(const xmlChar *) "defrouter"
111 #define	DTD_ATTR_DIR		(const xmlChar *) "directory"
112 #define	DTD_ATTR_LIMIT		(const xmlChar *) "limit"
113 #define	DTD_ATTR_LIMITPRIV	(const xmlChar *) "limitpriv"
114 #define	DTD_ATTR_BOOTARGS	(const xmlChar *) "bootargs"
115 #define	DTD_ATTR_SCHED		(const xmlChar *) "scheduling-class"
116 #define	DTD_ATTR_MATCH		(const xmlChar *) "match"
117 #define	DTD_ATTR_NAME		(const xmlChar *) "name"
118 #define	DTD_ATTR_PHYSICAL	(const xmlChar *) "physical"
119 #define	DTD_ATTR_POOL		(const xmlChar *) "pool"
120 #define	DTD_ATTR_PRIV		(const xmlChar *) "priv"
121 #define	DTD_ATTR_RAW		(const xmlChar *) "raw"
122 #define	DTD_ATTR_SPECIAL	(const xmlChar *) "special"
123 #define	DTD_ATTR_TYPE		(const xmlChar *) "type"
124 #define	DTD_ATTR_VALUE		(const xmlChar *) "value"
125 #define	DTD_ATTR_ZONEPATH	(const xmlChar *) "zonepath"
126 #define	DTD_ATTR_NCPU_MIN	(const xmlChar *) "ncpu_min"
127 #define	DTD_ATTR_NCPU_MAX	(const xmlChar *) "ncpu_max"
128 #define	DTD_ATTR_IMPORTANCE	(const xmlChar *) "importance"
129 #define	DTD_ATTR_PHYSCAP	(const xmlChar *) "physcap"
130 #define	DTD_ATTR_VERSION	(const xmlChar *) "version"
131 #define	DTD_ATTR_ID		(const xmlChar *) "id"
132 #define	DTD_ATTR_UID		(const xmlChar *) "uid"
133 #define	DTD_ATTR_GID		(const xmlChar *) "gid"
134 #define	DTD_ATTR_MODE		(const xmlChar *) "mode"
135 #define	DTD_ATTR_ACL		(const xmlChar *) "acl"
136 #define	DTD_ATTR_BRAND		(const xmlChar *) "brand"
137 #define	DTD_ATTR_HOSTID		(const xmlChar *) "hostid"
138 #define	DTD_ATTR_USER		(const xmlChar *) "user"
139 #define	DTD_ATTR_AUTHS		(const xmlChar *) "auths"
140 #define	DTD_ATTR_FS_ALLOWED	(const xmlChar *) "fs-allowed"
141 #define	DTD_ATTR_DEFAULT	(const xmlChar *) "default"
142 #define	DTD_ATTR_LOWER		(const xmlChar *) "lower"
143 #define	DTD_ATTR_UPPER		(const xmlChar *) "upper"
144 
145 
146 #define	DTD_ENTITY_BOOLEAN	"boolean"
147 #define	DTD_ENTITY_DEVPATH	"devpath"
148 #define	DTD_ENTITY_DRIVER	"driver"
149 #define	DTD_ENTITY_DRVMIN	"drv_min"
150 #define	DTD_ENTITY_FALSE	"false"
151 #define	DTD_ENTITY_INT		"int"
152 #define	DTD_ENTITY_STRING	"string"
153 #define	DTD_ENTITY_TRUE		"true"
154 #define	DTD_ENTITY_UINT		"uint"
155 
156 #define	DTD_ENTITY_BOOL_LEN	6	/* "false" */
157 
158 #define	ATTACH_FORCED	"SUNWattached.xml"
159 
160 #define	TMP_POOL_NAME	"SUNWtmp_%s"
161 #define	MAX_TMP_POOL_NAME	(ZONENAME_MAX + 9)
162 #define	RCAP_SERVICE	"system/rcap:default"
163 #define	POOLD_SERVICE	"system/pools/dynamic:default"
164 
165 /*
166  * rctl alias definitions
167  *
168  * This holds the alias, the full rctl name, the default priv value, action
169  * and lower limit.  The functions that handle rctl aliases step through
170  * this table, matching on the alias, and using the full values for setting
171  * the rctl entry as well the limit for validation.
172  */
173 static struct alias {
174 	char *shortname;
175 	char *realname;
176 	char *priv;
177 	char *action;
178 	uint64_t low_limit;
179 } aliases[] = {
180 	{ALIAS_MAXLWPS, "zone.max-lwps", "privileged", "deny", 100},
181 	{ALIAS_MAXSHMMEM, "zone.max-shm-memory", "privileged", "deny", 0},
182 	{ALIAS_MAXSHMIDS, "zone.max-shm-ids", "privileged", "deny", 0},
183 	{ALIAS_MAXMSGIDS, "zone.max-msg-ids", "privileged", "deny", 0},
184 	{ALIAS_MAXSEMIDS, "zone.max-sem-ids", "privileged", "deny", 0},
185 	{ALIAS_MAXLOCKEDMEM, "zone.max-locked-memory", "privileged", "deny", 0},
186 	{ALIAS_MAXSWAP, "zone.max-swap", "privileged", "deny", 0},
187 	{ALIAS_SHARES, "zone.cpu-shares", "privileged", "none", 0},
188 	{ALIAS_CPUCAP, "zone.cpu-cap", "privileged", "deny", 0},
189 	{ALIAS_MAXPROCS, "zone.max-processes", "privileged", "deny", 100},
190 	{NULL, NULL, NULL, NULL, 0}
191 };
192 
193 /*
194  * Structure for applying rctls to a running zone.  It allows important
195  * process values to be passed together easily.
196  */
197 typedef struct pr_info_handle {
198 	struct ps_prochandle *pr;
199 	pid_t pid;
200 } pr_info_handle_t;
201 
202 struct zone_dochandle {
203 	char		*zone_dh_rootdir;
204 	xmlDocPtr	zone_dh_doc;
205 	xmlNodePtr	zone_dh_cur;
206 	xmlNodePtr	zone_dh_top;
207 	boolean_t	zone_dh_newzone;
208 	boolean_t	zone_dh_snapshot;
209 	boolean_t	zone_dh_sw_inv;
210 	zone_userauths_t	*zone_dh_userauths;
211 	char		zone_dh_delete_name[ZONENAME_MAX];
212 };
213 
214 struct znotify {
215 	void * zn_private;
216 	evchan_t *zn_eventchan;
217 	int (*zn_callback)(const  char *zonename, zoneid_t zid,
218 	    const char *newstate, const char *oldstate, hrtime_t when, void *p);
219 	pthread_mutex_t zn_mutex;
220 	pthread_cond_t zn_cond;
221 	pthread_mutex_t zn_bigmutex;
222 	volatile enum {ZN_UNLOCKED, ZN_LOCKED, ZN_PING_INFLIGHT,
223 	    ZN_PING_RECEIVED} zn_state;
224 	char zn_subscriber_id[MAX_SUBID_LEN];
225 	volatile boolean_t zn_failed;
226 	int zn_failure_count;
227 };
228 
229 /* used to track nested zone-lock operations */
230 static int zone_lock_cnt = 0;
231 
232 /* used to communicate lock status to children */
233 #define	LOCK_ENV_VAR	"_ZONEADM_LOCK_HELD"
234 static char zoneadm_lock_held[] = LOCK_ENV_VAR"=1";
235 static char zoneadm_lock_not_held[] = LOCK_ENV_VAR"=0";
236 
237 char *zonecfg_root = "";
238 
239 /*
240  * For functions which return int, which is most of the functions herein,
241  * the return values should be from the Z_foo set defined in <libzonecfg.h>.
242  * In some instances, we take pains mapping some libc errno values to Z_foo
243  * values from this set.
244  */
245 
246 /*
247  * Set the root (/) path for all zonecfg configuration files.  This is a
248  * private interface used by Live Upgrade extensions to access zone
249  * configuration inside mounted alternate boot environments.
250  * This interface is also used by zoneadm mount and unmount subcommands.
251  */
252 void
zonecfg_set_root(const char * rootpath)253 zonecfg_set_root(const char *rootpath)
254 {
255 	if (*zonecfg_root != '\0')
256 		free(zonecfg_root);
257 	if (rootpath == NULL || rootpath[0] == '\0' || rootpath[1] == '\0' ||
258 	    (zonecfg_root = strdup(rootpath)) == NULL)
259 		zonecfg_root = "";
260 }
261 
262 const char *
zonecfg_get_root(void)263 zonecfg_get_root(void)
264 {
265 	return (zonecfg_root);
266 }
267 
268 boolean_t
zonecfg_in_alt_root(void)269 zonecfg_in_alt_root(void)
270 {
271 	return (*zonecfg_root != '\0');
272 }
273 
274 /*
275  * Callers of the _file_path() functions are expected to have the second
276  * parameter be a (char foo[MAXPATHLEN]).
277  */
278 
279 static boolean_t
config_file_path(const char * zonename,char * answer)280 config_file_path(const char *zonename, char *answer)
281 {
282 	return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root,
283 	    ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN);
284 }
285 
286 static boolean_t
snap_file_path(const char * zonename,char * answer)287 snap_file_path(const char *zonename, char *answer)
288 {
289 	return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml",
290 	    zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN);
291 }
292 
293 /*ARGSUSED*/
294 static void
zonecfg_error_func(void * ctx,const char * msg,...)295 zonecfg_error_func(void *ctx, const char *msg, ...)
296 {
297 	/*
298 	 * This function does nothing by design.  Its purpose is to prevent
299 	 * libxml from dumping unwanted messages to stdout/stderr.
300 	 */
301 }
302 
303 zone_dochandle_t
zonecfg_init_handle(void)304 zonecfg_init_handle(void)
305 {
306 	zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle));
307 	if (handle == NULL) {
308 		errno = Z_NOMEM;
309 		return (NULL);
310 	}
311 
312 	/* generic libxml initialization */
313 	(void) xmlLineNumbersDefault(1);
314 	xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
315 	xmlDoValidityCheckingDefaultValue = 1;
316 	(void) xmlKeepBlanksDefault(0);
317 	xmlGetWarningsDefaultValue = 0;
318 	xmlSetGenericErrorFunc(NULL, zonecfg_error_func);
319 
320 	return (handle);
321 }
322 
323 int
zonecfg_check_handle(zone_dochandle_t handle)324 zonecfg_check_handle(zone_dochandle_t handle)
325 {
326 	if (handle == NULL || handle->zone_dh_doc == NULL)
327 		return (Z_BAD_HANDLE);
328 	return (Z_OK);
329 }
330 
331 void
zonecfg_fini_handle(zone_dochandle_t handle)332 zonecfg_fini_handle(zone_dochandle_t handle)
333 {
334 	if (zonecfg_check_handle(handle) == Z_OK)
335 		xmlFreeDoc(handle->zone_dh_doc);
336 	if (handle != NULL)
337 		free(handle);
338 }
339 
340 static int
zonecfg_destroy_impl(char * filename)341 zonecfg_destroy_impl(char *filename)
342 {
343 	if (unlink(filename) == -1) {
344 		if (errno == EACCES)
345 			return (Z_ACCES);
346 		if (errno == ENOENT)
347 			return (Z_NO_ZONE);
348 		return (Z_MISC_FS);
349 	}
350 	return (Z_OK);
351 }
352 
353 int
zonecfg_destroy(const char * zonename,boolean_t force)354 zonecfg_destroy(const char *zonename, boolean_t force)
355 {
356 	char path[MAXPATHLEN];
357 	struct zoneent ze;
358 	int err, state_err;
359 	zone_state_t state;
360 
361 	if (!config_file_path(zonename, path))
362 		return (Z_MISC_FS);
363 
364 	state_err = zone_get_state((char *)zonename, &state);
365 	err = access(path, W_OK);
366 
367 	/*
368 	 * If there is no file, and no index entry, reliably indicate that no
369 	 * such zone exists.
370 	 */
371 	if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT))
372 		return (Z_NO_ZONE);
373 
374 	/*
375 	 * Handle any other filesystem related errors (except if the XML
376 	 * file is missing, which we treat silently), unless we're forcing,
377 	 * in which case we plow on.
378 	 */
379 	if (err == -1 && errno != ENOENT) {
380 		if (errno == EACCES)
381 			return (Z_ACCES);
382 		else if (!force)
383 			return (Z_MISC_FS);
384 	}
385 
386 	if (state > ZONE_STATE_INSTALLED)
387 		return (Z_BAD_ZONE_STATE);
388 
389 	if (!force && state > ZONE_STATE_CONFIGURED)
390 		return (Z_BAD_ZONE_STATE);
391 
392 	/*
393 	 * Index deletion succeeds even if the entry doesn't exist.  So this
394 	 * will fail only if we've had some more severe problem.
395 	 */
396 	bzero(&ze, sizeof (ze));
397 	(void) strlcpy(ze.zone_name, zonename, sizeof (ze.zone_name));
398 	if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK)
399 		if (!force)
400 			return (err);
401 
402 	err = zonecfg_destroy_impl(path);
403 
404 	/*
405 	 * Treat failure to find the XML file silently, since, well, it's
406 	 * gone, and with the index file cleaned up, we're done.
407 	 */
408 	if (err == Z_OK || err == Z_NO_ZONE)
409 		return (Z_OK);
410 	return (err);
411 }
412 
413 int
zonecfg_destroy_snapshot(const char * zonename)414 zonecfg_destroy_snapshot(const char *zonename)
415 {
416 	char path[MAXPATHLEN];
417 
418 	if (!snap_file_path(zonename, path))
419 		return (Z_MISC_FS);
420 	return (zonecfg_destroy_impl(path));
421 }
422 
423 static int
getroot(zone_dochandle_t handle,xmlNodePtr * root)424 getroot(zone_dochandle_t handle, xmlNodePtr *root)
425 {
426 	if (zonecfg_check_handle(handle) == Z_BAD_HANDLE)
427 		return (Z_BAD_HANDLE);
428 
429 	*root = xmlDocGetRootElement(handle->zone_dh_doc);
430 
431 	if (*root == NULL)
432 		return (Z_EMPTY_DOCUMENT);
433 
434 	if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE))
435 		return (Z_WRONG_DOC_TYPE);
436 
437 	return (Z_OK);
438 }
439 
440 static int
operation_prep(zone_dochandle_t handle)441 operation_prep(zone_dochandle_t handle)
442 {
443 	xmlNodePtr root;
444 	int err;
445 
446 	if ((err = getroot(handle, &root)) != 0)
447 		return (err);
448 
449 	handle->zone_dh_cur = root;
450 	handle->zone_dh_top = root;
451 	return (Z_OK);
452 }
453 
454 static int
fetchprop(xmlNodePtr cur,const xmlChar * propname,char * dst,size_t dstsize)455 fetchprop(xmlNodePtr cur, const xmlChar *propname, char *dst, size_t dstsize)
456 {
457 	xmlChar *property;
458 	size_t srcsize;
459 
460 	if ((property = xmlGetProp(cur, propname)) == NULL)
461 		return (Z_BAD_PROPERTY);
462 	srcsize = strlcpy(dst, (char *)property, dstsize);
463 	xmlFree(property);
464 	if (srcsize >= dstsize)
465 		return (Z_TOO_BIG);
466 	return (Z_OK);
467 }
468 
469 static int
fetch_alloc_prop(xmlNodePtr cur,const xmlChar * propname,char ** dst)470 fetch_alloc_prop(xmlNodePtr cur, const xmlChar *propname, char **dst)
471 {
472 	xmlChar *property;
473 
474 	if ((property = xmlGetProp(cur, propname)) == NULL)
475 		return (Z_BAD_PROPERTY);
476 	if ((*dst = strdup((char *)property)) == NULL) {
477 		xmlFree(property);
478 		return (Z_NOMEM);
479 	}
480 	xmlFree(property);
481 	return (Z_OK);
482 }
483 
484 static int
getrootattr(zone_dochandle_t handle,const xmlChar * propname,char * propval,size_t propsize)485 getrootattr(zone_dochandle_t handle, const xmlChar *propname,
486     char *propval, size_t propsize)
487 {
488 	xmlNodePtr root;
489 	int err;
490 
491 	if ((err = getroot(handle, &root)) != 0)
492 		return (err);
493 
494 	return (fetchprop(root, propname, propval, propsize));
495 }
496 
497 static int
get_alloc_rootattr(zone_dochandle_t handle,const xmlChar * propname,char ** propval)498 get_alloc_rootattr(zone_dochandle_t handle, const xmlChar *propname,
499     char **propval)
500 {
501 	xmlNodePtr root;
502 	int err;
503 
504 	if ((err = getroot(handle, &root)) != 0)
505 		return (err);
506 
507 	return (fetch_alloc_prop(root, propname, propval));
508 }
509 
510 static int
setrootattr(zone_dochandle_t handle,const xmlChar * propname,const char * propval)511 setrootattr(zone_dochandle_t handle, const xmlChar *propname,
512     const char *propval)
513 {
514 	int err;
515 	xmlNodePtr root;
516 
517 	if ((err = getroot(handle, &root)) != Z_OK)
518 		return (err);
519 
520 	/*
521 	 * If we get a null propval remove the property (ignore return since it
522 	 * may not be set to begin with).
523 	 */
524 	if (propval == NULL) {
525 		(void) xmlUnsetProp(root, propname);
526 	} else {
527 		if (xmlSetProp(root, propname, (const xmlChar *) propval)
528 		    == NULL)
529 			return (Z_INVAL);
530 	}
531 	return (Z_OK);
532 }
533 
534 static void
addcomment(zone_dochandle_t handle,const char * comment)535 addcomment(zone_dochandle_t handle, const char *comment)
536 {
537 	xmlNodePtr node;
538 	node = xmlNewComment((xmlChar *) comment);
539 
540 	if (node != NULL)
541 		(void) xmlAddPrevSibling(handle->zone_dh_top, node);
542 }
543 
544 static void
stripcomments(zone_dochandle_t handle)545 stripcomments(zone_dochandle_t handle)
546 {
547 	xmlDocPtr top;
548 	xmlNodePtr child, next;
549 
550 	top = handle->zone_dh_doc;
551 	for (child = top->xmlChildrenNode; child != NULL; child = next) {
552 		next = child->next;
553 		if (child->name == NULL)
554 			continue;
555 		if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) {
556 			next = child->next;
557 			xmlUnlinkNode(child);
558 			xmlFreeNode(child);
559 		}
560 	}
561 }
562 
563 static void
strip_sw_inv(zone_dochandle_t handle)564 strip_sw_inv(zone_dochandle_t handle)
565 {
566 	xmlNodePtr root, child, next;
567 
568 	root = xmlDocGetRootElement(handle->zone_dh_doc);
569 	for (child = root->xmlChildrenNode; child != NULL; child = next) {
570 		next = child->next;
571 		if (child->name == NULL)
572 			continue;
573 		if (xmlStrcmp(child->name, DTD_ELEM_PACKAGE) == 0) {
574 			next = child->next;
575 			xmlUnlinkNode(child);
576 			xmlFreeNode(child);
577 		}
578 	}
579 }
580 
581 static int
zonecfg_get_handle_impl(const char * zonename,const char * filename,zone_dochandle_t handle)582 zonecfg_get_handle_impl(const char *zonename, const char *filename,
583     zone_dochandle_t handle)
584 {
585 	xmlValidCtxtPtr cvp;
586 	struct stat statbuf;
587 	int valid;
588 
589 	if (zonename == NULL)
590 		return (Z_NO_ZONE);
591 
592 	if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) {
593 		/* distinguish file not found vs. found but not parsed */
594 		if (stat(filename, &statbuf) == 0)
595 			return (Z_INVALID_DOCUMENT);
596 		return (Z_NO_ZONE);
597 	}
598 	if ((cvp = xmlNewValidCtxt()) == NULL)
599 		return (Z_NOMEM);
600 	cvp->error = zonecfg_error_func;
601 	cvp->warning = zonecfg_error_func;
602 	valid = xmlValidateDocument(cvp, handle->zone_dh_doc);
603 	xmlFreeValidCtxt(cvp);
604 	if (valid == 0)
605 		return (Z_INVALID_DOCUMENT);
606 
607 	/* delete any comments such as inherited Sun copyright / ident str */
608 	stripcomments(handle);
609 	return (Z_OK);
610 }
611 
612 int
zonecfg_get_handle(const char * zonename,zone_dochandle_t handle)613 zonecfg_get_handle(const char *zonename, zone_dochandle_t handle)
614 {
615 	char path[MAXPATHLEN];
616 
617 	if (!config_file_path(zonename, path))
618 		return (Z_MISC_FS);
619 	handle->zone_dh_newzone = B_FALSE;
620 
621 	return (zonecfg_get_handle_impl(zonename, path, handle));
622 }
623 
624 int
zonecfg_get_attach_handle(const char * path,const char * fname,const char * zonename,boolean_t preserve_sw,zone_dochandle_t handle)625 zonecfg_get_attach_handle(const char *path, const char *fname,
626     const char *zonename, boolean_t preserve_sw, zone_dochandle_t handle)
627 {
628 	char		migpath[MAXPATHLEN];
629 	int		err;
630 	struct stat	buf;
631 
632 	if (snprintf(migpath, sizeof (migpath), "%s/root", path) >=
633 	    sizeof (migpath))
634 		return (Z_NOMEM);
635 
636 	if (stat(migpath, &buf) == -1 || !S_ISDIR(buf.st_mode))
637 		return (Z_NO_ZONE);
638 
639 	if (snprintf(migpath, sizeof (migpath), "%s/%s", path, fname) >=
640 	    sizeof (migpath))
641 		return (Z_NOMEM);
642 
643 	if ((err = zonecfg_get_handle_impl(zonename, migpath, handle)) != Z_OK)
644 		return (err);
645 
646 	if (!preserve_sw)
647 		strip_sw_inv(handle);
648 
649 	handle->zone_dh_newzone = B_TRUE;
650 	if ((err = setrootattr(handle, DTD_ATTR_ZONEPATH, path)) != Z_OK)
651 		return (err);
652 
653 	return (setrootattr(handle, DTD_ATTR_NAME, zonename));
654 }
655 
656 int
zonecfg_get_snapshot_handle(const char * zonename,zone_dochandle_t handle)657 zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle)
658 {
659 	char path[MAXPATHLEN];
660 
661 	if (!snap_file_path(zonename, path))
662 		return (Z_MISC_FS);
663 	handle->zone_dh_newzone = B_FALSE;
664 	return (zonecfg_get_handle_impl(zonename, path, handle));
665 }
666 
667 int
zonecfg_get_template_handle(const char * template,const char * zonename,zone_dochandle_t handle)668 zonecfg_get_template_handle(const char *template, const char *zonename,
669     zone_dochandle_t handle)
670 {
671 	char path[MAXPATHLEN];
672 	int err;
673 
674 	if (!config_file_path(template, path))
675 		return (Z_MISC_FS);
676 
677 	if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK)
678 		return (err);
679 	handle->zone_dh_newzone = B_TRUE;
680 	return (setrootattr(handle, DTD_ATTR_NAME, zonename));
681 }
682 
683 int
zonecfg_get_xml_handle(const char * path,zone_dochandle_t handle)684 zonecfg_get_xml_handle(const char *path, zone_dochandle_t handle)
685 {
686 	struct stat buf;
687 	int err;
688 
689 	if (stat(path, &buf) == -1)
690 		return (Z_MISC_FS);
691 
692 	if ((err = zonecfg_get_handle_impl("xml", path, handle)) != Z_OK)
693 		return (err);
694 	handle->zone_dh_newzone = B_TRUE;
695 	return (Z_OK);
696 }
697 
698 /*
699  * Initialize two handles from the manifest read on fd.  The rem_handle
700  * is initialized from the input file, including the sw inventory.  The
701  * local_handle is initialized with the same zone configuration but with
702  * no sw inventory.
703  */
704 int
zonecfg_attach_manifest(int fd,zone_dochandle_t local_handle,zone_dochandle_t rem_handle)705 zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle,
706     zone_dochandle_t rem_handle)
707 {
708 	xmlValidCtxtPtr cvp;
709 	int valid;
710 
711 	/* load the manifest into the handle for the remote system */
712 	if ((rem_handle->zone_dh_doc = xmlReadFd(fd, NULL, NULL, 0)) == NULL) {
713 		return (Z_INVALID_DOCUMENT);
714 	}
715 	if ((cvp = xmlNewValidCtxt()) == NULL)
716 		return (Z_NOMEM);
717 	cvp->error = zonecfg_error_func;
718 	cvp->warning = zonecfg_error_func;
719 	valid = xmlValidateDocument(cvp, rem_handle->zone_dh_doc);
720 	xmlFreeValidCtxt(cvp);
721 	if (valid == 0)
722 		return (Z_INVALID_DOCUMENT);
723 
724 	/* delete any comments such as inherited Sun copyright / ident str */
725 	stripcomments(rem_handle);
726 
727 	rem_handle->zone_dh_newzone = B_TRUE;
728 	rem_handle->zone_dh_sw_inv = B_TRUE;
729 
730 	/*
731 	 * Now use the remote system handle to generate a local system handle
732 	 * with an identical zones configuration but no sw inventory.
733 	 */
734 	if ((local_handle->zone_dh_doc = xmlCopyDoc(rem_handle->zone_dh_doc,
735 	    1)) == NULL) {
736 		return (Z_INVALID_DOCUMENT);
737 	}
738 
739 	/*
740 	 * We need to re-run xmlValidateDocument on local_handle to properly
741 	 * update the in-core representation of the configuration.
742 	 */
743 	if ((cvp = xmlNewValidCtxt()) == NULL)
744 		return (Z_NOMEM);
745 	cvp->error = zonecfg_error_func;
746 	cvp->warning = zonecfg_error_func;
747 	valid = xmlValidateDocument(cvp, local_handle->zone_dh_doc);
748 	xmlFreeValidCtxt(cvp);
749 	if (valid == 0)
750 		return (Z_INVALID_DOCUMENT);
751 
752 	strip_sw_inv(local_handle);
753 
754 	local_handle->zone_dh_newzone = B_TRUE;
755 	local_handle->zone_dh_sw_inv = B_FALSE;
756 
757 	return (Z_OK);
758 }
759 
760 static boolean_t
is_renaming(zone_dochandle_t handle)761 is_renaming(zone_dochandle_t handle)
762 {
763 	if (handle->zone_dh_newzone)
764 		return (B_FALSE);
765 	if (strlen(handle->zone_dh_delete_name) > 0)
766 		return (B_TRUE);
767 	return (B_FALSE);
768 }
769 
770 static boolean_t
is_new(zone_dochandle_t handle)771 is_new(zone_dochandle_t handle)
772 {
773 	return (handle->zone_dh_newzone || handle->zone_dh_snapshot);
774 }
775 
776 static boolean_t
is_snapshot(zone_dochandle_t handle)777 is_snapshot(zone_dochandle_t handle)
778 {
779 	return (handle->zone_dh_snapshot);
780 }
781 
782 /*
783  * It would be great to be able to use libc's ctype(3c) macros, but we
784  * can't, as they are locale sensitive, and it would break our limited thread
785  * safety if this routine had to change the app locale on the fly.
786  */
787 int
zonecfg_validate_zonename(const char * zone)788 zonecfg_validate_zonename(const char *zone)
789 {
790 	int i;
791 
792 	if (strcmp(zone, GLOBAL_ZONENAME) == 0)
793 		return (Z_BOGUS_ZONE_NAME);
794 
795 	if (strlen(zone) >= ZONENAME_MAX)
796 		return (Z_BOGUS_ZONE_NAME);
797 
798 	if (!((zone[0] >= 'a' && zone[0] <= 'z') ||
799 	    (zone[0] >= 'A' && zone[0] <= 'Z') ||
800 	    (zone[0] >= '0' && zone[0] <= '9')))
801 		return (Z_BOGUS_ZONE_NAME);
802 
803 	for (i = 1; zone[i] != '\0'; i++) {
804 		if (!((zone[i] >= 'a' && zone[i] <= 'z') ||
805 		    (zone[i] >= 'A' && zone[i] <= 'Z') ||
806 		    (zone[i] >= '0' && zone[i] <= '9') ||
807 		    (zone[i] == '-') || (zone[i] == '_') || (zone[i] == '.')))
808 			return (Z_BOGUS_ZONE_NAME);
809 	}
810 
811 	return (Z_OK);
812 }
813 
814 /*
815  * Changing the zone name requires us to track both the old and new
816  * name of the zone until commit time.
817  */
818 int
zonecfg_get_name(zone_dochandle_t handle,char * name,size_t namesize)819 zonecfg_get_name(zone_dochandle_t handle, char *name, size_t namesize)
820 {
821 	return (getrootattr(handle, DTD_ATTR_NAME, name, namesize));
822 }
823 
824 static int
insert_admins(zone_dochandle_t handle,char * zonename)825 insert_admins(zone_dochandle_t handle, char *zonename)
826 {
827 	int err;
828 	struct zone_admintab admintab;
829 
830 	if ((err = zonecfg_setadminent(handle)) != Z_OK) {
831 		return (err);
832 	}
833 	while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
834 		err = zonecfg_insert_userauths(handle,
835 		    admintab.zone_admin_user, zonename);
836 		if (err != Z_OK) {
837 			(void) zonecfg_endadminent(handle);
838 			return (err);
839 		}
840 	}
841 	(void) zonecfg_endadminent(handle);
842 	return (Z_OK);
843 }
844 
845 int
zonecfg_set_name(zone_dochandle_t handle,char * name)846 zonecfg_set_name(zone_dochandle_t handle, char *name)
847 {
848 	zone_state_t state;
849 	char curname[ZONENAME_MAX], old_delname[ZONENAME_MAX];
850 	int err;
851 
852 	if ((err = getrootattr(handle, DTD_ATTR_NAME, curname,
853 	    sizeof (curname))) != Z_OK)
854 		return (err);
855 
856 	if (strcmp(name, curname) == 0)
857 		return (Z_OK);
858 
859 	/*
860 	 * Switching zone names to one beginning with SUNW is not permitted.
861 	 */
862 	if (strncmp(name, "SUNW", 4) == 0)
863 		return (Z_BOGUS_ZONE_NAME);
864 
865 	if ((err = zonecfg_validate_zonename(name)) != Z_OK)
866 		return (err);
867 
868 	/*
869 	 * Setting the name back to the original name (effectively a revert of
870 	 * the name) is fine.  But if we carry on, we'll falsely identify the
871 	 * name as "in use," so special case here.
872 	 */
873 	if (strcmp(name, handle->zone_dh_delete_name) == 0) {
874 		err = setrootattr(handle, DTD_ATTR_NAME, name);
875 		handle->zone_dh_delete_name[0] = '\0';
876 		return (err);
877 	}
878 
879 	/* Check to see if new name chosen is already in use */
880 	if (zone_get_state(name, &state) != Z_NO_ZONE)
881 		return (Z_NAME_IN_USE);
882 
883 	/*
884 	 * If this isn't already "new" or in a renaming transition, then
885 	 * we're initiating a rename here; so stash the "delete name"
886 	 * (i.e. the name of the zone we'll be removing) for the rename.
887 	 */
888 	(void) strlcpy(old_delname, handle->zone_dh_delete_name,
889 	    sizeof (old_delname));
890 	if (!is_new(handle) && !is_renaming(handle)) {
891 		/*
892 		 * Name change is allowed only when the zone we're altering
893 		 * is not ready or running.
894 		 */
895 		err = zone_get_state(curname, &state);
896 		if (err == Z_OK) {
897 			if (state > ZONE_STATE_INSTALLED)
898 				return (Z_BAD_ZONE_STATE);
899 		} else if (err != Z_NO_ZONE) {
900 			return (err);
901 		}
902 
903 		(void) strlcpy(handle->zone_dh_delete_name, curname,
904 		    sizeof (handle->zone_dh_delete_name));
905 		assert(is_renaming(handle));
906 	} else if (is_renaming(handle)) {
907 		err = zone_get_state(handle->zone_dh_delete_name, &state);
908 		if (err == Z_OK) {
909 			if (state > ZONE_STATE_INSTALLED)
910 				return (Z_BAD_ZONE_STATE);
911 		} else if (err != Z_NO_ZONE) {
912 			return (err);
913 		}
914 	}
915 
916 	if ((err = setrootattr(handle, DTD_ATTR_NAME, name)) != Z_OK) {
917 		/*
918 		 * Restore the deletename to whatever it was at the
919 		 * top of the routine, since we've had a failure.
920 		 */
921 		(void) strlcpy(handle->zone_dh_delete_name, old_delname,
922 		    sizeof (handle->zone_dh_delete_name));
923 		return (err);
924 	}
925 
926 	/*
927 	 * Record the old admins from the old zonename
928 	 * so that they can be deleted when the operation is committed.
929 	 */
930 	if ((err = insert_admins(handle, curname)) != Z_OK)
931 		return (err);
932 	else
933 		return (Z_OK);
934 }
935 
936 int
zonecfg_get_zonepath(zone_dochandle_t handle,char * path,size_t pathsize)937 zonecfg_get_zonepath(zone_dochandle_t handle, char *path, size_t pathsize)
938 {
939 	size_t len;
940 
941 	if ((len = strlcpy(path, zonecfg_root, pathsize)) >= pathsize)
942 		return (Z_TOO_BIG);
943 	return (getrootattr(handle, DTD_ATTR_ZONEPATH, path + len,
944 	    pathsize - len));
945 }
946 
947 int
zonecfg_set_zonepath(zone_dochandle_t handle,char * zonepath)948 zonecfg_set_zonepath(zone_dochandle_t handle, char *zonepath)
949 {
950 	size_t len;
951 	char *modpath, *copy_mp, *curr_mp;	/* modified path ptrs */
952 	char last_copied;
953 	int ret;
954 
955 	/*
956 	 * Collapse multiple contiguous slashes and remove trailing slash.
957 	 */
958 	modpath = strdup(zonepath);
959 	if (modpath == NULL)
960 		return (Z_NOMEM);
961 	last_copied = '\0';
962 	for (copy_mp = curr_mp = modpath; *curr_mp != '\0'; curr_mp++) {
963 		if (*curr_mp != '/' || last_copied != '/') {
964 			last_copied = *copy_mp = *curr_mp;
965 			copy_mp++;
966 		}
967 	}
968 	if (last_copied == '/')
969 		copy_mp--;
970 	*copy_mp = '\0';
971 
972 	/*
973 	 * The user deals in absolute paths in the running global zone, but the
974 	 * internal configuration files deal with boot environment relative
975 	 * paths.  Strip out the alternate root when specified.
976 	 */
977 	len = strlen(zonecfg_root);
978 	if (strncmp(modpath, zonecfg_root, len) != 0 || modpath[len] != '/') {
979 		free(modpath);
980 		return (Z_BAD_PROPERTY);
981 	}
982 	curr_mp = modpath + len;
983 	ret = setrootattr(handle, DTD_ATTR_ZONEPATH, curr_mp);
984 	free(modpath);
985 	return (ret);
986 }
987 
988 static int
i_zonecfg_get_brand(zone_dochandle_t handle,char * brand,size_t brandsize,boolean_t default_query)989 i_zonecfg_get_brand(zone_dochandle_t handle, char *brand, size_t brandsize,
990     boolean_t default_query)
991 {
992 	int ret, sz;
993 
994 	ret = getrootattr(handle, DTD_ATTR_BRAND, brand, brandsize);
995 
996 	/*
997 	 * If the lookup failed, or succeeded in finding a non-null brand
998 	 * string then return.
999 	 */
1000 	if (ret != Z_OK || brand[0] != '\0')
1001 		return (ret);
1002 
1003 	if (!default_query) {
1004 		/* If the zone has no brand, it is the default brand. */
1005 		return (zonecfg_default_brand(brand, brandsize));
1006 	}
1007 
1008 	/* if SUNWdefault didn't specify a brand, fallback to "native" */
1009 	sz = strlcpy(brand, NATIVE_BRAND_NAME, brandsize);
1010 	if (sz >= brandsize)
1011 		return (Z_TOO_BIG);
1012 	return (Z_OK);
1013 }
1014 
1015 int
zonecfg_get_brand(zone_dochandle_t handle,char * brand,size_t brandsize)1016 zonecfg_get_brand(zone_dochandle_t handle, char *brand, size_t brandsize)
1017 {
1018 	return (i_zonecfg_get_brand(handle, brand, brandsize, B_FALSE));
1019 }
1020 
1021 int
zonecfg_set_brand(zone_dochandle_t handle,char * brand)1022 zonecfg_set_brand(zone_dochandle_t handle, char *brand)
1023 {
1024 	return (setrootattr(handle, DTD_ATTR_BRAND, brand));
1025 }
1026 
1027 int
zonecfg_get_autoboot(zone_dochandle_t handle,boolean_t * autoboot)1028 zonecfg_get_autoboot(zone_dochandle_t handle, boolean_t *autoboot)
1029 {
1030 	char autobootstr[DTD_ENTITY_BOOL_LEN];
1031 	int ret;
1032 
1033 	if ((ret = getrootattr(handle, DTD_ATTR_AUTOBOOT, autobootstr,
1034 	    sizeof (autobootstr))) != Z_OK)
1035 		return (ret);
1036 
1037 	if (strcmp(autobootstr, DTD_ENTITY_TRUE) == 0)
1038 		*autoboot = B_TRUE;
1039 	else if (strcmp(autobootstr, DTD_ENTITY_FALSE) == 0)
1040 		*autoboot = B_FALSE;
1041 	else
1042 		ret = Z_BAD_PROPERTY;
1043 	return (ret);
1044 }
1045 
1046 int
zonecfg_set_autoboot(zone_dochandle_t handle,boolean_t autoboot)1047 zonecfg_set_autoboot(zone_dochandle_t handle, boolean_t autoboot)
1048 {
1049 	return (setrootattr(handle, DTD_ATTR_AUTOBOOT,
1050 	    autoboot ? DTD_ENTITY_TRUE : DTD_ENTITY_FALSE));
1051 }
1052 
1053 int
zonecfg_get_pool(zone_dochandle_t handle,char * pool,size_t poolsize)1054 zonecfg_get_pool(zone_dochandle_t handle, char *pool, size_t poolsize)
1055 {
1056 	return (getrootattr(handle, DTD_ATTR_POOL, pool, poolsize));
1057 }
1058 
1059 int
zonecfg_set_pool(zone_dochandle_t handle,char * pool)1060 zonecfg_set_pool(zone_dochandle_t handle, char *pool)
1061 {
1062 	return (setrootattr(handle, DTD_ATTR_POOL, pool));
1063 }
1064 
1065 int
zonecfg_get_limitpriv(zone_dochandle_t handle,char ** limitpriv)1066 zonecfg_get_limitpriv(zone_dochandle_t handle, char **limitpriv)
1067 {
1068 	return (get_alloc_rootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv));
1069 }
1070 
1071 int
zonecfg_set_limitpriv(zone_dochandle_t handle,char * limitpriv)1072 zonecfg_set_limitpriv(zone_dochandle_t handle, char *limitpriv)
1073 {
1074 	return (setrootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv));
1075 }
1076 
1077 int
zonecfg_get_bootargs(zone_dochandle_t handle,char * bargs,size_t bargssize)1078 zonecfg_get_bootargs(zone_dochandle_t handle, char *bargs, size_t bargssize)
1079 {
1080 	return (getrootattr(handle, DTD_ATTR_BOOTARGS, bargs, bargssize));
1081 }
1082 
1083 int
zonecfg_set_bootargs(zone_dochandle_t handle,char * bargs)1084 zonecfg_set_bootargs(zone_dochandle_t handle, char *bargs)
1085 {
1086 	return (setrootattr(handle, DTD_ATTR_BOOTARGS, bargs));
1087 }
1088 
1089 int
zonecfg_get_sched_class(zone_dochandle_t handle,char * sched,size_t schedsize)1090 zonecfg_get_sched_class(zone_dochandle_t handle, char *sched, size_t schedsize)
1091 {
1092 	return (getrootattr(handle, DTD_ATTR_SCHED, sched, schedsize));
1093 }
1094 
1095 int
zonecfg_set_sched(zone_dochandle_t handle,char * sched)1096 zonecfg_set_sched(zone_dochandle_t handle, char *sched)
1097 {
1098 	return (setrootattr(handle, DTD_ATTR_SCHED, sched));
1099 }
1100 
1101 /*
1102  * /etc/zones/index caches a vital piece of information which is also
1103  * in the <zonename>.xml file: the path to the zone.  This is for performance,
1104  * since we need to walk all zonepath's in order to be able to detect conflicts
1105  * (see crosscheck_zonepaths() in the zoneadm command).
1106  *
1107  * An additional complexity is that when doing a rename, we'd like the entire
1108  * index update operation (rename, and potential state changes) to be atomic.
1109  * In general, the operation of this function should succeed or fail as
1110  * a unit.
1111  */
1112 int
zonecfg_refresh_index_file(zone_dochandle_t handle)1113 zonecfg_refresh_index_file(zone_dochandle_t handle)
1114 {
1115 	char name[ZONENAME_MAX], zonepath[MAXPATHLEN];
1116 	struct zoneent ze;
1117 	int err;
1118 	int opcode;
1119 	char *zn;
1120 
1121 	bzero(&ze, sizeof (ze));
1122 	ze.zone_state = -1;	/* Preserve existing state in index */
1123 
1124 	if ((err = zonecfg_get_name(handle, name, sizeof (name))) != Z_OK)
1125 		return (err);
1126 	(void) strlcpy(ze.zone_name, name, sizeof (ze.zone_name));
1127 
1128 	if ((err = zonecfg_get_zonepath(handle, zonepath,
1129 	    sizeof (zonepath))) != Z_OK)
1130 		return (err);
1131 	(void) strlcpy(ze.zone_path, zonepath + strlen(zonecfg_root),
1132 	    sizeof (ze.zone_path));
1133 
1134 	if (is_renaming(handle)) {
1135 		opcode = PZE_MODIFY;
1136 		(void) strlcpy(ze.zone_name, handle->zone_dh_delete_name,
1137 		    sizeof (ze.zone_name));
1138 		(void) strlcpy(ze.zone_newname, name, sizeof (ze.zone_newname));
1139 	} else if (is_new(handle)) {
1140 		FILE *cookie;
1141 		/*
1142 		 * Be tolerant of the zone already existing in the index file,
1143 		 * since we might be forcibly overwriting an existing
1144 		 * configuration with a new one (for example 'create -F'
1145 		 * in zonecfg).
1146 		 */
1147 		opcode = PZE_ADD;
1148 		cookie = setzoneent();
1149 		while ((zn = getzoneent(cookie)) != NULL) {
1150 			if (strcmp(zn, name) == 0) {
1151 				opcode = PZE_MODIFY;
1152 				free(zn);
1153 				break;
1154 			}
1155 			free(zn);
1156 		}
1157 		endzoneent(cookie);
1158 		ze.zone_state = ZONE_STATE_CONFIGURED;
1159 	} else {
1160 		opcode = PZE_MODIFY;
1161 	}
1162 
1163 	if ((err = putzoneent(&ze, opcode)) != Z_OK)
1164 		return (err);
1165 
1166 	return (Z_OK);
1167 }
1168 
1169 /*
1170  * The goal of this routine is to cause the index file update and the
1171  * document save to happen as an atomic operation.  We do the document
1172  * first, saving a backup copy using a hard link; if that succeeds, we go
1173  * on to the index.  If that fails, we roll the document back into place.
1174  *
1175  * Strategy:
1176  *
1177  * New zone 'foo' configuration:
1178  *	Create tmpfile (zonecfg.xxxxxx)
1179  *	Write XML to tmpfile
1180  *	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
1181  *	Add entry to index file
1182  *	If it fails, delete foo.xml, leaving nothing behind.
1183  *
1184  * Save existing zone 'foo':
1185  *	Make backup of foo.xml -> .backup
1186  *	Create tmpfile (zonecfg.xxxxxx)
1187  *	Write XML to tmpfile
1188  *	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
1189  *	Modify index file as needed
1190  *	If it fails, recover from .backup -> foo.xml
1191  *
1192  * Rename 'foo' to 'bar':
1193  *	Create tmpfile (zonecfg.xxxxxx)
1194  *	Write XML to tmpfile
1195  *	Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml)
1196  *	Add entry for 'bar' to index file, Remove entry for 'foo' (refresh)
1197  *	If it fails, delete bar.xml; foo.xml is left behind.
1198  */
1199 static int
zonecfg_save_impl(zone_dochandle_t handle,char * filename)1200 zonecfg_save_impl(zone_dochandle_t handle, char *filename)
1201 {
1202 	char tmpfile[MAXPATHLEN];
1203 	char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN];
1204 	int tmpfd, err, valid;
1205 	xmlValidCtxt cvp = { NULL };
1206 	boolean_t backup;
1207 
1208 	(void) strlcpy(tmpfile, filename, sizeof (tmpfile));
1209 	(void) dirname(tmpfile);
1210 	(void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile));
1211 
1212 	tmpfd = mkstemp(tmpfile);
1213 	if (tmpfd == -1) {
1214 		(void) unlink(tmpfile);
1215 		return (Z_TEMP_FILE);
1216 	}
1217 	(void) close(tmpfd);
1218 
1219 	cvp.error = zonecfg_error_func;
1220 	cvp.warning = zonecfg_error_func;
1221 
1222 	/*
1223 	 * We do a final validation of the document.  Since the library has
1224 	 * malfunctioned if it fails to validate, we follow-up with an
1225 	 * assert() that the doc is valid.
1226 	 */
1227 	valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1228 	assert(valid != 0);
1229 
1230 	if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0)
1231 		goto err;
1232 
1233 	(void) chmod(tmpfile, 0644);
1234 
1235 	/*
1236 	 * In the event we are doing a standard save, hard link a copy of the
1237 	 * original file in .backup.<pid>.filename so we can restore it if
1238 	 * something goes wrong.
1239 	 */
1240 	if (!is_new(handle) && !is_renaming(handle)) {
1241 		backup = B_TRUE;
1242 
1243 		(void) strlcpy(bakdir, filename, sizeof (bakdir));
1244 		(void) strlcpy(bakbase, filename, sizeof (bakbase));
1245 		(void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s",
1246 		    dirname(bakdir), getpid(), basename(bakbase));
1247 
1248 		if (link(filename, bakfile) == -1) {
1249 			err = errno;
1250 			(void) unlink(tmpfile);
1251 			if (errno == EACCES)
1252 				return (Z_ACCES);
1253 			return (Z_MISC_FS);
1254 		}
1255 	}
1256 
1257 	/*
1258 	 * Move the new document over top of the old.
1259 	 * i.e.:   zonecfg.XXXXXX  ->  myzone.xml
1260 	 */
1261 	if (rename(tmpfile, filename) == -1) {
1262 		err = errno;
1263 		(void) unlink(tmpfile);
1264 		if (backup)
1265 			(void) unlink(bakfile);
1266 		if (err == EACCES)
1267 			return (Z_ACCES);
1268 		return (Z_MISC_FS);
1269 	}
1270 
1271 	/*
1272 	 * If this is a snapshot, we're done-- don't add an index entry.
1273 	 */
1274 	if (is_snapshot(handle))
1275 		return (Z_OK);
1276 
1277 	/* now update the index file to reflect whatever we just did */
1278 	if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) {
1279 		if (backup) {
1280 			/*
1281 			 * Try to restore from our backup.
1282 			 */
1283 			(void) unlink(filename);
1284 			(void) rename(bakfile, filename);
1285 		} else {
1286 			/*
1287 			 * Either the zone is new, in which case we can delete
1288 			 * new.xml, or we're doing a rename, so ditto.
1289 			 */
1290 			assert(is_new(handle) || is_renaming(handle));
1291 			(void) unlink(filename);
1292 		}
1293 		return (Z_UPDATING_INDEX);
1294 	}
1295 
1296 	if (backup)
1297 		(void) unlink(bakfile);
1298 
1299 	return (Z_OK);
1300 
1301 err:
1302 	(void) unlink(tmpfile);
1303 	return (Z_SAVING_FILE);
1304 }
1305 
1306 int
zonecfg_save(zone_dochandle_t handle)1307 zonecfg_save(zone_dochandle_t handle)
1308 {
1309 	char zname[ZONENAME_MAX], path[MAXPATHLEN];
1310 	char delpath[MAXPATHLEN];
1311 	int err = Z_SAVING_FILE;
1312 
1313 	if (zonecfg_check_handle(handle) != Z_OK)
1314 		return (Z_BAD_HANDLE);
1315 
1316 	/*
1317 	 * We don't support saving snapshots or a tree containing a sw
1318 	 * inventory at this time.
1319 	 */
1320 	if (handle->zone_dh_snapshot || handle->zone_dh_sw_inv)
1321 		return (Z_INVAL);
1322 
1323 	if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK)
1324 		return (err);
1325 
1326 	if (!config_file_path(zname, path))
1327 		return (Z_MISC_FS);
1328 
1329 	addcomment(handle, "\n    DO NOT EDIT THIS "
1330 	    "FILE.  Use zonecfg(1M) instead.\n");
1331 
1332 	/*
1333 	 * Update user_attr first so that it will be older
1334 	 * than the config file.
1335 	 */
1336 	(void) zonecfg_authorize_users(handle, zname);
1337 	err = zonecfg_save_impl(handle, path);
1338 
1339 	stripcomments(handle);
1340 
1341 	if (err != Z_OK)
1342 		return (err);
1343 
1344 	handle->zone_dh_newzone = B_FALSE;
1345 
1346 	if (is_renaming(handle)) {
1347 		if (config_file_path(handle->zone_dh_delete_name, delpath))
1348 			(void) unlink(delpath);
1349 		handle->zone_dh_delete_name[0] = '\0';
1350 	}
1351 
1352 	return (Z_OK);
1353 }
1354 
1355 int
zonecfg_verify_save(zone_dochandle_t handle,char * filename)1356 zonecfg_verify_save(zone_dochandle_t handle, char *filename)
1357 {
1358 	int valid;
1359 
1360 	xmlValidCtxt cvp = { NULL };
1361 
1362 	if (zonecfg_check_handle(handle) != Z_OK)
1363 		return (Z_BAD_HANDLE);
1364 
1365 	cvp.error = zonecfg_error_func;
1366 	cvp.warning = zonecfg_error_func;
1367 
1368 	/*
1369 	 * We do a final validation of the document.  Since the library has
1370 	 * malfunctioned if it fails to validate, we follow-up with an
1371 	 * assert() that the doc is valid.
1372 	 */
1373 	valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1374 	assert(valid != 0);
1375 
1376 	if (xmlSaveFormatFile(filename, handle->zone_dh_doc, 1) <= 0)
1377 		return (Z_SAVING_FILE);
1378 
1379 	return (Z_OK);
1380 }
1381 
1382 int
zonecfg_detach_save(zone_dochandle_t handle,uint_t flags)1383 zonecfg_detach_save(zone_dochandle_t handle, uint_t flags)
1384 {
1385 	char zname[ZONENAME_MAX];
1386 	char path[MAXPATHLEN];
1387 	char migpath[MAXPATHLEN];
1388 	xmlValidCtxt cvp = { NULL };
1389 	int err = Z_SAVING_FILE;
1390 	int valid;
1391 
1392 	if (zonecfg_check_handle(handle) != Z_OK)
1393 		return (Z_BAD_HANDLE);
1394 
1395 	if (flags & ZONE_DRY_RUN) {
1396 		(void) strlcpy(migpath, "-", sizeof (migpath));
1397 	} else {
1398 		if ((err = zonecfg_get_name(handle, zname, sizeof (zname)))
1399 		    != Z_OK)
1400 			return (err);
1401 
1402 		if ((err = zone_get_zonepath(zname, path, sizeof (path)))
1403 		    != Z_OK)
1404 			return (err);
1405 
1406 		if (snprintf(migpath, sizeof (migpath), "%s/%s", path,
1407 		    ZONE_DETACHED) >= sizeof (migpath))
1408 			return (Z_NOMEM);
1409 	}
1410 
1411 	if ((err = operation_prep(handle)) != Z_OK)
1412 		return (err);
1413 
1414 	addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
1415 	    "Use zonecfg(1M) and zoneadm(1M) attach.\n");
1416 
1417 	cvp.error = zonecfg_error_func;
1418 	cvp.warning = zonecfg_error_func;
1419 
1420 	/*
1421 	 * We do a final validation of the document.  Since the library has
1422 	 * malfunctioned if it fails to validate, we follow-up with an
1423 	 * assert() that the doc is valid.
1424 	 */
1425 	valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1426 	assert(valid != 0);
1427 
1428 	if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0)
1429 		return (Z_SAVING_FILE);
1430 
1431 	if (!(flags & ZONE_DRY_RUN))
1432 		(void) chmod(migpath, 0644);
1433 
1434 	stripcomments(handle);
1435 
1436 	handle->zone_dh_newzone = B_FALSE;
1437 
1438 	return (Z_OK);
1439 }
1440 
1441 boolean_t
zonecfg_detached(const char * path)1442 zonecfg_detached(const char *path)
1443 {
1444 	char		migpath[MAXPATHLEN];
1445 	struct stat	buf;
1446 
1447 	if (snprintf(migpath, sizeof (migpath), "%s/%s", path, ZONE_DETACHED) >=
1448 	    sizeof (migpath))
1449 		return (B_FALSE);
1450 
1451 	if (stat(migpath, &buf) != -1)
1452 		return (B_TRUE);
1453 
1454 	return (B_FALSE);
1455 }
1456 
1457 void
zonecfg_rm_detached(zone_dochandle_t handle,boolean_t forced)1458 zonecfg_rm_detached(zone_dochandle_t handle, boolean_t forced)
1459 {
1460 	char zname[ZONENAME_MAX];
1461 	char path[MAXPATHLEN];
1462 	char detached[MAXPATHLEN];
1463 	char attached[MAXPATHLEN];
1464 
1465 	if (zonecfg_check_handle(handle) != Z_OK)
1466 		return;
1467 
1468 	if (zonecfg_get_name(handle, zname, sizeof (zname)) != Z_OK)
1469 		return;
1470 
1471 	if (zone_get_zonepath(zname, path, sizeof (path)) != Z_OK)
1472 		return;
1473 
1474 	(void) snprintf(detached, sizeof (detached), "%s/%s", path,
1475 	    ZONE_DETACHED);
1476 	(void) snprintf(attached, sizeof (attached), "%s/%s", path,
1477 	    ATTACH_FORCED);
1478 
1479 	if (forced) {
1480 		(void) rename(detached, attached);
1481 	} else {
1482 		(void) unlink(attached);
1483 		(void) unlink(detached);
1484 	}
1485 }
1486 
1487 /*
1488  * Special case: if access(2) fails with ENOENT, then try again using
1489  * ZONE_CONFIG_ROOT instead of config_file_path(zonename).  This is how we
1490  * work around the case of a config file which has not been created yet:
1491  * the user will need access to the directory so use that as a heuristic.
1492  */
1493 
1494 int
zonecfg_access(const char * zonename,int amode)1495 zonecfg_access(const char *zonename, int amode)
1496 {
1497 	char path[MAXPATHLEN];
1498 
1499 	if (!config_file_path(zonename, path))
1500 		return (Z_INVAL);
1501 	if (access(path, amode) == 0)
1502 		return (Z_OK);
1503 	if (errno == ENOENT) {
1504 		if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1505 		    ZONE_CONFIG_ROOT) >= sizeof (path))
1506 			return (Z_INVAL);
1507 		if (access(path, amode) == 0)
1508 			return (Z_OK);
1509 	}
1510 	if (errno == EACCES)
1511 		return (Z_ACCES);
1512 	if (errno == EINVAL)
1513 		return (Z_INVAL);
1514 	return (Z_MISC_FS);
1515 }
1516 
1517 int
zonecfg_create_snapshot(const char * zonename)1518 zonecfg_create_snapshot(const char *zonename)
1519 {
1520 	zone_dochandle_t handle;
1521 	char path[MAXPATHLEN], zonepath[MAXPATHLEN], rpath[MAXPATHLEN];
1522 	int error = Z_OK, res;
1523 
1524 	if ((handle = zonecfg_init_handle()) == NULL) {
1525 		return (Z_NOMEM);
1526 	}
1527 
1528 	handle->zone_dh_newzone = B_TRUE;
1529 	handle->zone_dh_snapshot = B_TRUE;
1530 
1531 	if ((error = zonecfg_get_handle(zonename, handle)) != Z_OK)
1532 		goto out;
1533 	if ((error = operation_prep(handle)) != Z_OK)
1534 		goto out;
1535 	error = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath));
1536 	if (error != Z_OK)
1537 		goto out;
1538 	if ((res = resolvepath(zonepath, rpath, sizeof (rpath))) == -1) {
1539 		error = Z_RESOLVED_PATH;
1540 		goto out;
1541 	}
1542 	/*
1543 	 * If the resolved path is not the same as the original path, then
1544 	 * save the resolved path in the snapshot, thus preventing any
1545 	 * potential problems down the line when zoneadmd goes to unmount
1546 	 * file systems and depends on initial string matches with resolved
1547 	 * paths.
1548 	 */
1549 	rpath[res] = '\0';
1550 	if (strcmp(zonepath, rpath) != 0) {
1551 		if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK)
1552 			goto out;
1553 	}
1554 	if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1555 	    ZONE_SNAPSHOT_ROOT) >= sizeof (path)) {
1556 		error = Z_MISC_FS;
1557 		goto out;
1558 	}
1559 	if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) {
1560 		error = Z_MISC_FS;
1561 		goto out;
1562 	}
1563 
1564 	if (!snap_file_path(zonename, path)) {
1565 		error = Z_MISC_FS;
1566 		goto out;
1567 	}
1568 
1569 	addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
1570 	    "It is a snapshot of running zone state.\n");
1571 
1572 	error = zonecfg_save_impl(handle, path);
1573 
1574 	stripcomments(handle);
1575 
1576 out:
1577 	zonecfg_fini_handle(handle);
1578 	return (error);
1579 }
1580 
1581 int
zonecfg_get_iptype(zone_dochandle_t handle,zone_iptype_t * iptypep)1582 zonecfg_get_iptype(zone_dochandle_t handle, zone_iptype_t *iptypep)
1583 {
1584 	char property[10]; /* 10 is big enough for "shared"/"exclusive" */
1585 	int err;
1586 
1587 	err = getrootattr(handle, DTD_ATTR_IPTYPE, property, sizeof (property));
1588 	if (err == Z_BAD_PROPERTY) {
1589 		/* Return default value */
1590 		*iptypep = ZS_SHARED;
1591 		return (Z_OK);
1592 	} else if (err != Z_OK) {
1593 		return (err);
1594 	}
1595 
1596 	if (strlen(property) == 0 ||
1597 	    strcmp(property, "shared") == 0)
1598 		*iptypep = ZS_SHARED;
1599 	else if (strcmp(property, "exclusive") == 0)
1600 		*iptypep = ZS_EXCLUSIVE;
1601 	else
1602 		return (Z_INVAL);
1603 
1604 	return (Z_OK);
1605 }
1606 
1607 int
zonecfg_set_iptype(zone_dochandle_t handle,zone_iptype_t iptype)1608 zonecfg_set_iptype(zone_dochandle_t handle, zone_iptype_t iptype)
1609 {
1610 	xmlNodePtr cur;
1611 
1612 	if (handle == NULL)
1613 		return (Z_INVAL);
1614 
1615 	cur = xmlDocGetRootElement(handle->zone_dh_doc);
1616 	if (cur == NULL) {
1617 		return (Z_EMPTY_DOCUMENT);
1618 	}
1619 
1620 	if (xmlStrcmp(cur->name, DTD_ELEM_ZONE) != 0) {
1621 		return (Z_WRONG_DOC_TYPE);
1622 	}
1623 	switch (iptype) {
1624 	case ZS_SHARED:
1625 		/*
1626 		 * Since "shared" is the default, we don't write it to the
1627 		 * configuration file, so that it's easier to migrate those
1628 		 * zones elsewhere, eg., to systems which are not IP-Instances
1629 		 * aware.
1630 		 * xmlUnsetProp only fails when the attribute doesn't exist,
1631 		 * which we don't care.
1632 		 */
1633 		(void) xmlUnsetProp(cur, DTD_ATTR_IPTYPE);
1634 		break;
1635 	case ZS_EXCLUSIVE:
1636 		if (xmlSetProp(cur, DTD_ATTR_IPTYPE,
1637 		    (const xmlChar *) "exclusive") == NULL)
1638 			return (Z_INVAL);
1639 		break;
1640 	}
1641 	return (Z_OK);
1642 }
1643 
1644 static int
newprop(xmlNodePtr node,const xmlChar * attrname,char * src)1645 newprop(xmlNodePtr node, const xmlChar *attrname, char *src)
1646 {
1647 	xmlAttrPtr newattr;
1648 
1649 	newattr = xmlNewProp(node, attrname, (xmlChar *)src);
1650 	if (newattr == NULL) {
1651 		xmlUnlinkNode(node);
1652 		xmlFreeNode(node);
1653 		return (Z_BAD_PROPERTY);
1654 	}
1655 	return (Z_OK);
1656 }
1657 
1658 static int
zonecfg_add_filesystem_core(zone_dochandle_t handle,struct zone_fstab * tabptr)1659 zonecfg_add_filesystem_core(zone_dochandle_t handle, struct zone_fstab *tabptr)
1660 {
1661 	xmlNodePtr newnode, cur = handle->zone_dh_cur, options_node;
1662 	zone_fsopt_t *ptr;
1663 	int err;
1664 
1665 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_FS, NULL);
1666 	if ((err = newprop(newnode, DTD_ATTR_SPECIAL,
1667 	    tabptr->zone_fs_special)) != Z_OK)
1668 		return (err);
1669 	if (tabptr->zone_fs_raw[0] != '\0' &&
1670 	    (err = newprop(newnode, DTD_ATTR_RAW, tabptr->zone_fs_raw)) != Z_OK)
1671 		return (err);
1672 	if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK)
1673 		return (err);
1674 	if ((err = newprop(newnode, DTD_ATTR_TYPE,
1675 	    tabptr->zone_fs_type)) != Z_OK)
1676 		return (err);
1677 	if (tabptr->zone_fs_options != NULL) {
1678 		for (ptr = tabptr->zone_fs_options; ptr != NULL;
1679 		    ptr = ptr->zone_fsopt_next) {
1680 			options_node = xmlNewTextChild(newnode, NULL,
1681 			    DTD_ELEM_FSOPTION, NULL);
1682 			if ((err = newprop(options_node, DTD_ATTR_NAME,
1683 			    ptr->zone_fsopt_opt)) != Z_OK)
1684 				return (err);
1685 		}
1686 	}
1687 	return (Z_OK);
1688 }
1689 
1690 int
zonecfg_add_filesystem(zone_dochandle_t handle,struct zone_fstab * tabptr)1691 zonecfg_add_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
1692 {
1693 	int err;
1694 
1695 	if (tabptr == NULL)
1696 		return (Z_INVAL);
1697 
1698 	if ((err = operation_prep(handle)) != Z_OK)
1699 		return (err);
1700 
1701 	if ((err = zonecfg_add_filesystem_core(handle, tabptr)) != Z_OK)
1702 		return (err);
1703 
1704 	return (Z_OK);
1705 }
1706 
1707 int
zonecfg_add_fs_option(struct zone_fstab * tabptr,char * option)1708 zonecfg_add_fs_option(struct zone_fstab *tabptr, char *option)
1709 {
1710 	zone_fsopt_t *last, *old, *new;
1711 
1712 	last = tabptr->zone_fs_options;
1713 	for (old = last; old != NULL; old = old->zone_fsopt_next)
1714 		last = old;	/* walk to the end of the list */
1715 	new = (zone_fsopt_t *)malloc(sizeof (zone_fsopt_t));
1716 	if (new == NULL)
1717 		return (Z_NOMEM);
1718 	(void) strlcpy(new->zone_fsopt_opt, option,
1719 	    sizeof (new->zone_fsopt_opt));
1720 	new->zone_fsopt_next = NULL;
1721 	if (last == NULL)
1722 		tabptr->zone_fs_options = new;
1723 	else
1724 		last->zone_fsopt_next = new;
1725 	return (Z_OK);
1726 }
1727 
1728 int
zonecfg_remove_fs_option(struct zone_fstab * tabptr,char * option)1729 zonecfg_remove_fs_option(struct zone_fstab *tabptr, char *option)
1730 {
1731 	zone_fsopt_t *last, *this, *next;
1732 
1733 	last = tabptr->zone_fs_options;
1734 	for (this = last; this != NULL; this = this->zone_fsopt_next) {
1735 		if (strcmp(this->zone_fsopt_opt, option) == 0) {
1736 			next = this->zone_fsopt_next;
1737 			if (this == tabptr->zone_fs_options)
1738 				tabptr->zone_fs_options = next;
1739 			else
1740 				last->zone_fsopt_next = next;
1741 			free(this);
1742 			return (Z_OK);
1743 		} else
1744 			last = this;
1745 	}
1746 	return (Z_NO_PROPERTY_ID);
1747 }
1748 
1749 void
zonecfg_free_fs_option_list(zone_fsopt_t * list)1750 zonecfg_free_fs_option_list(zone_fsopt_t *list)
1751 {
1752 	zone_fsopt_t *this, *next;
1753 
1754 	for (this = list; this != NULL; this = next) {
1755 		next = this->zone_fsopt_next;
1756 		free(this);
1757 	}
1758 }
1759 
1760 void
zonecfg_free_rctl_value_list(struct zone_rctlvaltab * valtab)1761 zonecfg_free_rctl_value_list(struct zone_rctlvaltab *valtab)
1762 {
1763 	if (valtab == NULL)
1764 		return;
1765 	zonecfg_free_rctl_value_list(valtab->zone_rctlval_next);
1766 	free(valtab);
1767 }
1768 
1769 static boolean_t
match_prop(xmlNodePtr cur,const xmlChar * attr,char * user_prop)1770 match_prop(xmlNodePtr cur, const xmlChar *attr, char *user_prop)
1771 {
1772 	xmlChar *gotten_prop;
1773 	int prop_result;
1774 
1775 	gotten_prop = xmlGetProp(cur, attr);
1776 	if (gotten_prop == NULL)	/* shouldn't happen */
1777 		return (B_FALSE);
1778 	prop_result = xmlStrcmp(gotten_prop, (const xmlChar *) user_prop);
1779 	xmlFree(gotten_prop);
1780 	return ((prop_result == 0));	/* empty strings will match */
1781 }
1782 
1783 static int
zonecfg_delete_filesystem_core(zone_dochandle_t handle,struct zone_fstab * tabptr)1784 zonecfg_delete_filesystem_core(zone_dochandle_t handle,
1785     struct zone_fstab *tabptr)
1786 {
1787 	xmlNodePtr cur = handle->zone_dh_cur;
1788 	boolean_t dir_match, spec_match, raw_match, type_match;
1789 
1790 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1791 		if (xmlStrcmp(cur->name, DTD_ELEM_FS))
1792 			continue;
1793 		dir_match = match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir);
1794 		spec_match = match_prop(cur, DTD_ATTR_SPECIAL,
1795 		    tabptr->zone_fs_special);
1796 		raw_match = match_prop(cur, DTD_ATTR_RAW,
1797 		    tabptr->zone_fs_raw);
1798 		type_match = match_prop(cur, DTD_ATTR_TYPE,
1799 		    tabptr->zone_fs_type);
1800 		if (dir_match && spec_match && raw_match && type_match) {
1801 			xmlUnlinkNode(cur);
1802 			xmlFreeNode(cur);
1803 			return (Z_OK);
1804 		}
1805 	}
1806 	return (Z_NO_RESOURCE_ID);
1807 }
1808 
1809 int
zonecfg_delete_filesystem(zone_dochandle_t handle,struct zone_fstab * tabptr)1810 zonecfg_delete_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
1811 {
1812 	int err;
1813 
1814 	if (tabptr == NULL)
1815 		return (Z_INVAL);
1816 
1817 	if ((err = operation_prep(handle)) != Z_OK)
1818 		return (err);
1819 
1820 	if ((err = zonecfg_delete_filesystem_core(handle, tabptr)) != Z_OK)
1821 		return (err);
1822 
1823 	return (Z_OK);
1824 }
1825 
1826 int
zonecfg_modify_filesystem(zone_dochandle_t handle,struct zone_fstab * oldtabptr,struct zone_fstab * newtabptr)1827 zonecfg_modify_filesystem(
1828 	zone_dochandle_t handle,
1829 	struct zone_fstab *oldtabptr,
1830 	struct zone_fstab *newtabptr)
1831 {
1832 	int err;
1833 
1834 	if (oldtabptr == NULL || newtabptr == NULL)
1835 		return (Z_INVAL);
1836 
1837 	if ((err = operation_prep(handle)) != Z_OK)
1838 		return (err);
1839 
1840 	if ((err = zonecfg_delete_filesystem_core(handle, oldtabptr)) != Z_OK)
1841 		return (err);
1842 
1843 	if ((err = zonecfg_add_filesystem_core(handle, newtabptr)) != Z_OK)
1844 		return (err);
1845 
1846 	return (Z_OK);
1847 }
1848 
1849 int
zonecfg_lookup_filesystem(zone_dochandle_t handle,struct zone_fstab * tabptr)1850 zonecfg_lookup_filesystem(
1851 	zone_dochandle_t handle,
1852 	struct zone_fstab *tabptr)
1853 {
1854 	xmlNodePtr cur, options, firstmatch;
1855 	int err;
1856 	char dirname[MAXPATHLEN], special[MAXPATHLEN], raw[MAXPATHLEN];
1857 	char type[FSTYPSZ];
1858 	char options_str[MAX_MNTOPT_STR];
1859 
1860 	if (tabptr == NULL)
1861 		return (Z_INVAL);
1862 
1863 	if ((err = operation_prep(handle)) != Z_OK)
1864 		return (err);
1865 
1866 	/*
1867 	 * Walk the list of children looking for matches on any properties
1868 	 * specified in the fstab parameter.  If more than one resource
1869 	 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return
1870 	 * Z_NO_RESOURCE_ID.
1871 	 */
1872 	cur = handle->zone_dh_cur;
1873 	firstmatch = NULL;
1874 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1875 		if (xmlStrcmp(cur->name, DTD_ELEM_FS))
1876 			continue;
1877 		if (strlen(tabptr->zone_fs_dir) > 0) {
1878 			if ((fetchprop(cur, DTD_ATTR_DIR, dirname,
1879 			    sizeof (dirname)) == Z_OK) &&
1880 			    (strcmp(tabptr->zone_fs_dir, dirname) == 0)) {
1881 				if (firstmatch == NULL)
1882 					firstmatch = cur;
1883 				else
1884 					return (Z_INSUFFICIENT_SPEC);
1885 			}
1886 		}
1887 		if (strlen(tabptr->zone_fs_special) > 0) {
1888 			if ((fetchprop(cur, DTD_ATTR_SPECIAL, special,
1889 			    sizeof (special)) == Z_OK)) {
1890 				if (strcmp(tabptr->zone_fs_special,
1891 				    special) == 0) {
1892 					if (firstmatch == NULL)
1893 						firstmatch = cur;
1894 					else if (firstmatch != cur)
1895 						return (Z_INSUFFICIENT_SPEC);
1896 				} else {
1897 					/*
1898 					 * If another property matched but this
1899 					 * one doesn't then reset firstmatch.
1900 					 */
1901 					if (firstmatch == cur)
1902 						firstmatch = NULL;
1903 				}
1904 			}
1905 		}
1906 		if (strlen(tabptr->zone_fs_raw) > 0) {
1907 			if ((fetchprop(cur, DTD_ATTR_RAW, raw,
1908 			    sizeof (raw)) == Z_OK)) {
1909 				if (strcmp(tabptr->zone_fs_raw, raw) == 0) {
1910 					if (firstmatch == NULL)
1911 						firstmatch = cur;
1912 					else if (firstmatch != cur)
1913 						return (Z_INSUFFICIENT_SPEC);
1914 				} else {
1915 					/*
1916 					 * If another property matched but this
1917 					 * one doesn't then reset firstmatch.
1918 					 */
1919 					if (firstmatch == cur)
1920 						firstmatch = NULL;
1921 				}
1922 			}
1923 		}
1924 		if (strlen(tabptr->zone_fs_type) > 0) {
1925 			if ((fetchprop(cur, DTD_ATTR_TYPE, type,
1926 			    sizeof (type)) == Z_OK)) {
1927 				if (strcmp(tabptr->zone_fs_type, type) == 0) {
1928 					if (firstmatch == NULL)
1929 						firstmatch = cur;
1930 					else if (firstmatch != cur)
1931 						return (Z_INSUFFICIENT_SPEC);
1932 				} else {
1933 					/*
1934 					 * If another property matched but this
1935 					 * one doesn't then reset firstmatch.
1936 					 */
1937 					if (firstmatch == cur)
1938 						firstmatch = NULL;
1939 				}
1940 			}
1941 		}
1942 	}
1943 
1944 	if (firstmatch == NULL)
1945 		return (Z_NO_RESOURCE_ID);
1946 
1947 	cur = firstmatch;
1948 
1949 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
1950 	    sizeof (tabptr->zone_fs_dir))) != Z_OK)
1951 		return (err);
1952 
1953 	if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
1954 	    sizeof (tabptr->zone_fs_special))) != Z_OK)
1955 		return (err);
1956 
1957 	if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
1958 	    sizeof (tabptr->zone_fs_raw))) != Z_OK)
1959 		return (err);
1960 
1961 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
1962 	    sizeof (tabptr->zone_fs_type))) != Z_OK)
1963 		return (err);
1964 
1965 	/* options are optional */
1966 	tabptr->zone_fs_options = NULL;
1967 	for (options = cur->xmlChildrenNode; options != NULL;
1968 	    options = options->next) {
1969 		if ((fetchprop(options, DTD_ATTR_NAME, options_str,
1970 		    sizeof (options_str)) != Z_OK))
1971 			break;
1972 		if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
1973 			break;
1974 	}
1975 	return (Z_OK);
1976 }
1977 
1978 /*
1979  * Compare two IP addresses in string form.  Allow for the possibility that
1980  * one might have "/<prefix-length>" at the end: allow a match on just the
1981  * IP address (or host name) part.
1982  */
1983 
1984 boolean_t
zonecfg_same_net_address(char * a1,char * a2)1985 zonecfg_same_net_address(char *a1, char *a2)
1986 {
1987 	char *slashp, *slashp1, *slashp2;
1988 	int result;
1989 
1990 	if (strcmp(a1, a2) == 0)
1991 		return (B_TRUE);
1992 
1993 	/*
1994 	 * If neither has a slash or both do, they need to match to be
1995 	 * considered the same, but they did not match above, so fail.
1996 	 */
1997 	slashp1 = strchr(a1, '/');
1998 	slashp2 = strchr(a2, '/');
1999 	if ((slashp1 == NULL && slashp2 == NULL) ||
2000 	    (slashp1 != NULL && slashp2 != NULL))
2001 		return (B_FALSE);
2002 
2003 	/*
2004 	 * Only one had a slash: pick that one, zero out the slash, compare
2005 	 * the "address only" strings, restore the slash, and return the
2006 	 * result of the comparison.
2007 	 */
2008 	slashp = (slashp1 == NULL) ? slashp2 : slashp1;
2009 	*slashp = '\0';
2010 	result = strcmp(a1, a2);
2011 	*slashp = '/';
2012 	return ((result == 0));
2013 }
2014 
2015 int
zonecfg_valid_net_address(char * address,struct lifreq * lifr)2016 zonecfg_valid_net_address(char *address, struct lifreq *lifr)
2017 {
2018 	struct sockaddr_in *sin4;
2019 	struct sockaddr_in6 *sin6;
2020 	struct addrinfo hints, *result;
2021 	char *slashp = strchr(address, '/');
2022 
2023 	bzero(lifr, sizeof (struct lifreq));
2024 	sin4 = (struct sockaddr_in *)&lifr->lifr_addr;
2025 	sin6 = (struct sockaddr_in6 *)&lifr->lifr_addr;
2026 	if (slashp != NULL)
2027 		*slashp = '\0';
2028 	if (inet_pton(AF_INET, address, &sin4->sin_addr) == 1) {
2029 		sin4->sin_family = AF_INET;
2030 	} else if (inet_pton(AF_INET6, address, &sin6->sin6_addr) == 1) {
2031 		if (slashp == NULL)
2032 			return (Z_IPV6_ADDR_PREFIX_LEN);
2033 		sin6->sin6_family = AF_INET6;
2034 	} else {
2035 		/* "address" may be a host name */
2036 		(void) memset(&hints, 0, sizeof (hints));
2037 		hints.ai_family = PF_INET;
2038 		if (getaddrinfo(address, NULL, &hints, &result) != 0)
2039 			return (Z_BOGUS_ADDRESS);
2040 		sin4->sin_family = result->ai_family;
2041 
2042 		(void) memcpy(&sin4->sin_addr,
2043 		    /* LINTED E_BAD_PTR_CAST_ALIGN */
2044 		    &((struct sockaddr_in *)result->ai_addr)->sin_addr,
2045 		    sizeof (struct in_addr));
2046 
2047 		freeaddrinfo(result);
2048 	}
2049 	return (Z_OK);
2050 }
2051 
2052 boolean_t
zonecfg_ifname_exists(sa_family_t af,char * ifname)2053 zonecfg_ifname_exists(sa_family_t af, char *ifname)
2054 {
2055 	struct lifreq lifr;
2056 	int so;
2057 	int save_errno;
2058 
2059 	(void) memset(&lifr, 0, sizeof (lifr));
2060 	(void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
2061 	lifr.lifr_addr.ss_family = af;
2062 	if ((so = socket(af, SOCK_DGRAM, 0)) < 0) {
2063 		/* Odd - can't tell if the ifname exists */
2064 		return (B_FALSE);
2065 	}
2066 	if (ioctl(so, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
2067 		save_errno = errno;
2068 		(void) close(so);
2069 		errno = save_errno;
2070 		return (B_FALSE);
2071 	}
2072 	(void) close(so);
2073 	return (B_TRUE);
2074 }
2075 
2076 /*
2077  * Determines whether there is a net resource with the physical interface, IP
2078  * address, and default router specified by 'tabptr' in the zone configuration
2079  * to which 'handle' refers.  'tabptr' must have an interface, an address, a
2080  * default router, or a combination of the three.  This function returns Z_OK
2081  * iff there is exactly one net resource matching the query specified by
2082  * 'tabptr'.  The function returns Z_INSUFFICIENT_SPEC if there are multiple
2083  * matches or 'tabptr' does not specify a physical interface, address, or
2084  * default router.  The function returns Z_NO_RESOURCE_ID if are no matches.
2085  *
2086  * Errors might also be returned if the entry that exactly matches the
2087  * query lacks critical network resource information.
2088  *
2089  * If there is a single match, then the matching entry's physical interface, IP
2090  * address, and default router information are stored in 'tabptr'.
2091  */
2092 int
zonecfg_lookup_nwif(zone_dochandle_t handle,struct zone_nwiftab * tabptr)2093 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2094 {
2095 	xmlNodePtr cur;
2096 	xmlNodePtr firstmatch;
2097 	int err;
2098 	char address[INET6_ADDRSTRLEN];
2099 	char physical[LIFNAMSIZ];
2100 	size_t addrspec;		/* nonzero if tabptr has IP addr */
2101 	size_t physspec;		/* nonzero if tabptr has interface */
2102 	size_t defrouterspec;		/* nonzero if tabptr has def. router */
2103 	size_t allowed_addrspec;
2104 	zone_iptype_t iptype;
2105 
2106 	if (tabptr == NULL)
2107 		return (Z_INVAL);
2108 
2109 	/*
2110 	 * Determine the fields that will be searched.  There must be at least
2111 	 * one.
2112 	 *
2113 	 * zone_nwif_address, zone_nwif_physical, and zone_nwif_defrouter are
2114 	 * arrays, so no NULL checks are necessary.
2115 	 */
2116 	addrspec = strlen(tabptr->zone_nwif_address);
2117 	physspec = strlen(tabptr->zone_nwif_physical);
2118 	defrouterspec = strlen(tabptr->zone_nwif_defrouter);
2119 	allowed_addrspec = strlen(tabptr->zone_nwif_allowed_address);
2120 	if (addrspec != 0 && allowed_addrspec != 0)
2121 		return (Z_INVAL); /* can't specify both */
2122 	if (addrspec == 0 && physspec == 0 && defrouterspec == 0 &&
2123 	    allowed_addrspec == 0)
2124 		return (Z_INSUFFICIENT_SPEC);
2125 
2126 	if ((err = operation_prep(handle)) != Z_OK)
2127 		return (err);
2128 
2129 	if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK)
2130 		return (err);
2131 	/*
2132 	 * Iterate over the configuration's elements and look for net elements
2133 	 * that match the query.
2134 	 */
2135 	firstmatch = NULL;
2136 	cur = handle->zone_dh_cur;
2137 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2138 		/* Skip non-net elements */
2139 		if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2140 			continue;
2141 
2142 		/*
2143 		 * If any relevant fields don't match the query, then skip
2144 		 * the current net element.
2145 		 */
2146 		if (physspec != 0 && (fetchprop(cur, DTD_ATTR_PHYSICAL,
2147 		    physical, sizeof (physical)) != Z_OK ||
2148 		    strcmp(tabptr->zone_nwif_physical, physical) != 0))
2149 			continue;
2150 		if (iptype == ZS_SHARED && addrspec != 0 &&
2151 		    (fetchprop(cur, DTD_ATTR_ADDRESS, address,
2152 		    sizeof (address)) != Z_OK ||
2153 		    !zonecfg_same_net_address(tabptr->zone_nwif_address,
2154 		    address)))
2155 			continue;
2156 		if (iptype == ZS_EXCLUSIVE && allowed_addrspec != 0 &&
2157 		    (fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS, address,
2158 		    sizeof (address)) != Z_OK ||
2159 		    !zonecfg_same_net_address(tabptr->zone_nwif_allowed_address,
2160 		    address)))
2161 			continue;
2162 		if (defrouterspec != 0 && (fetchprop(cur, DTD_ATTR_DEFROUTER,
2163 		    address, sizeof (address)) != Z_OK ||
2164 		    !zonecfg_same_net_address(tabptr->zone_nwif_defrouter,
2165 		    address)))
2166 			continue;
2167 
2168 		/*
2169 		 * The current net element matches the query.  Select it if
2170 		 * it's the first match; otherwise, abort the search.
2171 		 */
2172 		if (firstmatch == NULL)
2173 			firstmatch = cur;
2174 		else
2175 			return (Z_INSUFFICIENT_SPEC);
2176 	}
2177 	if (firstmatch == NULL)
2178 		return (Z_NO_RESOURCE_ID);
2179 
2180 	cur = firstmatch;
2181 
2182 	if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
2183 	    sizeof (tabptr->zone_nwif_physical))) != Z_OK)
2184 		return (err);
2185 
2186 	if (iptype == ZS_SHARED &&
2187 	    (err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
2188 	    sizeof (tabptr->zone_nwif_address))) != Z_OK)
2189 		return (err);
2190 
2191 	if (iptype == ZS_EXCLUSIVE &&
2192 	    (err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
2193 	    tabptr->zone_nwif_allowed_address,
2194 	    sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK)
2195 		return (err);
2196 
2197 	if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
2198 	    tabptr->zone_nwif_defrouter,
2199 	    sizeof (tabptr->zone_nwif_defrouter))) != Z_OK)
2200 		return (err);
2201 
2202 	return (Z_OK);
2203 }
2204 
2205 static int
zonecfg_add_nwif_core(zone_dochandle_t handle,struct zone_nwiftab * tabptr)2206 zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2207 {
2208 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
2209 	int err;
2210 
2211 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL);
2212 	if (strlen(tabptr->zone_nwif_address) > 0 &&
2213 	    (err = newprop(newnode, DTD_ATTR_ADDRESS,
2214 	    tabptr->zone_nwif_address)) != Z_OK)
2215 		return (err);
2216 	if (strlen(tabptr->zone_nwif_allowed_address) > 0 &&
2217 	    (err = newprop(newnode, DTD_ATTR_ALLOWED_ADDRESS,
2218 	    tabptr->zone_nwif_allowed_address)) != Z_OK)
2219 		return (err);
2220 	if ((err = newprop(newnode, DTD_ATTR_PHYSICAL,
2221 	    tabptr->zone_nwif_physical)) != Z_OK)
2222 		return (err);
2223 	/*
2224 	 * Do not add this property when it is not set, for backwards
2225 	 * compatibility and because it is optional.
2226 	 */
2227 	if ((strlen(tabptr->zone_nwif_defrouter) > 0) &&
2228 	    ((err = newprop(newnode, DTD_ATTR_DEFROUTER,
2229 	    tabptr->zone_nwif_defrouter)) != Z_OK))
2230 		return (err);
2231 	return (Z_OK);
2232 }
2233 
2234 int
zonecfg_add_nwif(zone_dochandle_t handle,struct zone_nwiftab * tabptr)2235 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2236 {
2237 	int err;
2238 
2239 	if (tabptr == NULL)
2240 		return (Z_INVAL);
2241 
2242 	if ((err = operation_prep(handle)) != Z_OK)
2243 		return (err);
2244 
2245 	if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK)
2246 		return (err);
2247 
2248 	return (Z_OK);
2249 }
2250 
2251 static int
zonecfg_delete_nwif_core(zone_dochandle_t handle,struct zone_nwiftab * tabptr)2252 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2253 {
2254 	xmlNodePtr cur = handle->zone_dh_cur;
2255 	boolean_t addr_match, phys_match, allowed_addr_match;
2256 
2257 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2258 		if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2259 			continue;
2260 
2261 		addr_match = match_prop(cur, DTD_ATTR_ADDRESS,
2262 		    tabptr->zone_nwif_address);
2263 		allowed_addr_match = match_prop(cur, DTD_ATTR_ALLOWED_ADDRESS,
2264 		    tabptr->zone_nwif_allowed_address);
2265 		phys_match = match_prop(cur, DTD_ATTR_PHYSICAL,
2266 		    tabptr->zone_nwif_physical);
2267 
2268 		if (addr_match && allowed_addr_match && phys_match) {
2269 			xmlUnlinkNode(cur);
2270 			xmlFreeNode(cur);
2271 			return (Z_OK);
2272 		}
2273 	}
2274 	return (Z_NO_RESOURCE_ID);
2275 }
2276 
2277 int
zonecfg_delete_nwif(zone_dochandle_t handle,struct zone_nwiftab * tabptr)2278 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2279 {
2280 	int err;
2281 
2282 	if (tabptr == NULL)
2283 		return (Z_INVAL);
2284 
2285 	if ((err = operation_prep(handle)) != Z_OK)
2286 		return (err);
2287 
2288 	if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK)
2289 		return (err);
2290 
2291 	return (Z_OK);
2292 }
2293 
2294 int
zonecfg_modify_nwif(zone_dochandle_t handle,struct zone_nwiftab * oldtabptr,struct zone_nwiftab * newtabptr)2295 zonecfg_modify_nwif(
2296 	zone_dochandle_t handle,
2297 	struct zone_nwiftab *oldtabptr,
2298 	struct zone_nwiftab *newtabptr)
2299 {
2300 	int err;
2301 
2302 	if (oldtabptr == NULL || newtabptr == NULL)
2303 		return (Z_INVAL);
2304 
2305 	if ((err = operation_prep(handle)) != Z_OK)
2306 		return (err);
2307 
2308 	if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK)
2309 		return (err);
2310 
2311 	if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK)
2312 		return (err);
2313 
2314 	return (Z_OK);
2315 }
2316 
2317 /*
2318  * Must be a comma-separated list of alpha-numeric file system names.
2319  */
2320 static int
zonecfg_valid_fs_allowed(const char * fsallowedp)2321 zonecfg_valid_fs_allowed(const char *fsallowedp)
2322 {
2323 	char tmp[ZONE_FS_ALLOWED_MAX];
2324 	char *cp = tmp;
2325 	char *p;
2326 
2327 	if (strlen(fsallowedp) > ZONE_FS_ALLOWED_MAX)
2328 		return (Z_TOO_BIG);
2329 
2330 	(void) strlcpy(tmp, fsallowedp, sizeof (tmp));
2331 
2332 	while (*cp != '\0') {
2333 		p = cp;
2334 		while (*p != '\0' && *p != ',') {
2335 			if (!isalnum(*p) && *p != '-')
2336 				return (Z_INVALID_PROPERTY);
2337 			p++;
2338 		}
2339 
2340 		if (*p == ',') {
2341 			if (p == cp)
2342 				return (Z_INVALID_PROPERTY);
2343 
2344 			p++;
2345 
2346 			if (*p == '\0')
2347 				return (Z_INVALID_PROPERTY);
2348 		}
2349 
2350 		cp = p;
2351 	}
2352 
2353 	return (Z_OK);
2354 }
2355 
2356 int
zonecfg_get_fs_allowed(zone_dochandle_t handle,char * bufp,size_t buflen)2357 zonecfg_get_fs_allowed(zone_dochandle_t handle, char *bufp, size_t buflen)
2358 {
2359 	int err;
2360 
2361 	if ((err = getrootattr(handle, DTD_ATTR_FS_ALLOWED,
2362 	    bufp, buflen)) != Z_OK)
2363 		return (err);
2364 	if (bufp[0] == '\0')
2365 		return (Z_BAD_PROPERTY);
2366 	return (zonecfg_valid_fs_allowed(bufp));
2367 }
2368 
2369 int
zonecfg_set_fs_allowed(zone_dochandle_t handle,const char * bufp)2370 zonecfg_set_fs_allowed(zone_dochandle_t handle, const char *bufp)
2371 {
2372 	int err;
2373 
2374 	if (bufp == NULL || (err = zonecfg_valid_fs_allowed(bufp)) == Z_OK)
2375 		return (setrootattr(handle, DTD_ATTR_FS_ALLOWED, bufp));
2376 	return (err);
2377 }
2378 
2379 /*
2380  * Determines if the specified string is a valid hostid string.  This function
2381  * returns Z_OK if the string is a valid hostid string.  It returns Z_INVAL if
2382  * 'hostidp' is NULL, Z_TOO_BIG if 'hostidp' refers to a string buffer
2383  * containing a hex string with more than 8 digits, and Z_INVALID_PROPERTY if
2384  * the string has an invalid format.
2385  */
2386 static int
zonecfg_valid_hostid(const char * hostidp)2387 zonecfg_valid_hostid(const char *hostidp)
2388 {
2389 	char *currentp;
2390 	u_longlong_t hostidval;
2391 	size_t len;
2392 
2393 	if (hostidp == NULL)
2394 		return (Z_INVAL);
2395 
2396 	/* Empty strings and strings with whitespace are invalid. */
2397 	if (*hostidp == '\0')
2398 		return (Z_INVALID_PROPERTY);
2399 	for (currentp = (char *)hostidp; *currentp != '\0'; ++currentp) {
2400 		if (isspace(*currentp))
2401 			return (Z_INVALID_PROPERTY);
2402 	}
2403 	len = (size_t)(currentp - hostidp);
2404 
2405 	/*
2406 	 * The caller might pass a hostid that is larger than the maximum
2407 	 * unsigned 32-bit integral value.  Check for this!  Also, make sure
2408 	 * that the whole string is converted (this helps us find illegal
2409 	 * characters) and that the whole string fits within a buffer of size
2410 	 * HW_HOSTID_LEN.
2411 	 */
2412 	currentp = (char *)hostidp;
2413 	if (strncmp(hostidp, "0x", 2) == 0 || strncmp(hostidp, "0X", 2) == 0)
2414 		currentp += 2;
2415 	hostidval = strtoull(currentp, &currentp, 16);
2416 	if ((size_t)(currentp - hostidp) >= HW_HOSTID_LEN)
2417 		return (Z_TOO_BIG);
2418 	if (hostidval > UINT_MAX || hostidval == HW_INVALID_HOSTID ||
2419 	    currentp != hostidp + len)
2420 		return (Z_INVALID_PROPERTY);
2421 	return (Z_OK);
2422 }
2423 
2424 /*
2425  * Gets the zone hostid string stored in the specified zone configuration
2426  * document.  This function returns Z_OK on success.  Z_BAD_PROPERTY is returned
2427  * if the config file doesn't specify a hostid or if the hostid is blank.
2428  *
2429  * Note that buflen should be at least HW_HOSTID_LEN.
2430  */
2431 int
zonecfg_get_hostid(zone_dochandle_t handle,char * bufp,size_t buflen)2432 zonecfg_get_hostid(zone_dochandle_t handle, char *bufp, size_t buflen)
2433 {
2434 	int err;
2435 
2436 	if ((err = getrootattr(handle, DTD_ATTR_HOSTID, bufp, buflen)) != Z_OK)
2437 		return (err);
2438 	if (bufp[0] == '\0')
2439 		return (Z_BAD_PROPERTY);
2440 	return (zonecfg_valid_hostid(bufp));
2441 }
2442 
2443 /*
2444  * Sets the hostid string in the specified zone config document to the given
2445  * string value.  If 'hostidp' is NULL, then the config document's hostid
2446  * attribute is cleared.  Non-NULL hostids are validated.  This function returns
2447  * Z_OK on success.  Any other return value indicates failure.
2448  */
2449 int
zonecfg_set_hostid(zone_dochandle_t handle,const char * hostidp)2450 zonecfg_set_hostid(zone_dochandle_t handle, const char *hostidp)
2451 {
2452 	int err;
2453 
2454 	/*
2455 	 * A NULL hostid string is interpreted as a request to clear the
2456 	 * hostid.
2457 	 */
2458 	if (hostidp == NULL || (err = zonecfg_valid_hostid(hostidp)) == Z_OK)
2459 		return (setrootattr(handle, DTD_ATTR_HOSTID, hostidp));
2460 	return (err);
2461 }
2462 
2463 int
zonecfg_lookup_dev(zone_dochandle_t handle,struct zone_devtab * tabptr)2464 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2465 {
2466 	xmlNodePtr cur, firstmatch;
2467 	int err;
2468 	char match[MAXPATHLEN];
2469 
2470 	if (tabptr == NULL)
2471 		return (Z_INVAL);
2472 
2473 	if ((err = operation_prep(handle)) != Z_OK)
2474 		return (err);
2475 
2476 	cur = handle->zone_dh_cur;
2477 	firstmatch = NULL;
2478 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2479 		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2480 			continue;
2481 		if (strlen(tabptr->zone_dev_match) == 0)
2482 			continue;
2483 
2484 		if ((fetchprop(cur, DTD_ATTR_MATCH, match,
2485 		    sizeof (match)) == Z_OK)) {
2486 			if (strcmp(tabptr->zone_dev_match,
2487 			    match) == 0) {
2488 				if (firstmatch == NULL)
2489 					firstmatch = cur;
2490 				else if (firstmatch != cur)
2491 					return (Z_INSUFFICIENT_SPEC);
2492 			} else {
2493 				/*
2494 				 * If another property matched but this
2495 				 * one doesn't then reset firstmatch.
2496 				 */
2497 				if (firstmatch == cur)
2498 					firstmatch = NULL;
2499 			}
2500 		}
2501 	}
2502 	if (firstmatch == NULL)
2503 		return (Z_NO_RESOURCE_ID);
2504 
2505 	cur = firstmatch;
2506 
2507 	if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
2508 	    sizeof (tabptr->zone_dev_match))) != Z_OK)
2509 		return (err);
2510 
2511 	return (Z_OK);
2512 }
2513 
2514 static int
zonecfg_add_dev_core(zone_dochandle_t handle,struct zone_devtab * tabptr)2515 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
2516 {
2517 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
2518 	int err;
2519 
2520 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL);
2521 
2522 	if ((err = newprop(newnode, DTD_ATTR_MATCH,
2523 	    tabptr->zone_dev_match)) != Z_OK)
2524 		return (err);
2525 
2526 	return (Z_OK);
2527 }
2528 
2529 int
zonecfg_add_dev(zone_dochandle_t handle,struct zone_devtab * tabptr)2530 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2531 {
2532 	int err;
2533 
2534 	if (tabptr == NULL)
2535 		return (Z_INVAL);
2536 
2537 	if ((err = operation_prep(handle)) != Z_OK)
2538 		return (err);
2539 
2540 	if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK)
2541 		return (err);
2542 
2543 	return (Z_OK);
2544 }
2545 
2546 static int
zonecfg_delete_dev_core(zone_dochandle_t handle,struct zone_devtab * tabptr)2547 zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
2548 {
2549 	xmlNodePtr cur = handle->zone_dh_cur;
2550 	int match_match;
2551 
2552 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2553 		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2554 			continue;
2555 
2556 		match_match = match_prop(cur, DTD_ATTR_MATCH,
2557 		    tabptr->zone_dev_match);
2558 
2559 		if (match_match) {
2560 			xmlUnlinkNode(cur);
2561 			xmlFreeNode(cur);
2562 			return (Z_OK);
2563 		}
2564 	}
2565 	return (Z_NO_RESOURCE_ID);
2566 }
2567 
2568 int
zonecfg_delete_dev(zone_dochandle_t handle,struct zone_devtab * tabptr)2569 zonecfg_delete_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2570 {
2571 	int err;
2572 
2573 	if (tabptr == NULL)
2574 		return (Z_INVAL);
2575 
2576 	if ((err = operation_prep(handle)) != Z_OK)
2577 		return (err);
2578 
2579 	if ((err = zonecfg_delete_dev_core(handle, tabptr)) != Z_OK)
2580 		return (err);
2581 
2582 	return (Z_OK);
2583 }
2584 
2585 int
zonecfg_modify_dev(zone_dochandle_t handle,struct zone_devtab * oldtabptr,struct zone_devtab * newtabptr)2586 zonecfg_modify_dev(
2587 	zone_dochandle_t handle,
2588 	struct zone_devtab *oldtabptr,
2589 	struct zone_devtab *newtabptr)
2590 {
2591 	int err;
2592 
2593 	if (oldtabptr == NULL || newtabptr == NULL)
2594 		return (Z_INVAL);
2595 
2596 	if ((err = operation_prep(handle)) != Z_OK)
2597 		return (err);
2598 
2599 	if ((err = zonecfg_delete_dev_core(handle, oldtabptr)) != Z_OK)
2600 		return (err);
2601 
2602 	if ((err = zonecfg_add_dev_core(handle, newtabptr)) != Z_OK)
2603 		return (err);
2604 
2605 	return (Z_OK);
2606 }
2607 
2608 static int
zonecfg_add_auth_core(zone_dochandle_t handle,struct zone_admintab * tabptr,char * zonename)2609 zonecfg_add_auth_core(zone_dochandle_t handle, struct zone_admintab *tabptr,
2610     char *zonename)
2611 {
2612 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
2613 	int err;
2614 
2615 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ADMIN, NULL);
2616 	err = newprop(newnode, DTD_ATTR_USER, tabptr->zone_admin_user);
2617 	if (err != Z_OK)
2618 		return (err);
2619 	err = newprop(newnode, DTD_ATTR_AUTHS, tabptr->zone_admin_auths);
2620 	if (err != Z_OK)
2621 		return (err);
2622 	if ((err = zonecfg_remove_userauths(
2623 	    handle, tabptr->zone_admin_user, zonename, B_FALSE)) != Z_OK)
2624 		return (err);
2625 	return (Z_OK);
2626 }
2627 
2628 int
zonecfg_add_admin(zone_dochandle_t handle,struct zone_admintab * tabptr,char * zonename)2629 zonecfg_add_admin(zone_dochandle_t handle, struct zone_admintab *tabptr,
2630     char *zonename)
2631 {
2632 	int err;
2633 
2634 	if (tabptr == NULL)
2635 		return (Z_INVAL);
2636 
2637 	if ((err = operation_prep(handle)) != Z_OK)
2638 		return (err);
2639 
2640 	if ((err = zonecfg_add_auth_core(handle, tabptr,
2641 	    zonename)) != Z_OK)
2642 		return (err);
2643 
2644 	return (Z_OK);
2645 }
2646 
2647 static int
zonecfg_delete_auth_core(zone_dochandle_t handle,struct zone_admintab * tabptr,char * zonename)2648 zonecfg_delete_auth_core(zone_dochandle_t handle, struct zone_admintab *tabptr,
2649     char *zonename)
2650 {
2651 	xmlNodePtr cur = handle->zone_dh_cur;
2652 	boolean_t auth_match;
2653 	int err;
2654 
2655 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2656 		if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
2657 			continue;
2658 		auth_match = match_prop(cur, DTD_ATTR_USER,
2659 		    tabptr->zone_admin_user);
2660 		if (auth_match) {
2661 			if ((err = zonecfg_insert_userauths(
2662 			    handle, tabptr->zone_admin_user,
2663 			    zonename)) != Z_OK)
2664 				return (err);
2665 			xmlUnlinkNode(cur);
2666 			xmlFreeNode(cur);
2667 			return (Z_OK);
2668 		}
2669 	}
2670 	return (Z_NO_RESOURCE_ID);
2671 }
2672 
2673 int
zonecfg_delete_admin(zone_dochandle_t handle,struct zone_admintab * tabptr,char * zonename)2674 zonecfg_delete_admin(zone_dochandle_t handle, struct zone_admintab *tabptr,
2675     char *zonename)
2676 {
2677 	int err;
2678 
2679 	if (tabptr == NULL)
2680 		return (Z_INVAL);
2681 
2682 	if ((err = operation_prep(handle)) != Z_OK)
2683 		return (err);
2684 
2685 	if ((err = zonecfg_delete_auth_core(handle, tabptr, zonename)) != Z_OK)
2686 		return (err);
2687 
2688 	return (Z_OK);
2689 }
2690 
2691 int
zonecfg_modify_admin(zone_dochandle_t handle,struct zone_admintab * oldtabptr,struct zone_admintab * newtabptr,char * zonename)2692 zonecfg_modify_admin(zone_dochandle_t handle, struct zone_admintab *oldtabptr,
2693     struct zone_admintab *newtabptr, char *zonename)
2694 {
2695 	int err;
2696 
2697 	if (oldtabptr == NULL || newtabptr == NULL)
2698 		return (Z_INVAL);
2699 
2700 	if ((err = operation_prep(handle)) != Z_OK)
2701 		return (err);
2702 
2703 	if ((err = zonecfg_delete_auth_core(handle, oldtabptr, zonename))
2704 	    != Z_OK)
2705 		return (err);
2706 
2707 	if ((err = zonecfg_add_auth_core(handle, newtabptr,
2708 	    zonename)) != Z_OK)
2709 		return (err);
2710 
2711 	return (Z_OK);
2712 }
2713 
2714 int
zonecfg_lookup_admin(zone_dochandle_t handle,struct zone_admintab * tabptr)2715 zonecfg_lookup_admin(zone_dochandle_t handle, struct zone_admintab *tabptr)
2716 {
2717 	xmlNodePtr cur, firstmatch;
2718 	int err;
2719 	char user[MAXUSERNAME];
2720 
2721 	if (tabptr == NULL)
2722 		return (Z_INVAL);
2723 
2724 	if ((err = operation_prep(handle)) != Z_OK)
2725 		return (err);
2726 
2727 	cur = handle->zone_dh_cur;
2728 	firstmatch = NULL;
2729 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2730 		if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
2731 			continue;
2732 		if (strlen(tabptr->zone_admin_user) > 0) {
2733 			if ((fetchprop(cur, DTD_ATTR_USER, user,
2734 			    sizeof (user)) == Z_OK) &&
2735 			    (strcmp(tabptr->zone_admin_user, user) == 0)) {
2736 				if (firstmatch == NULL)
2737 					firstmatch = cur;
2738 				else
2739 					return (Z_INSUFFICIENT_SPEC);
2740 			}
2741 		}
2742 	}
2743 	if (firstmatch == NULL)
2744 		return (Z_NO_RESOURCE_ID);
2745 
2746 	cur = firstmatch;
2747 
2748 	if ((err = fetchprop(cur, DTD_ATTR_USER, tabptr->zone_admin_user,
2749 	    sizeof (tabptr->zone_admin_user))) != Z_OK)
2750 		return (err);
2751 
2752 	if ((err = fetchprop(cur, DTD_ATTR_AUTHS, tabptr->zone_admin_auths,
2753 	    sizeof (tabptr->zone_admin_auths))) != Z_OK)
2754 		return (err);
2755 
2756 	return (Z_OK);
2757 }
2758 
2759 static int
zonecfg_add_secflags_core(zone_dochandle_t handle,struct zone_secflagstab * tabptr)2760 zonecfg_add_secflags_core(zone_dochandle_t handle,
2761     struct zone_secflagstab *tabptr)
2762 {
2763 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
2764 	int err;
2765 
2766 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_SECFLAGS, NULL);
2767 	err = newprop(newnode, DTD_ATTR_DEFAULT, tabptr->zone_secflags_default);
2768 	if (err != Z_OK)
2769 		return (err);
2770 	err = newprop(newnode, DTD_ATTR_LOWER, tabptr->zone_secflags_lower);
2771 	if (err != Z_OK)
2772 		return (err);
2773 	err = newprop(newnode, DTD_ATTR_UPPER, tabptr->zone_secflags_upper);
2774 	if (err != Z_OK)
2775 		return (err);
2776 
2777 	return (Z_OK);
2778 }
2779 
2780 int
zonecfg_add_secflags(zone_dochandle_t handle,struct zone_secflagstab * tabptr)2781 zonecfg_add_secflags(zone_dochandle_t handle, struct zone_secflagstab *tabptr)
2782 {
2783 	int err;
2784 
2785 
2786 	if (tabptr == NULL)
2787 		return (Z_INVAL);
2788 
2789 	if ((err = operation_prep(handle)) != Z_OK)
2790 		return (err);
2791 
2792 	if ((err = zonecfg_add_secflags_core(handle, tabptr)) != Z_OK)
2793 		return (err);
2794 
2795 	return (Z_OK);
2796 }
2797 
2798 static int
zonecfg_delete_secflags_core(zone_dochandle_t handle,struct zone_secflagstab * tabptr)2799 zonecfg_delete_secflags_core(zone_dochandle_t handle,
2800     struct zone_secflagstab *tabptr)
2801 {
2802 	xmlNodePtr cur = handle->zone_dh_cur;
2803 	boolean_t def_match, low_match, up_match;
2804 
2805 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2806 		if (xmlStrcmp(cur->name, DTD_ELEM_SECFLAGS) != 0)
2807 			continue;
2808 
2809 		def_match = match_prop(cur, DTD_ATTR_DEFAULT,
2810 		    tabptr->zone_secflags_default);
2811 		low_match = match_prop(cur, DTD_ATTR_LOWER,
2812 		    tabptr->zone_secflags_lower);
2813 		up_match = match_prop(cur, DTD_ATTR_UPPER,
2814 		    tabptr->zone_secflags_upper);
2815 
2816 		if (def_match && low_match && up_match) {
2817 			xmlUnlinkNode(cur);
2818 			xmlFreeNode(cur);
2819 			return (Z_OK);
2820 		}
2821 
2822 	}
2823 	return (Z_NO_RESOURCE_ID);
2824 }
2825 
2826 int
zonecfg_delete_secflags(zone_dochandle_t handle,struct zone_secflagstab * tabptr)2827 zonecfg_delete_secflags(zone_dochandle_t handle,
2828     struct zone_secflagstab *tabptr)
2829 {
2830 	int err;
2831 
2832 	if (tabptr == NULL)
2833 		return (Z_INVAL);
2834 
2835 	if ((err = operation_prep(handle)) != Z_OK)
2836 		return (err);
2837 
2838 	if ((err = zonecfg_delete_secflags_core(handle, tabptr)) != Z_OK)
2839 		return (err);
2840 
2841 	return (Z_OK);
2842 }
2843 
2844 int
zonecfg_modify_secflags(zone_dochandle_t handle,struct zone_secflagstab * oldtabptr,struct zone_secflagstab * newtabptr)2845 zonecfg_modify_secflags(zone_dochandle_t handle,
2846     struct zone_secflagstab *oldtabptr,
2847     struct zone_secflagstab *newtabptr)
2848 {
2849 	int err;
2850 
2851 	if (oldtabptr == NULL || newtabptr == NULL)
2852 		return (Z_INVAL);
2853 
2854 	if ((err = operation_prep(handle)) != Z_OK)
2855 		return (err);
2856 
2857 	if ((err = zonecfg_delete_secflags_core(handle, oldtabptr))
2858 	    != Z_OK)
2859 		return (err);
2860 
2861 	if ((err = zonecfg_add_secflags_core(handle, newtabptr)) != Z_OK)
2862 		return (err);
2863 
2864 	return (Z_OK);
2865 }
2866 
2867 int
zonecfg_lookup_secflags(zone_dochandle_t handle,struct zone_secflagstab * tabptr)2868 zonecfg_lookup_secflags(zone_dochandle_t handle,
2869     struct zone_secflagstab *tabptr)
2870 {
2871 	xmlNodePtr cur;
2872 	int err;
2873 
2874 	if (tabptr == NULL)
2875 		return (Z_INVAL);
2876 
2877 	if ((err = operation_prep(handle)) != Z_OK)
2878 		return (err);
2879 
2880 	cur = handle->zone_dh_cur;
2881 
2882 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2883 		if (xmlStrcmp(cur->name, DTD_ELEM_SECFLAGS) != 0)
2884 			continue;
2885 
2886 		if ((err = fetchprop(cur, DTD_ATTR_DEFAULT,
2887 		    tabptr->zone_secflags_default,
2888 		    sizeof (tabptr->zone_secflags_default))) != Z_OK) {
2889 			handle->zone_dh_cur = handle->zone_dh_top;
2890 			return (err);
2891 		}
2892 
2893 		if ((err = fetchprop(cur, DTD_ATTR_LOWER,
2894 		    tabptr->zone_secflags_lower,
2895 		    sizeof (tabptr->zone_secflags_lower))) != Z_OK) {
2896 			handle->zone_dh_cur = handle->zone_dh_top;
2897 			return (err);
2898 		}
2899 
2900 		if ((err = fetchprop(cur, DTD_ATTR_UPPER,
2901 		    tabptr->zone_secflags_upper,
2902 		    sizeof (tabptr->zone_secflags_upper))) != Z_OK) {
2903 			handle->zone_dh_cur = handle->zone_dh_top;
2904 			return (err);
2905 		}
2906 
2907 		return (Z_OK);
2908 	}
2909 
2910 	return (Z_NO_ENTRY);
2911 }
2912 
2913 /* Lock to serialize all devwalks */
2914 static pthread_mutex_t zonecfg_devwalk_lock = PTHREAD_MUTEX_INITIALIZER;
2915 /*
2916  * Global variables used to pass data from zonecfg_dev_manifest to the nftw
2917  * call-back (zonecfg_devwalk_cb).  g_devwalk_data is really the void*
2918  * parameter and g_devwalk_cb is really the *cb parameter from
2919  * zonecfg_dev_manifest.
2920  */
2921 typedef struct __g_devwalk_data *g_devwalk_data_t;
2922 static g_devwalk_data_t g_devwalk_data;
2923 static int (*g_devwalk_cb)(const char *, uid_t, gid_t, mode_t, const char *,
2924     void *);
2925 static size_t g_devwalk_skip_prefix;
2926 
2927 /*
2928  * zonecfg_dev_manifest call-back function used during detach to generate the
2929  * dev info in the manifest.
2930  */
2931 static int
get_detach_dev_entry(const char * name,uid_t uid,gid_t gid,mode_t mode,const char * acl,void * hdl)2932 get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode,
2933     const char *acl, void *hdl)
2934 {
2935 	zone_dochandle_t handle = (zone_dochandle_t)hdl;
2936 	xmlNodePtr newnode;
2937 	xmlNodePtr cur;
2938 	int err;
2939 	char buf[128];
2940 
2941 	if ((err = operation_prep(handle)) != Z_OK)
2942 		return (err);
2943 
2944 	cur = handle->zone_dh_cur;
2945 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL);
2946 	if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK)
2947 		return (err);
2948 	(void) snprintf(buf, sizeof (buf), "%lu", uid);
2949 	if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK)
2950 		return (err);
2951 	(void) snprintf(buf, sizeof (buf), "%lu", gid);
2952 	if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK)
2953 		return (err);
2954 	(void) snprintf(buf, sizeof (buf), "%o", mode);
2955 	if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK)
2956 		return (err);
2957 	if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK)
2958 		return (err);
2959 	return (Z_OK);
2960 }
2961 
2962 /*
2963  * This is the nftw call-back function used by zonecfg_dev_manifest.  It is
2964  * responsible for calling the actual call-back.
2965  */
2966 /* ARGSUSED2 */
2967 static int
zonecfg_devwalk_cb(const char * path,const struct stat * st,int f,struct FTW * ftw)2968 zonecfg_devwalk_cb(const char *path, const struct stat *st, int f,
2969     struct FTW *ftw)
2970 {
2971 	acl_t *acl;
2972 	char *acl_txt = NULL;
2973 
2974 	/* skip all but character and block devices */
2975 	if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode))
2976 		return (0);
2977 
2978 	if ((acl_get(path, ACL_NO_TRIVIAL, &acl) == 0) &&
2979 	    acl != NULL) {
2980 		acl_txt = acl_totext(acl, ACL_NORESOLVE);
2981 		acl_free(acl);
2982 	}
2983 
2984 	if (strlen(path) <= g_devwalk_skip_prefix)
2985 		return (0);
2986 
2987 	(void) g_devwalk_cb(path + g_devwalk_skip_prefix, st->st_uid,
2988 	    st->st_gid, st->st_mode & S_IAMB, acl_txt != NULL ? acl_txt : "",
2989 	    g_devwalk_data);
2990 	free(acl_txt);
2991 	return (0);
2992 }
2993 
2994 /*
2995  * Walk the dev tree for the zone specified by hdl and call the
2996  * get_detach_dev_entry call-back function for each entry in the tree.  The
2997  * call-back will be passed the name, uid, gid, mode, acl string and the
2998  * handle input parameter for each dev entry.
2999  *
3000  * Data is passed to get_detach_dev_entry through the global variables
3001  * g_devwalk_data, *g_devwalk_cb, and g_devwalk_skip_prefix.  The
3002  * zonecfg_devwalk_cb function will actually call get_detach_dev_entry.
3003  */
3004 int
zonecfg_dev_manifest(zone_dochandle_t hdl)3005 zonecfg_dev_manifest(zone_dochandle_t hdl)
3006 {
3007 	char path[MAXPATHLEN];
3008 	int ret;
3009 
3010 	if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK)
3011 		return (ret);
3012 
3013 	if (strlcat(path, "/dev", sizeof (path)) >= sizeof (path))
3014 		return (Z_TOO_BIG);
3015 
3016 	/*
3017 	 * We have to serialize all devwalks in the same process
3018 	 * (which should be fine), since nftw() is so badly designed.
3019 	 */
3020 	(void) pthread_mutex_lock(&zonecfg_devwalk_lock);
3021 
3022 	g_devwalk_skip_prefix = strlen(path) + 1;
3023 	g_devwalk_data = (g_devwalk_data_t)hdl;
3024 	g_devwalk_cb = get_detach_dev_entry;
3025 	(void) nftw(path, zonecfg_devwalk_cb, 0, FTW_PHYS);
3026 
3027 	(void) pthread_mutex_unlock(&zonecfg_devwalk_lock);
3028 	return (Z_OK);
3029 }
3030 
3031 /*
3032  * Update the owner, group, mode and acl on the specified dev (inpath) for
3033  * the zone (hdl).  This function can be used to fix up the dev tree after
3034  * attaching a migrated zone.
3035  */
3036 int
zonecfg_devperms_apply(zone_dochandle_t hdl,const char * inpath,uid_t owner,gid_t group,mode_t mode,const char * acltxt)3037 zonecfg_devperms_apply(zone_dochandle_t hdl, const char *inpath, uid_t owner,
3038     gid_t group, mode_t mode, const char *acltxt)
3039 {
3040 	int ret;
3041 	char path[MAXPATHLEN];
3042 	struct stat st;
3043 	acl_t *aclp;
3044 
3045 	if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK)
3046 		return (ret);
3047 
3048 	if (strlcat(path, "/dev/", sizeof (path)) >= sizeof (path))
3049 		return (Z_TOO_BIG);
3050 	if (strlcat(path, inpath, sizeof (path)) >= sizeof (path))
3051 		return (Z_TOO_BIG);
3052 
3053 	if (stat(path, &st) == -1)
3054 		return (Z_INVAL);
3055 
3056 	/* make sure we're only touching device nodes */
3057 	if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode))
3058 		return (Z_INVAL);
3059 
3060 	if (chown(path, owner, group) == -1)
3061 		return (Z_SYSTEM);
3062 
3063 	if (chmod(path, mode) == -1)
3064 		return (Z_SYSTEM);
3065 
3066 	if ((acltxt == NULL) || (strcmp(acltxt, "") == 0))
3067 		return (Z_OK);
3068 
3069 	if (acl_fromtext(acltxt, &aclp) != 0) {
3070 		errno = EINVAL;
3071 		return (Z_SYSTEM);
3072 	}
3073 
3074 	errno = 0;
3075 	if (acl_set(path, aclp) == -1) {
3076 		free(aclp);
3077 		return (Z_SYSTEM);
3078 	}
3079 
3080 	free(aclp);
3081 	return (Z_OK);
3082 }
3083 
3084 /*
3085  * This function finds everything mounted under a zone's rootpath.
3086  * This returns the number of mounts under rootpath, or -1 on error.
3087  * callback is called once per mount found with the first argument
3088  * pointing to a mnttab structure containing the mount's information.
3089  *
3090  * If the callback function returns non-zero zonecfg_find_mounts
3091  * aborts with an error.
3092  */
3093 int
zonecfg_find_mounts(char * rootpath,int (* callback)(const struct mnttab *,void *),void * priv)3094 zonecfg_find_mounts(char *rootpath, int (*callback)(const struct mnttab *,
3095     void *), void *priv)
3096 {
3097 	FILE *mnttab;
3098 	struct mnttab m;
3099 	size_t l;
3100 	int zfsl;
3101 	int rv = 0;
3102 	char zfs_path[MAXPATHLEN];
3103 
3104 	assert(rootpath != NULL);
3105 
3106 	if ((zfsl = snprintf(zfs_path, sizeof (zfs_path), "%s/.zfs/", rootpath))
3107 	    >= sizeof (zfs_path))
3108 		return (-1);
3109 
3110 	l = strlen(rootpath);
3111 
3112 	mnttab = fopen("/etc/mnttab", "r");
3113 
3114 	if (mnttab == NULL)
3115 		return (-1);
3116 
3117 	if (ioctl(fileno(mnttab), MNTIOC_SHOWHIDDEN, NULL) < 0)  {
3118 		rv = -1;
3119 		goto out;
3120 	}
3121 
3122 	while (!getmntent(mnttab, &m)) {
3123 		if ((strncmp(rootpath, m.mnt_mountp, l) == 0) &&
3124 		    (m.mnt_mountp[l] == '/') &&
3125 		    (strncmp(zfs_path, m.mnt_mountp, zfsl) != 0)) {
3126 			rv++;
3127 			if (callback == NULL)
3128 				continue;
3129 			if (callback(&m, priv)) {
3130 				rv = -1;
3131 				goto out;
3132 
3133 			}
3134 		}
3135 	}
3136 
3137 out:
3138 	(void) fclose(mnttab);
3139 	return (rv);
3140 }
3141 
3142 int
zonecfg_lookup_attr(zone_dochandle_t handle,struct zone_attrtab * tabptr)3143 zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3144 {
3145 	xmlNodePtr cur, firstmatch;
3146 	int err;
3147 	char name[MAXNAMELEN], type[MAXNAMELEN], value[MAXNAMELEN];
3148 
3149 	if (tabptr == NULL)
3150 		return (Z_INVAL);
3151 
3152 	if ((err = operation_prep(handle)) != Z_OK)
3153 		return (err);
3154 
3155 	cur = handle->zone_dh_cur;
3156 	firstmatch = NULL;
3157 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
3158 		if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
3159 			continue;
3160 		if (strlen(tabptr->zone_attr_name) > 0) {
3161 			if ((fetchprop(cur, DTD_ATTR_NAME, name,
3162 			    sizeof (name)) == Z_OK) &&
3163 			    (strcmp(tabptr->zone_attr_name, name) == 0)) {
3164 				if (firstmatch == NULL)
3165 					firstmatch = cur;
3166 				else
3167 					return (Z_INSUFFICIENT_SPEC);
3168 			}
3169 		}
3170 		if (strlen(tabptr->zone_attr_type) > 0) {
3171 			if ((fetchprop(cur, DTD_ATTR_TYPE, type,
3172 			    sizeof (type)) == Z_OK)) {
3173 				if (strcmp(tabptr->zone_attr_type, type) == 0) {
3174 					if (firstmatch == NULL)
3175 						firstmatch = cur;
3176 					else if (firstmatch != cur)
3177 						return (Z_INSUFFICIENT_SPEC);
3178 				} else {
3179 					/*
3180 					 * If another property matched but this
3181 					 * one doesn't then reset firstmatch.
3182 					 */
3183 					if (firstmatch == cur)
3184 						firstmatch = NULL;
3185 				}
3186 			}
3187 		}
3188 		if (strlen(tabptr->zone_attr_value) > 0) {
3189 			if ((fetchprop(cur, DTD_ATTR_VALUE, value,
3190 			    sizeof (value)) == Z_OK)) {
3191 				if (strcmp(tabptr->zone_attr_value, value) ==
3192 				    0) {
3193 					if (firstmatch == NULL)
3194 						firstmatch = cur;
3195 					else if (firstmatch != cur)
3196 						return (Z_INSUFFICIENT_SPEC);
3197 				} else {
3198 					/*
3199 					 * If another property matched but this
3200 					 * one doesn't then reset firstmatch.
3201 					 */
3202 					if (firstmatch == cur)
3203 						firstmatch = NULL;
3204 				}
3205 			}
3206 		}
3207 	}
3208 	if (firstmatch == NULL)
3209 		return (Z_NO_RESOURCE_ID);
3210 
3211 	cur = firstmatch;
3212 
3213 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
3214 	    sizeof (tabptr->zone_attr_name))) != Z_OK)
3215 		return (err);
3216 
3217 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
3218 	    sizeof (tabptr->zone_attr_type))) != Z_OK)
3219 		return (err);
3220 
3221 	if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
3222 	    sizeof (tabptr->zone_attr_value))) != Z_OK)
3223 		return (err);
3224 
3225 	return (Z_OK);
3226 }
3227 
3228 static int
zonecfg_add_attr_core(zone_dochandle_t handle,struct zone_attrtab * tabptr)3229 zonecfg_add_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3230 {
3231 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
3232 	int err;
3233 
3234 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ATTR, NULL);
3235 	err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_attr_name);
3236 	if (err != Z_OK)
3237 		return (err);
3238 	err = newprop(newnode, DTD_ATTR_TYPE, tabptr->zone_attr_type);
3239 	if (err != Z_OK)
3240 		return (err);
3241 	err = newprop(newnode, DTD_ATTR_VALUE, tabptr->zone_attr_value);
3242 	if (err != Z_OK)
3243 		return (err);
3244 	return (Z_OK);
3245 }
3246 
3247 int
zonecfg_add_attr(zone_dochandle_t handle,struct zone_attrtab * tabptr)3248 zonecfg_add_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3249 {
3250 	int err;
3251 
3252 	if (tabptr == NULL)
3253 		return (Z_INVAL);
3254 
3255 	if ((err = operation_prep(handle)) != Z_OK)
3256 		return (err);
3257 
3258 	if ((err = zonecfg_add_attr_core(handle, tabptr)) != Z_OK)
3259 		return (err);
3260 
3261 	return (Z_OK);
3262 }
3263 
3264 static int
zonecfg_delete_attr_core(zone_dochandle_t handle,struct zone_attrtab * tabptr)3265 zonecfg_delete_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3266 {
3267 	xmlNodePtr cur = handle->zone_dh_cur;
3268 	int name_match, type_match, value_match;
3269 
3270 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
3271 		if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
3272 			continue;
3273 
3274 		name_match = match_prop(cur, DTD_ATTR_NAME,
3275 		    tabptr->zone_attr_name);
3276 		type_match = match_prop(cur, DTD_ATTR_TYPE,
3277 		    tabptr->zone_attr_type);
3278 		value_match = match_prop(cur, DTD_ATTR_VALUE,
3279 		    tabptr->zone_attr_value);
3280 
3281 		if (name_match && type_match && value_match) {
3282 			xmlUnlinkNode(cur);
3283 			xmlFreeNode(cur);
3284 			return (Z_OK);
3285 		}
3286 	}
3287 	return (Z_NO_RESOURCE_ID);
3288 }
3289 
3290 int
zonecfg_delete_attr(zone_dochandle_t handle,struct zone_attrtab * tabptr)3291 zonecfg_delete_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3292 {
3293 	int err;
3294 
3295 	if (tabptr == NULL)
3296 		return (Z_INVAL);
3297 
3298 	if ((err = operation_prep(handle)) != Z_OK)
3299 		return (err);
3300 
3301 	if ((err = zonecfg_delete_attr_core(handle, tabptr)) != Z_OK)
3302 		return (err);
3303 
3304 	return (Z_OK);
3305 }
3306 
3307 int
zonecfg_modify_attr(zone_dochandle_t handle,struct zone_attrtab * oldtabptr,struct zone_attrtab * newtabptr)3308