xref: /illumos-gate/usr/src/lib/libzonecfg/common/libzonecfg.c (revision 0dee7919e2f2a6479d16b370af93747b9416b242)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <errno.h>
30 #include <fnmatch.h>
31 #include <strings.h>
32 #include <unistd.h>
33 #include <sys/stat.h>
34 #include <assert.h>
35 #include <libgen.h>
36 #include <libintl.h>
37 #include <alloca.h>
38 #include <ctype.h>
39 #include <sys/mntio.h>
40 #include <sys/mnttab.h>
41 
42 #include <arpa/inet.h>
43 #include <netdb.h>
44 
45 #include <priv.h>
46 
47 #include <libxml/xmlmemory.h>
48 #include <libxml/parser.h>
49 
50 #include <libdevinfo.h>
51 
52 #include <libzonecfg.h>
53 #include "zonecfg_impl.h"
54 
55 #define	_PATH_TMPFILE	"/zonecfg.XXXXXX"
56 
57 /* Hard-code the DTD element/attribute/entity names just once, here. */
58 #define	DTD_ELEM_ATTR		(const xmlChar *) "attr"
59 #define	DTD_ELEM_COMMENT	(const xmlChar *) "comment"
60 #define	DTD_ELEM_DEVICE		(const xmlChar *) "device"
61 #define	DTD_ELEM_FS		(const xmlChar *) "filesystem"
62 #define	DTD_ELEM_FSOPTION	(const xmlChar *) "fsoption"
63 #define	DTD_ELEM_IPD		(const xmlChar *) "inherited-pkg-dir"
64 #define	DTD_ELEM_NET		(const xmlChar *) "network"
65 #define	DTD_ELEM_RCTL		(const xmlChar *) "rctl"
66 #define	DTD_ELEM_RCTLVALUE	(const xmlChar *) "rctl-value"
67 #define	DTD_ELEM_ZONE		(const xmlChar *) "zone"
68 
69 #define	DTD_ATTR_ACTION		(const xmlChar *) "action"
70 #define	DTD_ATTR_ADDRESS	(const xmlChar *) "address"
71 #define	DTD_ATTR_AUTOBOOT	(const xmlChar *) "autoboot"
72 #define	DTD_ATTR_DIR		(const xmlChar *) "directory"
73 #define	DTD_ATTR_LIMIT		(const xmlChar *) "limit"
74 #define	DTD_ATTR_MATCH		(const xmlChar *) "match"
75 #define	DTD_ATTR_NAME		(const xmlChar *) "name"
76 #define	DTD_ATTR_PHYSICAL	(const xmlChar *) "physical"
77 #define	DTD_ATTR_POOL		(const xmlChar *) "pool"
78 #define	DTD_ATTR_PRIV		(const xmlChar *) "priv"
79 #define	DTD_ATTR_RAW		(const xmlChar *) "raw"
80 #define	DTD_ATTR_SPECIAL	(const xmlChar *) "special"
81 #define	DTD_ATTR_TYPE		(const xmlChar *) "type"
82 #define	DTD_ATTR_VALUE		(const xmlChar *) "value"
83 #define	DTD_ATTR_ZONEPATH	(const xmlChar *) "zonepath"
84 
85 #define	DTD_ENTITY_BOOLEAN	"boolean"
86 #define	DTD_ENTITY_DEVPATH	"devpath"
87 #define	DTD_ENTITY_DRIVER	"driver"
88 #define	DTD_ENTITY_DRVMIN	"drv_min"
89 #define	DTD_ENTITY_FALSE	"false"
90 #define	DTD_ENTITY_INT		"int"
91 #define	DTD_ENTITY_STRING	"string"
92 #define	DTD_ENTITY_TRUE		"true"
93 #define	DTD_ENTITY_UINT		"uint"
94 
95 #define	DTD_ENTITY_BOOL_LEN	6	/* "false" */
96 
97 struct zone_dochandle {
98 	char		*zone_dh_rootdir;
99 	xmlDocPtr	zone_dh_doc;
100 	xmlNodePtr	zone_dh_cur;
101 	xmlNodePtr	zone_dh_top;
102 };
103 
104 /*
105  * For functions which return int, which is most of the functions herein,
106  * the return values should be from the Z_foo set defined in <libzonecfg.h>.
107  * In some instances, we take pains mapping some libc errno values to Z_foo
108  * values from this set.
109  */
110 
111 /*
112  * Callers of the _file_path() functions are expected to have the second
113  * parameter be a (char foo[MAXPATHLEN]).
114  */
115 
116 static void
117 config_file_path(const char *zonename, char *answer)
118 {
119 	(void) snprintf(answer, MAXPATHLEN,
120 	    "%s/%s.xml", ZONE_CONFIG_ROOT, zonename);
121 }
122 
123 static void
124 snap_file_path(char *zonename, char *answer)
125 {
126 	(void) snprintf(answer, MAXPATHLEN,
127 	    "%s/%s.snapshot.xml", ZONE_SNAPSHOT_ROOT, zonename);
128 }
129 
130 /*ARGSUSED*/
131 static void
132 zonecfg_error_func(void *ctx, const char *msg, ...)
133 {
134 	/*
135 	 * This function does nothing by design.  Its purpose is to prevent
136 	 * libxml from dumping unwanted messages to stdout/stderr.
137 	 */
138 }
139 
140 zone_dochandle_t
141 zonecfg_init_handle(void)
142 {
143 	zone_dochandle_t handle = malloc(sizeof (struct zone_dochandle));
144 	if (handle == NULL) {
145 		errno = Z_NOMEM;
146 		return (NULL);
147 	}
148 	handle->zone_dh_doc = NULL;
149 	handle->zone_dh_cur = NULL;
150 	handle->zone_dh_top = NULL;
151 
152 	/* generic libxml initialization */
153 	xmlLineNumbersDefault(1);
154 	xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
155 	xmlDoValidityCheckingDefaultValue = 1;
156 	(void) xmlKeepBlanksDefault(0);
157 	xmlGetWarningsDefaultValue = 0;
158 	xmlSetGenericErrorFunc(NULL, zonecfg_error_func);
159 
160 	return (handle);
161 }
162 
163 int
164 zonecfg_check_handle(zone_dochandle_t handle)
165 {
166 	if (handle == NULL || handle->zone_dh_doc == NULL)
167 		return (Z_BAD_HANDLE);
168 	return (Z_OK);
169 }
170 
171 void
172 zonecfg_fini_handle(zone_dochandle_t handle)
173 {
174 	if (zonecfg_check_handle(handle) == Z_OK)
175 		xmlFreeDoc(handle->zone_dh_doc);
176 	if (handle != NULL)
177 		free(handle);
178 }
179 
180 static int
181 zonecfg_destroy_impl(char *filename)
182 {
183 	if (unlink(filename) == -1) {
184 		if (errno == EACCES)
185 			return (Z_ACCES);
186 		if (errno == ENOENT)
187 			return (Z_NO_ZONE);
188 		return (Z_MISC_FS);
189 	}
190 	return (Z_OK);
191 }
192 
193 int
194 zonecfg_destroy(const char *zonename)
195 {
196 	char path[MAXPATHLEN];
197 
198 	config_file_path(zonename, path);
199 	return (zonecfg_destroy_impl(path));
200 }
201 
202 int
203 zonecfg_destroy_snapshot(char *zonename)
204 {
205 	char path[MAXPATHLEN];
206 
207 	snap_file_path(zonename, path);
208 	return (zonecfg_destroy_impl(path));
209 }
210 
211 static int
212 getroot(zone_dochandle_t handle, xmlNodePtr *root)
213 {
214 	if (zonecfg_check_handle(handle) == Z_BAD_HANDLE)
215 		return (Z_BAD_HANDLE);
216 
217 	*root = xmlDocGetRootElement(handle->zone_dh_doc);
218 
219 	if (*root == NULL)
220 		return (Z_EMPTY_DOCUMENT);
221 
222 	if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE))
223 		return (Z_WRONG_DOC_TYPE);
224 
225 	return (Z_OK);
226 }
227 
228 static int
229 operation_prep(zone_dochandle_t handle)
230 {
231 	xmlNodePtr root;
232 	int err;
233 
234 	if ((err = getroot(handle, &root)) != 0)
235 		return (err);
236 
237 	handle->zone_dh_cur = root;
238 	handle->zone_dh_top = root;
239 	return (Z_OK);
240 }
241 
242 static int
243 getrootattr(zone_dochandle_t handle, const xmlChar *propname,
244     char *propval, size_t propsize)
245 {
246 	xmlNodePtr root;
247 	xmlChar *property;
248 	size_t srcsize;
249 	int err;
250 
251 	if ((err = getroot(handle, &root)) != 0)
252 		return (err);
253 
254 	if ((property = xmlGetProp(root, propname)) == NULL)
255 		return (Z_BAD_PROPERTY);
256 	srcsize = strlcpy(propval, (char *)property, propsize);
257 	xmlFree(property);
258 	if (srcsize >= propsize)
259 		return (Z_TOO_BIG);
260 	return (Z_OK);
261 }
262 
263 static int
264 setrootattr(zone_dochandle_t handle, const xmlChar *propname, char *propval)
265 {
266 	int err;
267 	xmlNodePtr root;
268 
269 	if (propval == NULL)
270 		return (Z_INVAL);
271 
272 	if ((err = getroot(handle, &root)) != Z_OK)
273 		return (err);
274 
275 	if (xmlSetProp(root, propname, (const xmlChar *) propval) == NULL)
276 		return (Z_INVAL);
277 	return (Z_OK);
278 }
279 
280 static int
281 zonecfg_get_handle_impl(char *zonename, char *filename, zone_dochandle_t handle)
282 {
283 	xmlValidCtxtPtr cvp;
284 	xmlDocPtr top;
285 	xmlNodePtr child, next;
286 	struct stat statbuf;
287 	int valid;
288 
289 	if (zonename == NULL)
290 		return (Z_NO_ZONE);
291 	if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) {
292 		/* distinguish file not found vs. found but not parsed */
293 		if (stat(filename, &statbuf) == 0)
294 			return (Z_INVALID_DOCUMENT);
295 		return (Z_NO_ZONE);
296 	}
297 	if ((cvp = xmlNewValidCtxt()) == NULL)
298 		return (Z_NOMEM);
299 	cvp->error = zonecfg_error_func;
300 	cvp->warning = zonecfg_error_func;
301 	valid = xmlValidateDocument(cvp, handle->zone_dh_doc);
302 	xmlFreeValidCtxt(cvp);
303 	if (valid == 0)
304 		return (Z_INVALID_DOCUMENT);
305 	/* delete any comments such as inherited Sun copyright / ident str */
306 	top = handle->zone_dh_doc;
307 	for (child = top->xmlChildrenNode; child != NULL; child = next) {
308 		next = child->next;
309 		if (child->name == NULL)
310 			continue;
311 		if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) {
312 			next = child->next;
313 			xmlUnlinkNode(child);
314 			xmlFreeNode(child);
315 		}
316 	}
317 	return (Z_OK);
318 }
319 
320 int
321 zonecfg_get_handle(char *zonename, zone_dochandle_t handle)
322 {
323 	char path[MAXPATHLEN];
324 
325 	config_file_path(zonename, path);
326 	return (zonecfg_get_handle_impl(zonename, path, handle));
327 }
328 
329 int
330 zonecfg_get_snapshot_handle(char *zonename, zone_dochandle_t handle)
331 {
332 	char path[MAXPATHLEN];
333 
334 	snap_file_path(zonename, path);
335 	return (zonecfg_get_handle_impl(zonename, path, handle));
336 }
337 
338 int
339 zonecfg_get_name(zone_dochandle_t handle, char *name, size_t namesize)
340 {
341 	return (getrootattr(handle, DTD_ATTR_NAME, name, namesize));
342 }
343 
344 int
345 zonecfg_set_name(zone_dochandle_t handle, char *name)
346 {
347 	return (setrootattr(handle, DTD_ATTR_NAME, name));
348 }
349 
350 int
351 zonecfg_get_zonepath(zone_dochandle_t handle, char *path, size_t pathsize)
352 {
353 	return (getrootattr(handle, DTD_ATTR_ZONEPATH, path, pathsize));
354 }
355 
356 int
357 zonecfg_set_zonepath(zone_dochandle_t handle, char *zonepath)
358 {
359 	return (setrootattr(handle, DTD_ATTR_ZONEPATH, zonepath));
360 }
361 
362 int
363 zonecfg_get_autoboot(zone_dochandle_t handle, boolean_t *autoboot)
364 {
365 	char autobootstr[DTD_ENTITY_BOOL_LEN];
366 	int ret;
367 
368 	if ((ret = getrootattr(handle, DTD_ATTR_AUTOBOOT, autobootstr,
369 	    sizeof (autobootstr))) != Z_OK)
370 		return (ret);
371 
372 	if (strcmp(autobootstr, DTD_ENTITY_TRUE) == 0)
373 		*autoboot = B_TRUE;
374 	else if (strcmp(autobootstr, DTD_ENTITY_FALSE) == 0)
375 		*autoboot = B_FALSE;
376 	else
377 		ret = Z_BAD_PROPERTY;
378 	return (ret);
379 }
380 
381 int
382 zonecfg_set_autoboot(zone_dochandle_t handle, boolean_t autoboot)
383 {
384 	return (setrootattr(handle, DTD_ATTR_AUTOBOOT,
385 	    autoboot ? DTD_ENTITY_TRUE : DTD_ENTITY_FALSE));
386 }
387 
388 int
389 zonecfg_get_pool(zone_dochandle_t handle, char *pool, size_t poolsize)
390 {
391 	return (getrootattr(handle, DTD_ATTR_POOL, pool, poolsize));
392 }
393 
394 int
395 zonecfg_set_pool(zone_dochandle_t handle, char *pool)
396 {
397 	return (setrootattr(handle, DTD_ATTR_POOL, pool));
398 }
399 
400 /*
401  * /etc/zones/index caches a vital piece of information which is also
402  * in the <zonename>.xml file: the path to the zone.  This is for performance,
403  * since we need to walk all zonepath's in order to be able to detect conflicts
404  * (see crosscheck_zonepaths() in the zoneadm command).
405  */
406 int
407 zonecfg_refresh_index_file(zone_dochandle_t handle)
408 {
409 	char name[ZONENAME_MAX], zonepath[MAXPATHLEN];
410 	struct zoneent ze;
411 	int err;
412 
413 	if ((err = zonecfg_get_name(handle, name, sizeof (name))) != Z_OK)
414 		return (err);
415 	if ((err = zonecfg_get_zonepath(handle, zonepath,
416 	    sizeof (zonepath))) != Z_OK)
417 		return (err);
418 	(void) strlcpy(ze.zone_name, name, sizeof (ze.zone_name));
419 	ze.zone_state = -1;
420 	(void) strlcpy(ze.zone_path, zonepath, sizeof (ze.zone_path));
421 	return (putzoneent(&ze, PZE_MODIFY));
422 }
423 
424 static int
425 zonecfg_save_impl(zone_dochandle_t handle, char *filename)
426 {
427 	char tmpfile[MAXPATHLEN];
428 	int tmpfd;
429 	xmlValidCtxt cvp = { NULL };
430 	xmlNodePtr comment;
431 
432 	(void) strlcpy(tmpfile, filename, sizeof (tmpfile));
433 	(void) dirname(tmpfile);
434 	(void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile));
435 
436 	tmpfd = mkstemp(tmpfile);
437 	if (tmpfd == -1) {
438 		(void) unlink(tmpfile);
439 		return (Z_TEMP_FILE);
440 	}
441 	(void) close(tmpfd);
442 
443 	cvp.error = zonecfg_error_func;
444 	cvp.warning = zonecfg_error_func;
445 
446 	if ((comment = xmlNewComment((xmlChar *) "\n    DO NOT EDIT THIS "
447 	    "FILE.  Use zonecfg(1M) instead.\n")) == NULL)
448 		goto err;
449 	if (xmlAddPrevSibling(handle->zone_dh_top, comment) == 0)
450 		goto err;
451 
452 	if (xmlValidateDocument(&cvp, handle->zone_dh_doc) == 0)
453 		goto err;
454 
455 	if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0)
456 		goto err;
457 	(void) chmod(tmpfile, 0644);
458 
459 	if (rename(tmpfile, filename) == -1) {
460 		(void) unlink(tmpfile);
461 		if (errno == EACCES)
462 			return (Z_ACCES);
463 		return (Z_MISC_FS);
464 	}
465 
466 	/* now update the cached copy of the zone path in the index file */
467 	return (zonecfg_refresh_index_file(handle));
468 
469 err:
470 	(void) unlink(tmpfile);
471 	return (Z_SAVING_FILE);
472 }
473 
474 int
475 zonecfg_save(zone_dochandle_t handle)
476 {
477 	char zname[MAXPATHLEN], path[MAXPATHLEN];
478 	int err;
479 
480 	if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK) {
481 		return (err);
482 	}
483 	config_file_path(zname, path);
484 	return (zonecfg_save_impl(handle, path));
485 }
486 
487 /*
488  * Special case: if access(2) fails with ENOENT, then try again using
489  * ZONE_CONFIG_ROOT instead of config_file_path(zonename).  This is how we
490  * work around the case of a config file which has not been created yet:
491  * the user will need access to the directory so use that as a heuristic.
492  */
493 
494 int
495 zonecfg_access(const char *zonename, int amode)
496 {
497 	char path[MAXPATHLEN];
498 
499 	config_file_path(zonename, path);
500 	if (access(path, amode) == 0)
501 		return (Z_OK);
502 	if (errno == ENOENT && access(ZONE_CONFIG_ROOT, amode) == 0)
503 		return (Z_OK);
504 	if (errno == EACCES)
505 		return (Z_ACCES);
506 	if (errno == EINVAL)
507 		return (Z_INVAL);
508 	return (Z_MISC_FS);
509 }
510 
511 int
512 zonecfg_create_snapshot(char *zonename)
513 {
514 	zone_dochandle_t handle;
515 	char path[MAXPATHLEN], zonepath[MAXPATHLEN], rpath[MAXPATHLEN];
516 	int error = Z_OK, res;
517 
518 	if ((handle = zonecfg_init_handle()) == NULL) {
519 		return (Z_NOMEM);
520 	}
521 
522 	if ((error = zonecfg_get_handle(zonename, handle)) != Z_OK)
523 		goto out;
524 	if ((error = operation_prep(handle)) != Z_OK)
525 		goto out;
526 	error = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath));
527 	if (error != Z_OK)
528 		goto out;
529 	if ((res = resolvepath(zonepath, rpath, sizeof (rpath))) == -1) {
530 		error = Z_RESOLVED_PATH;
531 		goto out;
532 	}
533 	/*
534 	 * If the resolved path is not the same as the original path, then
535 	 * save the resolved path in the snapshot, thus preventing any
536 	 * potential problems down the line when zoneadmd goes to unmount
537 	 * file systems and depends on initial string matches with resolved
538 	 * paths.
539 	 */
540 	rpath[res] = '\0';
541 	if (strcmp(zonepath, rpath) != 0) {
542 		if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK)
543 			goto out;
544 	}
545 	if ((mkdir(ZONE_SNAPSHOT_ROOT, S_IRWXU) == -1) && (errno != EEXIST)) {
546 		error = Z_MISC_FS;
547 		goto out;
548 	}
549 
550 	snap_file_path(zonename, path);
551 	error = zonecfg_save_impl(handle, path);
552 
553 out:
554 	zonecfg_fini_handle(handle);
555 	return (error);
556 }
557 
558 static int
559 newprop(xmlNodePtr node, const xmlChar *attrname, char *src)
560 {
561 	xmlAttrPtr newattr;
562 
563 	newattr = xmlNewProp(node, attrname, (xmlChar *)src);
564 	if (newattr == NULL) {
565 		xmlUnlinkNode(node);
566 		xmlFreeNode(node);
567 		return (Z_BAD_PROPERTY);
568 	}
569 	return (Z_OK);
570 }
571 
572 static int
573 zonecfg_add_filesystem_core(zone_dochandle_t handle, struct zone_fstab *tabptr)
574 {
575 	xmlNodePtr newnode, cur = handle->zone_dh_cur, options_node;
576 	zone_fsopt_t *ptr;
577 	int err;
578 
579 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_FS, NULL);
580 	if ((err = newprop(newnode, DTD_ATTR_SPECIAL,
581 	    tabptr->zone_fs_special)) != Z_OK)
582 		return (err);
583 	if (tabptr->zone_fs_raw[0] != '\0' &&
584 	    (err = newprop(newnode, DTD_ATTR_RAW, tabptr->zone_fs_raw)) != Z_OK)
585 		return (err);
586 	if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK)
587 		return (err);
588 	if ((err = newprop(newnode, DTD_ATTR_TYPE,
589 	    tabptr->zone_fs_type)) != Z_OK)
590 		return (err);
591 	if (tabptr->zone_fs_options != NULL) {
592 		for (ptr = tabptr->zone_fs_options; ptr != NULL;
593 		    ptr = ptr->zone_fsopt_next) {
594 			options_node = xmlNewTextChild(newnode, NULL,
595 			    DTD_ELEM_FSOPTION, NULL);
596 			if ((err = newprop(options_node, DTD_ATTR_NAME,
597 			    ptr->zone_fsopt_opt)) != Z_OK)
598 				return (err);
599 		}
600 	}
601 	return (Z_OK);
602 }
603 
604 int
605 zonecfg_add_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
606 {
607 	int err;
608 
609 	if (tabptr == NULL)
610 		return (Z_INVAL);
611 
612 	if ((err = operation_prep(handle)) != Z_OK)
613 		return (err);
614 
615 	if ((err = zonecfg_add_filesystem_core(handle, tabptr)) != Z_OK)
616 		return (err);
617 
618 	return (Z_OK);
619 }
620 
621 static int
622 zonecfg_add_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr)
623 {
624 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
625 	int err;
626 
627 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_IPD, NULL);
628 	if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK)
629 		return (err);
630 	return (Z_OK);
631 }
632 
633 int
634 zonecfg_add_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr)
635 {
636 	int err;
637 
638 	if (tabptr == NULL)
639 		return (Z_INVAL);
640 
641 	if ((err = operation_prep(handle)) != Z_OK)
642 		return (err);
643 
644 	if ((err = zonecfg_add_ipd_core(handle, tabptr)) != Z_OK)
645 		return (err);
646 
647 	return (Z_OK);
648 }
649 
650 int
651 zonecfg_add_fs_option(struct zone_fstab *tabptr, char *option)
652 {
653 	zone_fsopt_t *last, *old, *new;
654 
655 	last = tabptr->zone_fs_options;
656 	for (old = last; old != NULL; old = old->zone_fsopt_next)
657 		last = old;	/* walk to the end of the list */
658 	new = (zone_fsopt_t *)malloc(sizeof (zone_fsopt_t));
659 	if (new == NULL)
660 		return (Z_NOMEM);
661 	(void) strlcpy(new->zone_fsopt_opt, option,
662 	    sizeof (new->zone_fsopt_opt));
663 	new->zone_fsopt_next = NULL;
664 	if (last == NULL)
665 		tabptr->zone_fs_options = new;
666 	else
667 		last->zone_fsopt_next = new;
668 	return (Z_OK);
669 }
670 
671 int
672 zonecfg_remove_fs_option(struct zone_fstab *tabptr, char *option)
673 {
674 	zone_fsopt_t *last, *this, *next;
675 
676 	last = tabptr->zone_fs_options;
677 	for (this = last; this != NULL; this = this->zone_fsopt_next) {
678 		if (strcmp(this->zone_fsopt_opt, option) == 0) {
679 			next = this->zone_fsopt_next;
680 			if (this == tabptr->zone_fs_options)
681 				tabptr->zone_fs_options = next;
682 			else
683 				last->zone_fsopt_next = next;
684 			free(this);
685 			return (Z_OK);
686 		} else
687 			last = this;
688 	}
689 	return (Z_NO_PROPERTY_ID);
690 }
691 
692 void
693 zonecfg_free_fs_option_list(zone_fsopt_t *list)
694 {
695 	zone_fsopt_t *this, *next;
696 
697 	for (this = list; this != NULL; this = next) {
698 		next = this->zone_fsopt_next;
699 		free(this);
700 	}
701 }
702 
703 void
704 zonecfg_free_rctl_value_list(struct zone_rctlvaltab *valtab)
705 {
706 	if (valtab == NULL)
707 		return;
708 	zonecfg_free_rctl_value_list(valtab->zone_rctlval_next);
709 	free(valtab);
710 }
711 
712 static boolean_t
713 match_prop(xmlNodePtr cur, const xmlChar *attr, char *user_prop)
714 {
715 	xmlChar *gotten_prop;
716 	int prop_result;
717 
718 	gotten_prop = xmlGetProp(cur, attr);
719 	if (gotten_prop == NULL)	/* shouldn't happen */
720 		return (B_FALSE);
721 	prop_result = xmlStrcmp(gotten_prop, (const xmlChar *) user_prop);
722 	xmlFree(gotten_prop);
723 	return ((prop_result == 0));
724 }
725 
726 static int
727 zonecfg_delete_filesystem_core(zone_dochandle_t handle,
728     struct zone_fstab *tabptr)
729 {
730 	xmlNodePtr cur = handle->zone_dh_cur;
731 	boolean_t dir_match, spec_match, raw_match, type_match;
732 
733 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
734 		if (xmlStrcmp(cur->name, DTD_ELEM_FS))
735 			continue;
736 		dir_match = match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir);
737 		spec_match = match_prop(cur, DTD_ATTR_SPECIAL,
738 		    tabptr->zone_fs_special);
739 		raw_match = match_prop(cur, DTD_ATTR_RAW,
740 		    tabptr->zone_fs_raw);
741 		type_match = match_prop(cur, DTD_ATTR_TYPE,
742 		    tabptr->zone_fs_type);
743 		if (dir_match && spec_match && raw_match && type_match) {
744 			xmlUnlinkNode(cur);
745 			xmlFreeNode(cur);
746 			return (Z_OK);
747 		}
748 	}
749 	return (Z_NO_RESOURCE_ID);
750 }
751 
752 int
753 zonecfg_delete_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
754 {
755 	int err;
756 
757 	if (tabptr == NULL)
758 		return (Z_INVAL);
759 
760 	if ((err = operation_prep(handle)) != Z_OK)
761 		return (err);
762 
763 	if ((err = zonecfg_delete_filesystem_core(handle, tabptr)) != Z_OK)
764 		return (err);
765 
766 	return (Z_OK);
767 }
768 
769 int
770 zonecfg_modify_filesystem(
771 	zone_dochandle_t handle,
772 	struct zone_fstab *oldtabptr,
773 	struct zone_fstab *newtabptr)
774 {
775 	int err;
776 
777 	if (oldtabptr == NULL || newtabptr == NULL)
778 		return (Z_INVAL);
779 
780 	if ((err = operation_prep(handle)) != Z_OK)
781 		return (err);
782 
783 	if ((err = zonecfg_delete_filesystem_core(handle, oldtabptr)) != Z_OK)
784 		return (err);
785 
786 	if ((err = zonecfg_add_filesystem_core(handle, newtabptr)) != Z_OK)
787 		return (err);
788 
789 	return (Z_OK);
790 }
791 
792 static int
793 zonecfg_delete_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr)
794 {
795 	xmlNodePtr cur = handle->zone_dh_cur;
796 
797 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
798 		if (xmlStrcmp(cur->name, DTD_ELEM_IPD))
799 			continue;
800 		if (match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir)) {
801 			xmlUnlinkNode(cur);
802 			xmlFreeNode(cur);
803 			return (Z_OK);
804 		}
805 	}
806 	return (Z_NO_RESOURCE_ID);
807 }
808 
809 int
810 zonecfg_delete_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr)
811 {
812 	int err;
813 
814 	if (tabptr == NULL)
815 		return (Z_INVAL);
816 
817 	if ((err = operation_prep(handle)) != Z_OK)
818 		return (err);
819 
820 	if ((err = zonecfg_delete_ipd_core(handle, tabptr)) != Z_OK)
821 		return (err);
822 
823 	return (Z_OK);
824 }
825 
826 int
827 zonecfg_modify_ipd(zone_dochandle_t handle, struct zone_fstab *oldtabptr,
828     struct zone_fstab *newtabptr)
829 {
830 	int err;
831 
832 	if (oldtabptr == NULL || newtabptr == NULL)
833 		return (Z_INVAL);
834 
835 	if ((err = operation_prep(handle)) != Z_OK)
836 		return (err);
837 
838 	if ((err = zonecfg_delete_ipd_core(handle, oldtabptr)) != Z_OK)
839 		return (err);
840 
841 	if ((err = zonecfg_add_ipd_core(handle, newtabptr)) != Z_OK)
842 		return (err);
843 
844 	return (Z_OK);
845 }
846 
847 static int
848 fetchprop(xmlNodePtr cur, const xmlChar *propname, char *dst, size_t dstsize)
849 {
850 	xmlChar *property;
851 	size_t srcsize;
852 
853 	if ((property = xmlGetProp(cur, propname)) == NULL)
854 		return (Z_BAD_PROPERTY);
855 	srcsize = strlcpy(dst, (char *)property, dstsize);
856 	xmlFree(property);
857 	if (srcsize >= dstsize)
858 		return (Z_TOO_BIG);
859 	return (Z_OK);
860 }
861 
862 int
863 zonecfg_lookup_filesystem(
864 	zone_dochandle_t handle,
865 	struct zone_fstab *tabptr)
866 {
867 	xmlNodePtr cur, options, firstmatch;
868 	int err;
869 	char dirname[MAXPATHLEN], special[MAXPATHLEN], raw[MAXPATHLEN];
870 	char type[FSTYPSZ];
871 	char options_str[MAX_MNTOPT_STR];
872 
873 	if (tabptr == NULL)
874 		return (Z_INVAL);
875 
876 	if ((err = operation_prep(handle)) != Z_OK)
877 		return (err);
878 
879 	/*
880 	 * Walk the list of children looking for matches on any properties
881 	 * specified in the fstab parameter.  If more than one resource
882 	 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return
883 	 * Z_NO_RESOURCE_ID.
884 	 */
885 	cur = handle->zone_dh_cur;
886 	firstmatch = NULL;
887 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
888 		if (xmlStrcmp(cur->name, DTD_ELEM_FS))
889 			continue;
890 		if (strlen(tabptr->zone_fs_dir) > 0) {
891 			if ((fetchprop(cur, DTD_ATTR_DIR, dirname,
892 			    sizeof (dirname)) == Z_OK) &&
893 			    (strcmp(tabptr->zone_fs_dir, dirname) == 0)) {
894 				if (firstmatch == NULL)
895 					firstmatch = cur;
896 				else
897 					return (Z_INSUFFICIENT_SPEC);
898 			}
899 		}
900 		if (strlen(tabptr->zone_fs_special) > 0) {
901 			if ((fetchprop(cur, DTD_ATTR_SPECIAL, special,
902 			    sizeof (special)) == Z_OK)) {
903 				if (strcmp(tabptr->zone_fs_special,
904 				    special) == 0) {
905 					if (firstmatch == NULL)
906 						firstmatch = cur;
907 					else if (firstmatch != cur)
908 						return (Z_INSUFFICIENT_SPEC);
909 				} else {
910 					/*
911 					 * If another property matched but this
912 					 * one doesn't then reset firstmatch.
913 					 */
914 					if (firstmatch == cur)
915 						firstmatch = NULL;
916 				}
917 			}
918 		}
919 		if (strlen(tabptr->zone_fs_raw) > 0) {
920 			if ((fetchprop(cur, DTD_ATTR_RAW, raw,
921 			    sizeof (raw)) == Z_OK)) {
922 				if (strcmp(tabptr->zone_fs_raw, raw) == 0) {
923 					if (firstmatch == NULL)
924 						firstmatch = cur;
925 					else if (firstmatch != cur)
926 						return (Z_INSUFFICIENT_SPEC);
927 				} else {
928 					/*
929 					 * If another property matched but this
930 					 * one doesn't then reset firstmatch.
931 					 */
932 					if (firstmatch == cur)
933 						firstmatch = NULL;
934 				}
935 			}
936 		}
937 		if (strlen(tabptr->zone_fs_type) > 0) {
938 			if ((fetchprop(cur, DTD_ATTR_TYPE, type,
939 			    sizeof (type)) == Z_OK)) {
940 				if (strcmp(tabptr->zone_fs_type, type) == 0) {
941 					if (firstmatch == NULL)
942 						firstmatch = cur;
943 					else if (firstmatch != cur)
944 						return (Z_INSUFFICIENT_SPEC);
945 				} else {
946 					/*
947 					 * If another property matched but this
948 					 * one doesn't then reset firstmatch.
949 					 */
950 					if (firstmatch == cur)
951 						firstmatch = NULL;
952 				}
953 			}
954 		}
955 	}
956 
957 	if (firstmatch == NULL)
958 		return (Z_NO_RESOURCE_ID);
959 
960 	cur = firstmatch;
961 
962 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
963 	    sizeof (tabptr->zone_fs_dir))) != Z_OK)
964 		return (err);
965 
966 	if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
967 	    sizeof (tabptr->zone_fs_special))) != Z_OK)
968 		return (err);
969 
970 	if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
971 	    sizeof (tabptr->zone_fs_raw))) != Z_OK)
972 		return (err);
973 
974 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
975 	    sizeof (tabptr->zone_fs_type))) != Z_OK)
976 		return (err);
977 
978 	/* options are optional */
979 	tabptr->zone_fs_options = NULL;
980 	for (options = cur->xmlChildrenNode; options != NULL;
981 	    options = options->next) {
982 		if ((fetchprop(options, DTD_ATTR_NAME, options_str,
983 		    sizeof (options_str)) != Z_OK))
984 			break;
985 		if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
986 			break;
987 	}
988 	return (Z_OK);
989 }
990 
991 int
992 zonecfg_lookup_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr)
993 {
994 	xmlNodePtr cur, match;
995 	int err;
996 	char dirname[MAXPATHLEN];
997 
998 	if (tabptr == NULL)
999 		return (Z_INVAL);
1000 
1001 	if ((err = operation_prep(handle)) != Z_OK)
1002 		return (err);
1003 
1004 	/*
1005 	 * General algorithm:
1006 	 * Walk the list of children looking for matches on any properties
1007 	 * specified in the fstab parameter.  If more than one resource
1008 	 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return
1009 	 * Z_NO_RESOURCE_ID.
1010 	 */
1011 	cur = handle->zone_dh_cur;
1012 	match = NULL;
1013 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1014 		if (xmlStrcmp(cur->name, DTD_ELEM_IPD))
1015 			continue;
1016 		if (strlen(tabptr->zone_fs_dir) > 0) {
1017 			if ((fetchprop(cur, DTD_ATTR_DIR, dirname,
1018 			    sizeof (dirname)) == Z_OK) &&
1019 			    (strcmp(tabptr->zone_fs_dir, dirname) == 0)) {
1020 				if (match == NULL)
1021 					match = cur;
1022 				else
1023 					return (Z_INSUFFICIENT_SPEC);
1024 			}
1025 		}
1026 	}
1027 
1028 	if (match == NULL)
1029 		return (Z_NO_RESOURCE_ID);
1030 
1031 	cur = match;
1032 
1033 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
1034 	    sizeof (tabptr->zone_fs_dir))) != Z_OK)
1035 		return (err);
1036 
1037 	return (Z_OK);
1038 }
1039 
1040 /*
1041  * Compare two IP addresses in string form.  Allow for the possibility that
1042  * one might have "/<prefix-length>" at the end: allow a match on just the
1043  * IP address (or host name) part.
1044  */
1045 
1046 boolean_t
1047 zonecfg_same_net_address(char *a1, char *a2)
1048 {
1049 	char *slashp, *slashp1, *slashp2;
1050 	int result;
1051 
1052 	if (strcmp(a1, a2) == 0)
1053 		return (B_TRUE);
1054 
1055 	/*
1056 	 * If neither has a slash or both do, they need to match to be
1057 	 * considered the same, but they did not match above, so fail.
1058 	 */
1059 	slashp1 = strchr(a1, '/');
1060 	slashp2 = strchr(a2, '/');
1061 	if ((slashp1 == NULL && slashp2 == NULL) ||
1062 	    (slashp1 != NULL && slashp2 != NULL))
1063 		return (B_FALSE);
1064 
1065 	/*
1066 	 * Only one had a slash: pick that one, zero out the slash, compare
1067 	 * the "address only" strings, restore the slash, and return the
1068 	 * result of the comparison.
1069 	 */
1070 	slashp = (slashp1 == NULL) ? slashp2 : slashp1;
1071 	*slashp = '\0';
1072 	result = strcmp(a1, a2);
1073 	*slashp = '/';
1074 	return ((result == 0));
1075 }
1076 
1077 int
1078 zonecfg_valid_net_address(char *address, struct lifreq *lifr)
1079 {
1080 	struct sockaddr_in *sin4;
1081 	struct sockaddr_in6 *sin6;
1082 	struct addrinfo hints, *result;
1083 	char *slashp = strchr(address, '/');
1084 
1085 	bzero(lifr, sizeof (struct lifreq));
1086 	sin4 = (struct sockaddr_in *)&lifr->lifr_addr;
1087 	sin6 = (struct sockaddr_in6 *)&lifr->lifr_addr;
1088 	if (slashp != NULL)
1089 		*slashp = '\0';
1090 	if (inet_pton(AF_INET, address, &sin4->sin_addr) == 1) {
1091 		sin4->sin_family = AF_INET;
1092 	} else if (inet_pton(AF_INET6, address, &sin6->sin6_addr) == 1) {
1093 		if (slashp == NULL)
1094 			return (Z_IPV6_ADDR_PREFIX_LEN);
1095 		sin6->sin6_family = AF_INET6;
1096 	} else {
1097 		/* "address" may be a host name */
1098 		(void) memset(&hints, 0, sizeof (hints));
1099 		hints.ai_family = PF_INET;
1100 		if (getaddrinfo(address, NULL, &hints, &result) != 0)
1101 			return (Z_BOGUS_ADDRESS);
1102 		sin4->sin_family = result->ai_family;
1103 
1104 		(void) memcpy(&sin4->sin_addr,
1105 		    /* LINTED E_BAD_PTR_CAST_ALIGN */
1106 		    &((struct sockaddr_in *)result->ai_addr)->sin_addr,
1107 		    sizeof (struct in_addr));
1108 
1109 		freeaddrinfo(result);
1110 	}
1111 	return (Z_OK);
1112 }
1113 
1114 int
1115 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
1116 {
1117 	xmlNodePtr cur, firstmatch;
1118 	int err;
1119 	char address[INET6_ADDRSTRLEN], physical[LIFNAMSIZ];
1120 
1121 	if (tabptr == NULL)
1122 		return (Z_INVAL);
1123 
1124 	if ((err = operation_prep(handle)) != Z_OK)
1125 		return (err);
1126 
1127 	cur = handle->zone_dh_cur;
1128 	firstmatch = NULL;
1129 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1130 		if (xmlStrcmp(cur->name, DTD_ELEM_NET))
1131 			continue;
1132 		if (strlen(tabptr->zone_nwif_physical) > 0) {
1133 			if ((fetchprop(cur, DTD_ATTR_PHYSICAL, physical,
1134 			    sizeof (physical)) == Z_OK) &&
1135 			    (strcmp(tabptr->zone_nwif_physical,
1136 			    physical) == 0)) {
1137 				if (firstmatch == NULL)
1138 					firstmatch = cur;
1139 				else
1140 					return (Z_INSUFFICIENT_SPEC);
1141 			}
1142 		}
1143 		if (strlen(tabptr->zone_nwif_address) > 0) {
1144 			if ((fetchprop(cur, DTD_ATTR_ADDRESS, address,
1145 			    sizeof (address)) == Z_OK)) {
1146 				if (zonecfg_same_net_address(
1147 				    tabptr->zone_nwif_address, address)) {
1148 					if (firstmatch == NULL)
1149 						firstmatch = cur;
1150 					else if (firstmatch != cur)
1151 						return (Z_INSUFFICIENT_SPEC);
1152 				} else {
1153 					/*
1154 					 * If another property matched but this
1155 					 * one doesn't then reset firstmatch.
1156 					 */
1157 					if (firstmatch == cur)
1158 						firstmatch = NULL;
1159 				}
1160 			}
1161 		}
1162 	}
1163 	if (firstmatch == NULL)
1164 		return (Z_NO_RESOURCE_ID);
1165 
1166 	cur = firstmatch;
1167 
1168 	if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
1169 	    sizeof (tabptr->zone_nwif_physical))) != Z_OK)
1170 		return (err);
1171 
1172 	if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
1173 	    sizeof (tabptr->zone_nwif_address))) != Z_OK)
1174 		return (err);
1175 
1176 	return (Z_OK);
1177 }
1178 
1179 static int
1180 zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
1181 {
1182 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
1183 	int err;
1184 
1185 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL);
1186 	if ((err = newprop(newnode, DTD_ATTR_ADDRESS,
1187 	    tabptr->zone_nwif_address)) != Z_OK)
1188 		return (err);
1189 	if ((err = newprop(newnode, DTD_ATTR_PHYSICAL,
1190 	    tabptr->zone_nwif_physical)) != Z_OK)
1191 		return (err);
1192 	return (Z_OK);
1193 }
1194 
1195 int
1196 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
1197 {
1198 	int err;
1199 
1200 	if (tabptr == NULL)
1201 		return (Z_INVAL);
1202 
1203 	if ((err = operation_prep(handle)) != Z_OK)
1204 		return (err);
1205 
1206 	if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK)
1207 		return (err);
1208 
1209 	return (Z_OK);
1210 }
1211 
1212 static int
1213 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
1214 {
1215 	xmlNodePtr cur = handle->zone_dh_cur;
1216 	boolean_t addr_match, phys_match;
1217 
1218 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1219 		if (xmlStrcmp(cur->name, DTD_ELEM_NET))
1220 			continue;
1221 
1222 		addr_match = match_prop(cur, DTD_ATTR_ADDRESS,
1223 		    tabptr->zone_nwif_address);
1224 		phys_match = match_prop(cur, DTD_ATTR_PHYSICAL,
1225 		    tabptr->zone_nwif_physical);
1226 
1227 		if (addr_match && phys_match) {
1228 			xmlUnlinkNode(cur);
1229 			xmlFreeNode(cur);
1230 			return (Z_OK);
1231 		}
1232 	}
1233 	return (Z_NO_RESOURCE_ID);
1234 }
1235 
1236 int
1237 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
1238 {
1239 	int err;
1240 
1241 	if (tabptr == NULL)
1242 		return (Z_INVAL);
1243 
1244 	if ((err = operation_prep(handle)) != Z_OK)
1245 		return (err);
1246 
1247 	if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK)
1248 		return (err);
1249 
1250 	return (Z_OK);
1251 }
1252 
1253 int
1254 zonecfg_modify_nwif(
1255 	zone_dochandle_t handle,
1256 	struct zone_nwiftab *oldtabptr,
1257 	struct zone_nwiftab *newtabptr)
1258 {
1259 	int err;
1260 
1261 	if (oldtabptr == NULL || newtabptr == NULL)
1262 		return (Z_INVAL);
1263 
1264 	if ((err = operation_prep(handle)) != Z_OK)
1265 		return (err);
1266 
1267 	if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK)
1268 		return (err);
1269 
1270 	if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK)
1271 		return (err);
1272 
1273 	return (Z_OK);
1274 }
1275 
1276 int
1277 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
1278 {
1279 	xmlNodePtr cur, firstmatch;
1280 	int err;
1281 	char match[MAXPATHLEN];
1282 
1283 	if (tabptr == NULL)
1284 		return (Z_INVAL);
1285 
1286 	if ((err = operation_prep(handle)) != Z_OK)
1287 		return (err);
1288 
1289 	cur = handle->zone_dh_cur;
1290 	firstmatch = NULL;
1291 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1292 		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
1293 			continue;
1294 		if (strlen(tabptr->zone_dev_match) == 0)
1295 			continue;
1296 
1297 		if ((fetchprop(cur, DTD_ATTR_MATCH, match,
1298 		    sizeof (match)) == Z_OK)) {
1299 			if (strcmp(tabptr->zone_dev_match,
1300 			    match) == 0) {
1301 				if (firstmatch == NULL)
1302 					firstmatch = cur;
1303 				else if (firstmatch != cur)
1304 					return (Z_INSUFFICIENT_SPEC);
1305 			} else {
1306 				/*
1307 				 * If another property matched but this
1308 				 * one doesn't then reset firstmatch.
1309 				 */
1310 				if (firstmatch == cur)
1311 					firstmatch = NULL;
1312 			}
1313 		}
1314 	}
1315 	if (firstmatch == NULL)
1316 		return (Z_NO_RESOURCE_ID);
1317 
1318 	cur = firstmatch;
1319 
1320 	if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
1321 	    sizeof (tabptr->zone_dev_match))) != Z_OK)
1322 		return (err);
1323 
1324 	return (Z_OK);
1325 }
1326 
1327 static int
1328 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
1329 {
1330 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
1331 	int err;
1332 
1333 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL);
1334 
1335 	if ((err = newprop(newnode, DTD_ATTR_MATCH,
1336 	    tabptr->zone_dev_match)) != Z_OK)
1337 		return (err);
1338 
1339 	return (Z_OK);
1340 }
1341 
1342 int
1343 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
1344 {
1345 	int err;
1346 
1347 	if (tabptr == NULL)
1348 		return (Z_INVAL);
1349 
1350 	if ((err = operation_prep(handle)) != Z_OK)
1351 		return (err);
1352 
1353 	if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK)
1354 		return (err);
1355 
1356 	return (Z_OK);
1357 }
1358 
1359 static int
1360 zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
1361 {
1362 	xmlNodePtr cur = handle->zone_dh_cur;
1363 	int match_match;
1364 
1365 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1366 		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
1367 			continue;
1368 
1369 		match_match = match_prop(cur, DTD_ATTR_MATCH,
1370 		    tabptr->zone_dev_match);
1371 
1372 		if (match_match) {
1373 			xmlUnlinkNode(cur);
1374 			xmlFreeNode(cur);
1375 			return (Z_OK);
1376 		}
1377 	}
1378 	return (Z_NO_RESOURCE_ID);
1379 }
1380 
1381 int
1382 zonecfg_delete_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
1383 {
1384 	int err;
1385 
1386 	if (tabptr == NULL)
1387 		return (Z_INVAL);
1388 
1389 	if ((err = operation_prep(handle)) != Z_OK)
1390 		return (err);
1391 
1392 	if ((err = zonecfg_delete_dev_core(handle, tabptr)) != Z_OK)
1393 		return (err);
1394 
1395 	return (Z_OK);
1396 }
1397 
1398 int
1399 zonecfg_modify_dev(
1400 	zone_dochandle_t handle,
1401 	struct zone_devtab *oldtabptr,
1402 	struct zone_devtab *newtabptr)
1403 {
1404 	int err;
1405 
1406 	if (oldtabptr == NULL || newtabptr == NULL)
1407 		return (Z_INVAL);
1408 
1409 	if ((err = operation_prep(handle)) != Z_OK)
1410 		return (err);
1411 
1412 	if ((err = zonecfg_delete_dev_core(handle, oldtabptr)) != Z_OK)
1413 		return (err);
1414 
1415 	if ((err = zonecfg_add_dev_core(handle, newtabptr)) != Z_OK)
1416 		return (err);
1417 
1418 	return (Z_OK);
1419 }
1420 
1421 /*
1422  * This is the set of devices which must be present in every zone.  Users
1423  * can augment this list with additional device rules in their zone
1424  * configuration, but at present cannot remove any of the this set of
1425  * standard devices.  All matching is done by /dev pathname (the "/dev"
1426  * part is implicit.  Try to keep rules which match a large number of
1427  * devices (like the pts rule) first.
1428  */
1429 static const char *standard_devs[] = {
1430 	"pts/*",
1431 	"ptmx",
1432 	"random",
1433 	"urandom",
1434 	"poll",
1435 	"pool",
1436 	"kstat",
1437 	"zero",
1438 	"null",
1439 	"crypto",
1440 	"cryptoadm",
1441 	"ticots",
1442 	"ticotsord",
1443 	"ticlts",
1444 	"lo0",
1445 	"lo1",
1446 	"lo2",
1447 	"lo3",
1448 	"sad/user",
1449 	"tty",
1450 	"logindmux",
1451 	"log",
1452 	"conslog",
1453 	"arp",
1454 	"tcp",
1455 	"tcp6",
1456 	"udp",
1457 	"udp6",
1458 	"sysevent",
1459 #ifdef __sparc
1460 	"openprom",
1461 #endif
1462 	"cpu/self/cpuid",
1463 	"dtrace/helper",
1464 	NULL
1465 };
1466 
1467 /*
1468  * This function finds everything mounted under a zone's rootpath.
1469  * This returns the number of mounts under rootpath, or -1 on error.
1470  * callback is called once per mount found with the first argument
1471  * pointing to the  mount point.
1472  *
1473  * If the callback function returns non-zero zonecfg_find_mounts
1474  * aborts with an error.
1475  */
1476 
1477 int
1478 zonecfg_find_mounts(char *rootpath, int (*callback)(const char *, void *),
1479     void *priv) {
1480 	FILE *mnttab;
1481 	struct mnttab m;
1482 	size_t l;
1483 	int rv = 0;
1484 
1485 	assert(rootpath != NULL);
1486 
1487 	l = strlen(rootpath);
1488 
1489 	mnttab = fopen("/etc/mnttab", "r");
1490 
1491 	if (mnttab == NULL)
1492 		return (-1);
1493 
1494 	if (ioctl(fileno(mnttab), MNTIOC_SHOWHIDDEN, NULL) < 0)  {
1495 		rv = -1;
1496 		goto out;
1497 	}
1498 
1499 	while (!getmntent(mnttab, &m)) {
1500 		if ((strncmp(rootpath, m.mnt_mountp, l) == 0) &&
1501 		    (m.mnt_mountp[l] == '/')) {
1502 			rv++;
1503 			if (callback == NULL)
1504 				continue;
1505 			if (callback(m.mnt_mountp, priv)) {
1506 				rv = -1;
1507 				goto out;
1508 
1509 			}
1510 		}
1511 	}
1512 
1513 out:
1514 	(void) fclose(mnttab);
1515 	return (rv);
1516 }
1517 
1518 /*
1519  * This routine is used to determine if a given device should appear in the
1520  * zone represented by 'handle'.  First it consults the list of "standard"
1521  * zone devices.  Then it scans the user-supplied device entries.
1522  */
1523 int
1524 zonecfg_match_dev(zone_dochandle_t handle, char *devpath,
1525     struct zone_devtab *out_match)
1526 {
1527 	int err;
1528 	boolean_t found = B_FALSE;
1529 	char match[MAXPATHLEN];
1530 	const char **stdmatch;
1531 	xmlNodePtr cur;
1532 
1533 	if (handle == NULL || devpath == NULL)
1534 		return (Z_INVAL);
1535 
1536 	/*
1537 	 * Check the "standard" devices which we require to be present.
1538 	 */
1539 	for (stdmatch = &standard_devs[0]; *stdmatch != NULL; stdmatch++) {
1540 		/*
1541 		 * fnmatch gives us simple but powerful shell-style matching.
1542 		 */
1543 		if (fnmatch(*stdmatch, devpath, FNM_PATHNAME) == 0) {
1544 			if (!out_match)
1545 				return (Z_OK);
1546 			(void) snprintf(out_match->zone_dev_match,
1547 			    sizeof (out_match->zone_dev_match),
1548 			    "/dev/%s", *stdmatch);
1549 			return (Z_OK);
1550 		}
1551 	}
1552 
1553 	/*
1554 	 * We got no hits in the set of standard devices.  On to the user
1555 	 * supplied ones.
1556 	 */
1557 	if ((err = operation_prep(handle)) != Z_OK) {
1558 		handle->zone_dh_cur = NULL;
1559 		return (err);
1560 	}
1561 
1562 	cur = handle->zone_dh_cur;
1563 	cur = cur->xmlChildrenNode;
1564 	if (cur == NULL)
1565 		return (Z_NO_ENTRY);
1566 	handle->zone_dh_cur = cur;
1567 
1568 	for (; cur != NULL; cur = cur->next) {
1569 		char *m;
1570 		if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE) != 0)
1571 			continue;
1572 		if ((err = fetchprop(cur, DTD_ATTR_MATCH, match,
1573 		    sizeof (match))) != Z_OK) {
1574 			handle->zone_dh_cur = handle->zone_dh_top;
1575 			return (err);
1576 		}
1577 		m = match;
1578 		/*
1579 		 * fnmatch gives us simple but powerful shell-style matching;
1580 		 * but first, we need to strip out /dev/ from the matching rule.
1581 		 */
1582 		if (strncmp(m, "/dev/", 5) == 0)
1583 			m += 5;
1584 
1585 		if (fnmatch(m, devpath, FNM_PATHNAME) == 0) {
1586 			found = B_TRUE;
1587 			break;
1588 		}
1589 	}
1590 
1591 	if (!found)
1592 		return (Z_NO_ENTRY);
1593 
1594 	if (!out_match)
1595 		return (Z_OK);
1596 
1597 	(void) strlcpy(out_match->zone_dev_match, match,
1598 	    sizeof (out_match->zone_dev_match));
1599 	return (Z_OK);
1600 }
1601 
1602 int
1603 zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
1604 {
1605 	xmlNodePtr cur, firstmatch;
1606 	int err;
1607 	char name[MAXNAMELEN], type[MAXNAMELEN], value[MAXNAMELEN];
1608 
1609 	if (tabptr == NULL)
1610 		return (Z_INVAL);
1611 
1612 	if ((err = operation_prep(handle)) != Z_OK)
1613 		return (err);
1614 
1615 	cur = handle->zone_dh_cur;
1616 	firstmatch = NULL;
1617 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1618 		if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
1619 			continue;
1620 		if (strlen(tabptr->zone_attr_name) > 0) {
1621 			if ((fetchprop(cur, DTD_ATTR_NAME, name,
1622 			    sizeof (name)) == Z_OK) &&
1623 			    (strcmp(tabptr->zone_attr_name, name) == 0)) {
1624 				if (firstmatch == NULL)
1625 					firstmatch = cur;
1626 				else
1627 					return (Z_INSUFFICIENT_SPEC);
1628 			}
1629 		}
1630 		if (strlen(tabptr->zone_attr_type) > 0) {
1631 			if ((fetchprop(cur, DTD_ATTR_TYPE, type,
1632 			    sizeof (type)) == Z_OK)) {
1633 				if (strcmp(tabptr->zone_attr_type, type) == 0) {
1634 					if (firstmatch == NULL)
1635 						firstmatch = cur;
1636 					else if (firstmatch != cur)
1637 						return (Z_INSUFFICIENT_SPEC);
1638 				} else {
1639 					/*
1640 					 * If another property matched but this
1641 					 * one doesn't then reset firstmatch.
1642 					 */
1643 					if (firstmatch == cur)
1644 						firstmatch = NULL;
1645 				}
1646 			}
1647 		}
1648 		if (strlen(tabptr->zone_attr_value) > 0) {
1649 			if ((fetchprop(cur, DTD_ATTR_VALUE, value,
1650 			    sizeof (value)) == Z_OK)) {
1651 				if (strcmp(tabptr->zone_attr_value, value) ==
1652 				    0) {
1653 					if (firstmatch == NULL)
1654 						firstmatch = cur;
1655 					else if (firstmatch != cur)
1656 						return (Z_INSUFFICIENT_SPEC);
1657 				} else {
1658 					/*
1659 					 * If another property matched but this
1660 					 * one doesn't then reset firstmatch.
1661 					 */
1662 					if (firstmatch == cur)
1663 						firstmatch = NULL;
1664 				}
1665 			}
1666 		}
1667 	}
1668 	if (firstmatch == NULL)
1669 		return (Z_NO_RESOURCE_ID);
1670 
1671 	cur = firstmatch;
1672 
1673 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
1674 	    sizeof (tabptr->zone_attr_name))) != Z_OK)
1675 		return (err);
1676 
1677 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
1678 	    sizeof (tabptr->zone_attr_type))) != Z_OK)
1679 		return (err);
1680 
1681 	if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
1682 	    sizeof (tabptr->zone_attr_value))) != Z_OK)
1683 		return (err);
1684 
1685 	return (Z_OK);
1686 }
1687 
1688 static int
1689 zonecfg_add_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
1690 {
1691 	xmlNodePtr newnode, cur = handle->zone_dh_cur;
1692 	int err;
1693 
1694 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ATTR, NULL);
1695 	err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_attr_name);
1696 	if (err != Z_OK)
1697 		return (err);
1698 	err = newprop(newnode, DTD_ATTR_TYPE, tabptr->zone_attr_type);
1699 	if (err != Z_OK)
1700 		return (err);
1701 	err = newprop(newnode, DTD_ATTR_VALUE, tabptr->zone_attr_value);
1702 	if (err != Z_OK)
1703 		return (err);
1704 	return (Z_OK);
1705 }
1706 
1707 int
1708 zonecfg_add_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
1709 {
1710 	int err;
1711 
1712 	if (tabptr == NULL)
1713 		return (Z_INVAL);
1714 
1715 	if ((err = operation_prep(handle)) != Z_OK)
1716 		return (err);
1717 
1718 	if ((err = zonecfg_add_attr_core(handle, tabptr)) != Z_OK)
1719 		return (err);
1720 
1721 	return (Z_OK);
1722 }
1723 
1724 static int
1725 zonecfg_delete_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
1726 {
1727 	xmlNodePtr cur = handle->zone_dh_cur;
1728 	int name_match, type_match, value_match;
1729 
1730 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1731 		if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
1732 			continue;
1733 
1734 		name_match = match_prop(cur, DTD_ATTR_NAME,
1735 		    tabptr->zone_attr_name);
1736 		type_match = match_prop(cur, DTD_ATTR_TYPE,
1737 		    tabptr->zone_attr_type);
1738 		value_match = match_prop(cur, DTD_ATTR_VALUE,
1739 		    tabptr->zone_attr_value);
1740 
1741 		if (name_match && type_match && value_match) {
1742 			xmlUnlinkNode(cur);
1743 			xmlFreeNode(cur);
1744 			return (Z_OK);
1745 		}
1746 	}
1747 	return (Z_NO_RESOURCE_ID);
1748 }
1749 
1750 int
1751 zonecfg_delete_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
1752 {
1753 	int err;
1754 
1755 	if (tabptr == NULL)
1756 		return (Z_INVAL);
1757 
1758 	if ((err = operation_prep(handle)) != Z_OK)
1759 		return (err);
1760 
1761 	if ((err = zonecfg_delete_attr_core(handle, tabptr)) != Z_OK)
1762 		return (err);
1763 
1764 	return (Z_OK);
1765 }
1766 
1767 int
1768 zonecfg_modify_attr(
1769 	zone_dochandle_t handle,
1770 	struct zone_attrtab *oldtabptr,
1771 	struct zone_attrtab *newtabptr)
1772 {
1773 	int err;
1774 
1775 	if (oldtabptr == NULL || newtabptr == NULL)
1776 		return (Z_INVAL);
1777 
1778 	if ((err = operation_prep(handle)) != Z_OK)
1779 		return (err);
1780 
1781 	if ((err = zonecfg_delete_attr_core(handle, oldtabptr)) != Z_OK)
1782 		return (err);
1783 
1784 	if ((err = zonecfg_add_attr_core(handle, newtabptr)) != Z_OK)
1785 		return (err);
1786 
1787 	return (Z_OK);
1788 }
1789 
1790 int
1791 zonecfg_get_attr_boolean(const struct zone_attrtab *attr, boolean_t *value)
1792 {
1793 	if (attr == NULL)
1794 		return (Z_INVAL);
1795 
1796 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_BOOLEAN) != 0)
1797 		return (Z_INVAL);
1798 
1799 	if (strcmp(attr->zone_attr_value, DTD_ENTITY_TRUE) == 0) {
1800 		*value = B_TRUE;
1801 		return (Z_OK);
1802 	}
1803 	if (strcmp(attr->zone_attr_value, DTD_ENTITY_FALSE) == 0) {
1804 		*value = B_FALSE;
1805 		return (Z_OK);
1806 	}
1807 	return (Z_INVAL);
1808 }
1809 
1810 int
1811 zonecfg_get_attr_int(const struct zone_attrtab *attr, int64_t *value)
1812 {
1813 	long long result;
1814 	char *endptr;
1815 
1816 	if (attr == NULL)
1817 		return (Z_INVAL);
1818 
1819 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_INT) != 0)
1820 		return (Z_INVAL);
1821 
1822 	errno = 0;
1823 	result = strtoll(attr->zone_attr_value, &endptr, 10);
1824 	if (errno != 0 || *endptr != '\0')
1825 		return (Z_INVAL);
1826 	*value = result;
1827 	return (Z_OK);
1828 }
1829 
1830 int
1831 zonecfg_get_attr_string(const struct zone_attrtab *attr, char *value,
1832     size_t val_sz)
1833 {
1834 	if (attr == NULL)
1835 		return (Z_INVAL);
1836 
1837 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_STRING) != 0)
1838 		return (Z_INVAL);
1839 
1840 	if (strlcpy(value, attr->zone_attr_value, val_sz) >= val_sz)
1841 		return (Z_TOO_BIG);
1842 	return (Z_OK);
1843 }
1844 
1845 int
1846 zonecfg_get_attr_uint(const struct zone_attrtab *attr, uint64_t *value)
1847 {
1848 	unsigned long long result;
1849 	long long neg_result;
1850 	char *endptr;
1851 
1852 	if (attr == NULL)
1853 		return (Z_INVAL);
1854 
1855 	if (strcmp(attr->zone_attr_type, DTD_ENTITY_UINT) != 0)
1856 		return (Z_INVAL);
1857 
1858 	errno = 0;
1859 	result = strtoull(attr->zone_attr_value, &endptr, 10);
1860 	if (errno != 0 || *endptr != '\0')
1861 		return (Z_INVAL);
1862 	errno = 0;
1863 	neg_result = strtoll(attr->zone_attr_value, &endptr, 10);
1864 	/*
1865 	 * Incredibly, strtoull("<negative number>", ...) will not fail but
1866 	 * return whatever (negative) number cast as a u_longlong_t, so we
1867 	 * need to look for this here.
1868 	 */
1869 	if (errno == 0 && neg_result < 0)
1870 		return (Z_INVAL);
1871 	*value = result;
1872 	return (Z_OK);
1873 }
1874 
1875 int
1876 zonecfg_lookup_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
1877 {
1878 	xmlNodePtr cur, val;
1879 	char savedname[MAXNAMELEN];
1880 	struct zone_rctlvaltab *valptr;
1881 	int err;
1882 
1883 	if (tabptr->zone_rctl_name == NULL ||
1884 	    strlen(tabptr->zone_rctl_name) == 0)
1885 		return (Z_INVAL);
1886 
1887 	if ((err = operation_prep(handle)) != Z_OK)
1888 		return (err);
1889 
1890 	cur = handle->zone_dh_cur;
1891 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1892 		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL))
1893 			continue;
1894 		if ((fetchprop(cur, DTD_ATTR_NAME, savedname,
1895 		    sizeof (savedname)) == Z_OK) &&
1896 		    (strcmp(savedname, tabptr->zone_rctl_name) == 0)) {
1897 			tabptr->zone_rctl_valptr = NULL;
1898 			for (val = cur->xmlChildrenNode; val != NULL;
1899 			    val = val->next) {
1900 				valptr = (struct zone_rctlvaltab *)malloc(
1901 				    sizeof (struct zone_rctlvaltab));
1902 				if (valptr == NULL)
1903 					return (Z_NOMEM);
1904 				if ((fetchprop(val, DTD_ATTR_PRIV,
1905 				    valptr->zone_rctlval_priv,
1906 				    sizeof (valptr->zone_rctlval_priv)) !=
1907 				    Z_OK))
1908 					break;
1909 				if ((fetchprop(val, DTD_ATTR_LIMIT,
1910 				    valptr->zone_rctlval_limit,
1911 				    sizeof (valptr->zone_rctlval_limit)) !=
1912 				    Z_OK))
1913 					break;
1914 				if ((fetchprop(val, DTD_ATTR_ACTION,
1915 				    valptr->zone_rctlval_action,
1916 				    sizeof (valptr->zone_rctlval_action)) !=
1917 				    Z_OK))
1918 					break;
1919 				if (zonecfg_add_rctl_value(tabptr, valptr) !=
1920 				    Z_OK)
1921 					break;
1922 			}
1923 			return (Z_OK);
1924 		}
1925 	}
1926 	return (Z_NO_RESOURCE_ID);
1927 }
1928 
1929 static int
1930 zonecfg_add_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr)
1931 {
1932 	xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode;
1933 	struct zone_rctlvaltab *valptr;
1934 	int err;
1935 
1936 	newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_RCTL, NULL);
1937 	err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_rctl_name);
1938 	if (err != Z_OK)
1939 		return (err);
1940 	for (valptr = tabptr->zone_rctl_valptr; valptr != NULL;
1941 	    valptr = valptr->zone_rctlval_next) {
1942 		valnode = xmlNewTextChild(newnode, NULL,
1943 		    DTD_ELEM_RCTLVALUE, NULL);
1944 		err = newprop(valnode, DTD_ATTR_PRIV,
1945 		    valptr->zone_rctlval_priv);
1946 		if (err != Z_OK)
1947 			return (err);
1948 		err = newprop(valnode, DTD_ATTR_LIMIT,
1949 		    valptr->zone_rctlval_limit);
1950 		if (err != Z_OK)
1951 			return (err);
1952 		err = newprop(valnode, DTD_ATTR_ACTION,
1953 		    valptr->zone_rctlval_action);
1954 		if (err != Z_OK)
1955 			return (err);
1956 	}
1957 	return (Z_OK);
1958 }
1959 
1960 int
1961 zonecfg_add_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
1962 {
1963 	int err;
1964 
1965 	if (tabptr == NULL || tabptr->zone_rctl_name == NULL)
1966 		return (Z_INVAL);
1967 
1968 	if ((err = operation_prep(handle)) != Z_OK)
1969 		return (err);
1970 
1971 	if ((err = zonecfg_add_rctl_core(handle, tabptr)) != Z_OK)
1972 		return (err);
1973 
1974 	return (Z_OK);
1975 }
1976 
1977 static int
1978 zonecfg_delete_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr)
1979 {
1980 	xmlNodePtr cur = handle->zone_dh_cur;
1981 	xmlChar *savedname;
1982 	int name_result;
1983 
1984 	for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1985 		if (xmlStrcmp(cur->name, DTD_ELEM_RCTL))
1986 			continue;
1987 
1988 		savedname = xmlGetProp(cur, DTD_ATTR_NAME);
1989 		if (savedname == NULL)	/* shouldn't happen */
1990 			continue;
1991 		name_result = xmlStrcmp(savedname,
1992 		    (const xmlChar *) tabptr->zone_rctl_name);
1993 		xmlFree(savedname);
1994 
1995 		if (name_result == 0) {
1996 			xmlUnlinkNode(cur);
1997 			xmlFreeNode(cur);
1998 			return (Z_OK);
1999 		}
2000 	}
2001 	return (Z_NO_RESOURCE_ID);
2002 }
2003 
2004 int
2005 zonecfg_delete_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
2006 {
2007 	int err;
2008 
2009 	if (tabptr == NULL || tabptr->zone_rctl_name == NULL)
2010 		return (Z_INVAL);
2011 
2012 	if ((err = operation_prep(handle)) != Z_OK)
2013 		return (err);
2014 
2015 	if ((err = zonecfg_delete_rctl_core(handle, tabptr)) != Z_OK)
2016 		return (err);
2017 
2018 	return (Z_OK);
2019 }
2020 
2021 int
2022 zonecfg_modify_rctl(
2023 	zone_dochandle_t handle,
2024 	struct zone_rctltab *oldtabptr,
2025 	struct zone_rctltab *newtabptr)
2026 {
2027 	int err;
2028 
2029 	if (oldtabptr == NULL || oldtabptr->zone_rctl_name == NULL ||
2030 	    newtabptr == NULL || newtabptr->zone_rctl_name == NULL)
2031 		return (Z_INVAL);
2032 
2033 	if ((err = operation_prep(handle)) != Z_OK)
2034 		return (err);
2035 
2036 	if ((err = zonecfg_delete_rctl_core(handle, oldtabptr)) != Z_OK)
2037 		return (err);
2038 
2039 	if ((err = zonecfg_add_rctl_core(handle, newtabptr)) != Z_OK)
2040 		return (err);
2041 
2042 	return (Z_OK);
2043 }
2044 
2045 int
2046 zonecfg_add_rctl_value(
2047 	struct zone_rctltab *tabptr,
2048 	struct zone_rctlvaltab *valtabptr)
2049 {
2050 	struct zone_rctlvaltab *last, *old, *new;
2051 	rctlblk_t *rctlblk = alloca(rctlblk_size());
2052 
2053 	last = tabptr->zone_rctl_valptr;
2054 	for (old = last; old != NULL; old = old->zone_rctlval_next)
2055 		last = old;	/* walk to the end of the list */
2056 	new = valtabptr;	/* alloc'd by caller */
2057 	new->zone_rctlval_next = NULL;
2058 	if (zonecfg_construct_rctlblk(valtabptr, rctlblk) != Z_OK)
2059 		return (Z_INVAL);
2060 	if (!zonecfg_valid_rctlblk(rctlblk))
2061 		return (Z_INVAL);
2062 	if (last == NULL)
2063 		tabptr->zone_rctl_valptr = new;
2064 	else
2065 		last->zone_rctlval_next = new;
2066 	return (Z_OK);
2067 }
2068 
2069 int
2070 zonecfg_remove_rctl_value(
2071 	struct zone_rctltab *tabptr,
2072 	struct zone_rctlvaltab *valtabptr)
2073 {
2074 	struct zone_rctlvaltab *last, *this, *next;
2075 
2076 	last = tabptr->zone_rctl_valptr;
2077 	for (this = last; this != NULL; this = this->zone_rctlval_next) {
2078 		if (strcmp(this->zone_rctlval_priv,
2079 		    valtabptr->zone_rctlval_priv) == 0 &&
2080 		    strcmp(this->zone_rctlval_limit,
2081 		    valtabptr->zone_rctlval_limit) == 0 &&
2082 		    strcmp(this->zone_rctlval_action,
2083 		    valtabptr->zone_rctlval_action) == 0) {
2084 			next = this->zone_rctlval_next;
2085 			if (this == tabptr->zone_rctl_valptr)
2086 				tabptr->zone_rctl_valptr = next;
2087 			else
2088 				last->zone_rctlval_next = next;
2089 			free(this);
2090 			return (Z_OK);
2091 		} else
2092 			last = this;
2093 	}
2094 	return (Z_NO_PROPERTY_ID);
2095 }
2096 
2097 char *
2098 zonecfg_strerror(int errnum)
2099 {
2100 	switch (errnum) {
2101 	case Z_OK:
2102 		return (dgettext(TEXT_DOMAIN, "OK"));
2103 	case Z_EMPTY_DOCUMENT:
2104 		return (dgettext(TEXT_DOMAIN, "Empty document"));
2105 	case Z_WRONG_DOC_TYPE:
2106 		return (dgettext(TEXT_DOMAIN, "Wrong document type"));
2107 	case Z_BAD_PROPERTY:
2108 		return (dgettext(TEXT_DOMAIN, "Bad document property"));
2109 	case Z_TEMP_FILE:
2110 		return (dgettext(TEXT_DOMAIN,
2111 		    "Problem creating temporary file"));
2112 	case Z_SAVING_FILE:
2113 		return (dgettext(TEXT_DOMAIN, "Problem saving file"));
2114 	case Z_NO_ENTRY:
2115 		return (dgettext(TEXT_DOMAIN, "No such entry"));
2116 	case Z_BOGUS_ZONE_NAME:
2117 		return (dgettext(TEXT_DOMAIN, "Bogus zone name"));
2118 	case Z_REQD_RESOURCE_MISSING:
2119 		return (dgettext(TEXT_DOMAIN, "Required resource missing"));
2120 	case Z_REQD_PROPERTY_MISSING:
2121 		return (dgettext(TEXT_DOMAIN, "Required property missing"));
2122 	case Z_BAD_HANDLE:
2123 		return (dgettext(TEXT_DOMAIN, "Bad handle"));
2124 	case Z_NOMEM:
2125 		return (dgettext(TEXT_DOMAIN, "Out of memory"));
2126 	case Z_INVAL:
2127 		return (dgettext(TEXT_DOMAIN, "Invalid argument"));
2128 	case Z_ACCES:
2129 		return (dgettext(TEXT_DOMAIN, "Permission denied"));
2130 	case Z_TOO_BIG:
2131 		return (dgettext(TEXT_DOMAIN, "Argument list too long"));
2132 	case Z_MISC_FS:
2133 		return (dgettext(TEXT_DOMAIN,
2134 		    "Miscellaneous file system error"));
2135 	case Z_NO_ZONE:
2136 		return (dgettext(TEXT_DOMAIN, "No such zone configured"));
2137 	case Z_NO_RESOURCE_TYPE:
2138 		return (dgettext(TEXT_DOMAIN, "No such resource type"));
2139 	case Z_NO_RESOURCE_ID:
2140 		return (dgettext(TEXT_DOMAIN, "No such resource with that id"));
2141 	case Z_NO_PROPERTY_TYPE:
2142 		return (dgettext(TEXT_DOMAIN, "No such property type"));
2143 	case Z_NO_PROPERTY_ID:
2144 		return (dgettext(TEXT_DOMAIN, "No such property with that id"));
2145 	case Z_RESOURCE_EXISTS:
2146 		return (dgettext(TEXT_DOMAIN,
2147 		    "Resource already exists with that id"));
2148 	case Z_INVALID_DOCUMENT:
2149 		return (dgettext(TEXT_DOMAIN, "Invalid document"));
2150 	case Z_ID_IN_USE:
2151 		return (dgettext(TEXT_DOMAIN, "Zone ID in use"));
2152 	case Z_NO_SUCH_ID:
2153 		return (dgettext(TEXT_DOMAIN, "No such zone ID"));
2154 	case Z_UPDATING_INDEX:
2155 		return (dgettext(TEXT_DOMAIN, "Problem updating index file"));
2156 	case Z_LOCKING_FILE:
2157 		return (dgettext(TEXT_DOMAIN, "Locking index file"));
2158 	case Z_UNLOCKING_FILE:
2159 		return (dgettext(TEXT_DOMAIN, "Unlocking index file"));
2160 	case Z_INSUFFICIENT_SPEC:
2161 		return (dgettext(TEXT_DOMAIN, "Insufficient specification"));
2162 	case Z_RESOLVED_PATH:
2163 		return (dgettext(TEXT_DOMAIN, "Resolved path mismatch"));
2164 	case Z_IPV6_ADDR_PREFIX_LEN:
2165 		return (dgettext(TEXT_DOMAIN,
2166 		    "IPv6 address missing required prefix length"));
2167 	case Z_BOGUS_ADDRESS:
2168 		return (dgettext(TEXT_DOMAIN,
2169 		    "Neither an IPv4 nor an IPv6 address nor a host name"));
2170 	default:
2171 		return (dgettext(TEXT_DOMAIN, "Unknown error"));
2172 	}
2173 }
2174 
2175 /*
2176  * Note that the zonecfg_setXent() and zonecfg_endXent() calls are all the
2177  * same, as they just turn around and call zonecfg_setent() / zonecfg_endent().
2178  */
2179 
2180 static int
2181 zonecfg_setent(zone_dochandle_t handle)
2182 {
2183 	xmlNodePtr cur;
2184 	int err;
2185 
2186 	if (handle == NULL)
2187 		return (Z_INVAL);
2188 
2189 	if ((err = operation_prep(handle)) != Z_OK) {
2190 		handle->zone_dh_cur = NULL;
2191 		return (err);
2192 	}
2193 	cur = handle->zone_dh_cur;
2194 	cur = cur->xmlChildrenNode;
2195 	handle->zone_dh_cur = cur;
2196 	return (Z_OK);
2197 }
2198 
2199 static int
2200 zonecfg_endent(zone_dochandle_t handle)
2201 {
2202 	if (handle == NULL)
2203 		return (Z_INVAL);
2204 
2205 	handle->zone_dh_cur = handle->zone_dh_top;
2206 	return (Z_OK);
2207 }
2208 
2209 int
2210 zonecfg_setfsent(zone_dochandle_t handle)
2211 {
2212 	return (zonecfg_setent(handle));
2213 }
2214 
2215 int
2216 zonecfg_getfsent(zone_dochandle_t handle, struct zone_fstab *tabptr)
2217 {
2218 	xmlNodePtr cur, options;
2219 	char options_str[MAX_MNTOPT_STR];
2220 	int err;
2221 
2222 	if (handle == NULL)
2223 		return (Z_INVAL);
2224 
2225 	if ((cur = handle->zone_dh_cur) == NULL)
2226 		return (Z_NO_ENTRY);
2227 
2228 	for (; cur != NULL; cur = cur->next)
2229 		if (!xmlStrcmp(cur->name, DTD_ELEM_FS))
2230 			break;
2231 	if (cur == NULL) {
2232 		handle->zone_dh_cur = handle->zone_dh_top;
2233 		return (Z_NO_ENTRY);
2234 	}
2235 
2236 	if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
2237 	    sizeof (tabptr->zone_fs_special))) != Z_OK) {
2238 		handle->zone_dh_cur = handle->zone_dh_top;
2239 		return (err);
2240 	}
2241 
2242 	if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
2243 	    sizeof (tabptr->zone_fs_raw))) != Z_OK) {
2244 		handle->zone_dh_cur = handle->zone_dh_top;
2245 		return (err);
2246 	}
2247 
2248 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
2249 	    sizeof (tabptr->zone_fs_dir))) != Z_OK) {
2250 		handle->zone_dh_cur = handle->zone_dh_top;
2251 		return (err);
2252 	}
2253 
2254 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
2255 	    sizeof (tabptr->zone_fs_type))) != Z_OK) {
2256 		handle->zone_dh_cur = handle->zone_dh_top;
2257 		return (err);
2258 	}
2259 
2260 	/* OK for options to be NULL */
2261 	tabptr->zone_fs_options = NULL;
2262 	for (options = cur->xmlChildrenNode; options != NULL;
2263 	    options = options->next) {
2264 		if (fetchprop(options, DTD_ATTR_NAME, options_str,
2265 		    sizeof (options_str)) != Z_OK)
2266 			break;
2267 		if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
2268 			break;
2269 	}
2270 
2271 	handle->zone_dh_cur = cur->next;
2272 	return (Z_OK);
2273 }
2274 
2275 int
2276 zonecfg_endfsent(zone_dochandle_t handle)
2277 {
2278 	return (zonecfg_endent(handle));
2279 }
2280 
2281 int
2282 zonecfg_setipdent(zone_dochandle_t handle)
2283 {
2284 	return (zonecfg_setent(handle));
2285 }
2286 
2287 int
2288 zonecfg_getipdent(zone_dochandle_t handle, struct zone_fstab *tabptr)
2289 {
2290 	xmlNodePtr cur;
2291 	int err;
2292 
2293 	if (handle == NULL)
2294 		return (Z_INVAL);
2295 
2296 	if ((cur = handle->zone_dh_cur) == NULL)
2297 		return (Z_NO_ENTRY);
2298 
2299 	for (; cur != NULL; cur = cur->next)
2300 		if (!xmlStrcmp(cur->name, DTD_ELEM_IPD))
2301 			break;
2302 	if (cur == NULL) {
2303 		handle->zone_dh_cur = handle->zone_dh_top;
2304 		return (Z_NO_ENTRY);
2305 	}
2306 
2307 	if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
2308 	    sizeof (tabptr->zone_fs_dir))) != Z_OK) {
2309 		handle->zone_dh_cur = handle->zone_dh_top;
2310 		return (err);
2311 	}
2312 
2313 	handle->zone_dh_cur = cur->next;
2314 	return (Z_OK);
2315 }
2316 
2317 int
2318 zonecfg_endipdent(zone_dochandle_t handle)
2319 {
2320 	return (zonecfg_endent(handle));
2321 }
2322 
2323 int
2324 zonecfg_setnwifent(zone_dochandle_t handle)
2325 {
2326 	return (zonecfg_setent(handle));
2327 }
2328 
2329 int
2330 zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2331 {
2332 	xmlNodePtr cur;
2333 	int err;
2334 
2335 	if (handle == NULL)
2336 		return (Z_INVAL);
2337 
2338 	if ((cur = handle->zone_dh_cur) == NULL)
2339 		return (Z_NO_ENTRY);
2340 
2341 	for (; cur != NULL; cur = cur->next)
2342 		if (!xmlStrcmp(cur->name, DTD_ELEM_NET))
2343 			break;
2344 	if (cur == NULL) {
2345 		handle->zone_dh_cur = handle->zone_dh_top;
2346 		return (Z_NO_ENTRY);
2347 	}
2348 
2349 	if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
2350 	    sizeof (tabptr->zone_nwif_address))) != Z_OK) {
2351 		handle->zone_dh_cur = handle->zone_dh_top;
2352 		return (err);
2353 	}
2354 
2355 	if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
2356 	    sizeof (tabptr->zone_nwif_physical))) != Z_OK) {
2357 		handle->zone_dh_cur = handle->zone_dh_top;
2358 		return (err);
2359 	}
2360 
2361 	handle->zone_dh_cur = cur->next;
2362 	return (Z_OK);
2363 }
2364 
2365 int
2366 zonecfg_endnwifent(zone_dochandle_t handle)
2367 {
2368 	return (zonecfg_endent(handle));
2369 }
2370 
2371 int
2372 zonecfg_setdevent(zone_dochandle_t handle)
2373 {
2374 	return (zonecfg_setent(handle));
2375 }
2376 
2377 int
2378 zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr)
2379 {
2380 	xmlNodePtr cur;
2381 	int err;
2382 
2383 	if (handle == NULL)
2384 		return (Z_INVAL);
2385 
2386 	if ((cur = handle->zone_dh_cur) == NULL)
2387 		return (Z_NO_ENTRY);
2388 
2389 	for (; cur != NULL; cur = cur->next)
2390 		if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2391 			break;
2392 	if (cur == NULL) {
2393 		handle->zone_dh_cur = handle->zone_dh_top;
2394 		return (Z_NO_ENTRY);
2395 	}
2396 
2397 	if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
2398 	    sizeof (tabptr->zone_dev_match))) != Z_OK) {
2399 		handle->zone_dh_cur = handle->zone_dh_top;
2400 		return (err);
2401 	}
2402 
2403 	handle->zone_dh_cur = cur->next;
2404 	return (Z_OK);
2405 }
2406 
2407 int
2408 zonecfg_enddevent(zone_dochandle_t handle)
2409 {
2410 	return (zonecfg_endent(handle));
2411 }
2412 
2413 int
2414 zonecfg_setrctlent(zone_dochandle_t handle)
2415 {
2416 	return (zonecfg_setent(handle));
2417 }
2418 
2419 int
2420 zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr)
2421 {
2422 	xmlNodePtr cur, val;
2423 	struct zone_rctlvaltab *valptr;
2424 	int err;
2425 
2426 	if (handle == NULL)
2427 		return (Z_INVAL);
2428 
2429 	if ((cur = handle->zone_dh_cur) == NULL)
2430 		return (Z_NO_ENTRY);
2431 
2432 	for (; cur != NULL; cur = cur->next)
2433 		if (!xmlStrcmp(cur->name, DTD_ELEM_RCTL))
2434 			break;
2435 	if (cur == NULL) {
2436 		handle->zone_dh_cur = handle->zone_dh_top;
2437 		return (Z_NO_ENTRY);
2438 	}
2439 
2440 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_rctl_name,
2441 	    sizeof (tabptr->zone_rctl_name))) != Z_OK) {
2442 		handle->zone_dh_cur = handle->zone_dh_top;
2443 		return (err);
2444 	}
2445 
2446 	tabptr->zone_rctl_valptr = NULL;
2447 	for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
2448 		valptr = (struct zone_rctlvaltab *)malloc(
2449 		    sizeof (struct zone_rctlvaltab));
2450 		if (valptr == NULL)
2451 			return (Z_NOMEM);
2452 		if (fetchprop(val, DTD_ATTR_PRIV, valptr->zone_rctlval_priv,
2453 		    sizeof (valptr->zone_rctlval_priv)) != Z_OK)
2454 			break;
2455 		if (fetchprop(val, DTD_ATTR_LIMIT, valptr->zone_rctlval_limit,
2456 		    sizeof (valptr->zone_rctlval_limit)) != Z_OK)
2457 			break;
2458 		if (fetchprop(val, DTD_ATTR_ACTION, valptr->zone_rctlval_action,
2459 		    sizeof (valptr->zone_rctlval_action)) != Z_OK)
2460 			break;
2461 		if (zonecfg_add_rctl_value(tabptr, valptr) != Z_OK)
2462 			break;
2463 	}
2464 
2465 	handle->zone_dh_cur = cur->next;
2466 	return (Z_OK);
2467 }
2468 
2469 int
2470 zonecfg_endrctlent(zone_dochandle_t handle)
2471 {
2472 	return (zonecfg_endent(handle));
2473 }
2474 
2475 int
2476 zonecfg_setattrent(zone_dochandle_t handle)
2477 {
2478 	return (zonecfg_setent(handle));
2479 }
2480 
2481 int
2482 zonecfg_getattrent(zone_dochandle_t handle, struct zone_attrtab *tabptr)
2483 {
2484 	xmlNodePtr cur;
2485 	int err;
2486 
2487 	if (handle == NULL)
2488 		return (Z_INVAL);
2489 
2490 	if ((cur = handle->zone_dh_cur) == NULL)
2491 		return (Z_NO_ENTRY);
2492 
2493 	for (; cur != NULL; cur = cur->next)
2494 		if (!xmlStrcmp(cur->name, DTD_ELEM_ATTR))
2495 			break;
2496 	if (cur == NULL) {
2497 		handle->zone_dh_cur = handle->zone_dh_top;
2498 		return (Z_NO_ENTRY);
2499 	}
2500 
2501 	if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
2502 	    sizeof (tabptr->zone_attr_name))) != Z_OK) {
2503 		handle->zone_dh_cur = handle->zone_dh_top;
2504 		return (err);
2505 	}
2506 
2507 	if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
2508 	    sizeof (tabptr->zone_attr_type))) != Z_OK) {
2509 		handle->zone_dh_cur = handle->zone_dh_top;
2510 		return (err);
2511 	}
2512 
2513 	if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
2514 	    sizeof (tabptr->zone_attr_value))) != Z_OK) {
2515 		handle->zone_dh_cur = handle->zone_dh_top;
2516 		return (err);
2517 	}
2518 
2519 	handle->zone_dh_cur = cur->next;
2520 	return (Z_OK);
2521 }
2522 
2523 int
2524 zonecfg_endattrent(zone_dochandle_t handle)
2525 {
2526 	return (zonecfg_endent(handle));
2527 }
2528 
2529 /* This will ultimately be configurable. */
2530 static const char *priv_list[] = {
2531 	PRIV_FILE_CHOWN,
2532 	PRIV_FILE_CHOWN_SELF,
2533 	PRIV_FILE_DAC_EXECUTE,
2534 	PRIV_FILE_DAC_READ,
2535 	PRIV_FILE_DAC_SEARCH,
2536 	PRIV_FILE_DAC_WRITE,
2537 	PRIV_FILE_OWNER,
2538 	PRIV_FILE_SETID,
2539 	PRIV_IPC_DAC_READ,
2540 	PRIV_IPC_DAC_WRITE,
2541 	PRIV_IPC_OWNER,
2542 	PRIV_NET_ICMPACCESS,
2543 	PRIV_NET_PRIVADDR,
2544 	PRIV_PROC_CHROOT,
2545 	PRIV_SYS_AUDIT,
2546 	PRIV_PROC_AUDIT,
2547 	PRIV_PROC_OWNER,
2548 	PRIV_PROC_SETID,
2549 	PRIV_PROC_TASKID,
2550 	PRIV_SYS_ACCT,
2551 	PRIV_SYS_ADMIN,
2552 	PRIV_SYS_MOUNT,
2553 	PRIV_SYS_NFS,
2554 	PRIV_SYS_RESOURCE,
2555 	PRIV_CONTRACT_EVENT,
2556 	PRIV_CONTRACT_OBSERVER,
2557 	NULL
2558 };
2559 
2560 int
2561 zonecfg_get_privset(priv_set_t *privs)
2562 {
2563 	const char **strp;
2564 	priv_set_t *basic = priv_str_to_set("basic", ",", NULL);
2565 
2566 	if (basic == NULL)
2567 		return (Z_INVAL);
2568 
2569 	priv_union(basic, privs);
2570 	priv_freeset(basic);
2571 
2572 	for (strp = priv_list; *strp != NULL; strp++) {
2573 		if (priv_addset(privs, *strp) != 0) {
2574 			return (Z_INVAL);
2575 		}
2576 	}
2577 	return (Z_OK);
2578 }
2579 
2580 int
2581 zonecfg_add_index(char *zone, char *path)
2582 {
2583 	struct zoneent ze;
2584 
2585 	(void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name));
2586 	ze.zone_state = ZONE_STATE_CONFIGURED;
2587 	(void) strlcpy(ze.zone_path, path, sizeof (ze.zone_path));
2588 	return (putzoneent(&ze, PZE_ADD));
2589 }
2590 
2591 int
2592 zonecfg_delete_index(char *zone)
2593 {
2594 	struct zoneent ze;
2595 
2596 	(void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name));
2597 	return (putzoneent(&ze, PZE_REMOVE));
2598 }
2599 
2600 int
2601 zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz)
2602 {
2603 	zone_dochandle_t handle;
2604 	boolean_t found = B_FALSE;
2605 	struct zoneent *ze;
2606 	FILE *cookie;
2607 	int err;
2608 
2609 	if (zone_name == NULL)
2610 		return (Z_INVAL);
2611 
2612 	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) {
2613 		(void) strlcpy(zonepath, "/", rp_sz);
2614 		return (Z_OK);
2615 	}
2616 
2617 	/*
2618 	 * First check the index file.  Because older versions did not have
2619 	 * a copy of the zone path, allow for it to be zero length, in which
2620 	 * case we ignore this result and fall back to the XML files.
2621 	 */
2622 	(void) strlcpy(zonepath, "", rp_sz);
2623 	cookie = setzoneent();
2624 	while ((ze = getzoneent_private(cookie)) != NULL) {
2625 		if (strcmp(ze->zone_name, zone_name) == 0) {
2626 			found = B_TRUE;
2627 			if (strlen(ze->zone_path) > 0)
2628 				(void) strlcpy(zonepath, ze->zone_path, rp_sz);
2629 		}
2630 		free(ze);
2631 		if (found)
2632 			break;
2633 	}
2634 	endzoneent(cookie);
2635 	if (found && strlen(zonepath) > 0)
2636 		return (Z_OK);
2637 
2638 	/* Fall back to the XML files. */
2639 	if ((handle = zonecfg_init_handle()) == NULL)
2640 		return (Z_NOMEM);
2641 
2642 	/*
2643 	 * Check the snapshot first: if a zone is running, its zonepath
2644 	 * may have changed.
2645 	 */
2646 	if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
2647 		if ((err = zonecfg_get_handle(zone_name, handle)) != Z_OK)
2648 			return (err);
2649 	}
2650 	err = zonecfg_get_zonepath(handle, zonepath, rp_sz);
2651 	zonecfg_fini_handle(handle);
2652 	return (err);
2653 }
2654 
2655 int
2656 zone_get_rootpath(char *zone_name, char *rootpath, size_t rp_sz)
2657 {
2658 	int err;
2659 
2660 	/* This function makes sense for non-global zones only. */
2661 	if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
2662 		return (Z_BOGUS_ZONE_NAME);
2663 	if ((err = zone_get_zonepath(zone_name, rootpath, rp_sz)) != Z_OK)
2664 		return (err);
2665 	if (strlcat(rootpath, "/root", rp_sz) >= rp_sz)
2666 		return (Z_TOO_BIG);
2667 	return (Z_OK);
2668 }
2669 
2670 static zone_state_t
2671 kernel_state_to_user_state(zone_status_t kernel_state)
2672 {
2673 	assert(kernel_state <= ZONE_MAX_STATE);
2674 	switch (kernel_state) {
2675 		case ZONE_IS_UNINITIALIZED:
2676 		case ZONE_IS_READY:
2677 			return (ZONE_STATE_READY);
2678 		case ZONE_IS_BOOTING:
2679 		case ZONE_IS_RUNNING:
2680 			return (ZONE_STATE_RUNNING);
2681 		case ZONE_IS_SHUTTING_DOWN:
2682 		case ZONE_IS_EMPTY:
2683 			return (ZONE_STATE_SHUTTING_DOWN);
2684 		case ZONE_IS_DOWN:
2685 		case ZONE_IS_DYING:
2686 		case ZONE_IS_DEAD:
2687 		default:
2688 			return (ZONE_STATE_DOWN);
2689 	}
2690 	/* NOTREACHED */
2691 }
2692 
2693 int
2694 zone_get_state(char *zone_name, zone_state_t *state_num)
2695 {
2696 	zone_status_t status;
2697 	zoneid_t zone_id;
2698 	struct zoneent *ze;
2699 	boolean_t found = B_FALSE;
2700 	FILE *cookie;
2701 
2702 	if (zone_name == NULL)
2703 		return (Z_INVAL);
2704 
2705 	/* check to see if zone is running */
2706 	if ((zone_id = getzoneidbyname(zone_name)) != -1 &&
2707 	    zone_getattr(zone_id, ZONE_ATTR_STATUS, &status,
2708 	    sizeof (status)) >= 0) {
2709 		*state_num = kernel_state_to_user_state(status);
2710 		return (Z_OK);
2711 	}
2712 
2713 	cookie = setzoneent();
2714 	while ((ze = getzoneent_private(cookie)) != NULL) {
2715 		if (strcmp(ze->zone_name, zone_name) == 0) {
2716 			found = B_TRUE;
2717 			*state_num = ze->zone_state;
2718 		}
2719 		free(ze);
2720 		if (found)
2721 			break;
2722 	}
2723 	endzoneent(cookie);
2724 	return ((found) ? Z_OK : Z_NO_ZONE);
2725 }
2726 
2727 int
2728 zone_set_state(char *zone, zone_state_t state)
2729 {
2730 	struct zoneent ze;
2731 
2732 	if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED &&
2733 	    state != ZONE_STATE_INCOMPLETE)
2734 		return (Z_INVAL);
2735 
2736 	(void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name));
2737 	ze.zone_state = state;
2738 	(void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path));
2739 	return (putzoneent(&ze, PZE_MODIFY));
2740 }
2741 
2742 /*
2743  * Get id (if any) for specified zone.  There are four possible outcomes:
2744  * - If the string corresponds to the numeric id of an active (booted)
2745  *   zone, sets *zip to the zone id and returns 0.
2746  * - If the string corresponds to the name of an active (booted) zone,
2747  *   sets *zip to the zone id and returns 0.
2748  * - If the string is a name in the configuration but is not booted,
2749  *   sets *zip to ZONE_ID_UNDEFINED and returns 0.
2750  * - Otherwise, leaves *zip unchanged and returns -1.
2751  *
2752  * This function acts as an auxiliary filter on the function of the same
2753  * name in libc; the linker binds to this version if libzonecfg exists,
2754  * and the libc version if it doesn't.  Any changes to this version of
2755  * the function should probably be reflected in the libc version as well.
2756  */
2757 int
2758 zone_get_id(const char *str, zoneid_t *zip)
2759 {
2760 	zone_dochandle_t hdl;
2761 	zoneid_t zoneid;
2762 	char *cp;
2763 	int err;
2764 
2765 	/* first try looking for active zone by id */
2766 	errno = 0;
2767 	zoneid = (zoneid_t)strtol(str, &cp, 0);
2768 	if (errno == 0 && cp != str && *cp == '\0' &&
2769 	    getzonenamebyid(zoneid, NULL, 0) != -1) {
2770 		*zip = zoneid;
2771 		return (0);
2772 	}
2773 
2774 	/* then look for active zone by name */
2775 	if ((zoneid = getzoneidbyname(str)) != -1) {
2776 		*zip = zoneid;
2777 		return (0);
2778 	}
2779 
2780 	/* if in global zone, try looking up name in configuration database */
2781 	if (getzoneid() != GLOBAL_ZONEID ||
2782 	    (hdl = zonecfg_init_handle()) == NULL)
2783 		return (-1);
2784 
2785 	if (zonecfg_get_handle((char *)str, hdl) == Z_OK) {
2786 		/* zone exists but isn't active */
2787 		*zip = ZONE_ID_UNDEFINED;
2788 		err = 0;
2789 	} else {
2790 		err = -1;
2791 	}
2792 
2793 	zonecfg_fini_handle(hdl);
2794 	return (err);
2795 }
2796 
2797 char *
2798 zone_state_str(zone_state_t state_num)
2799 {
2800 	switch (state_num) {
2801 	case ZONE_STATE_CONFIGURED:
2802 		return (ZONE_STATE_STR_CONFIGURED);
2803 	case ZONE_STATE_INCOMPLETE:
2804 		return (ZONE_STATE_STR_INCOMPLETE);
2805 	case ZONE_STATE_INSTALLED:
2806 		return (ZONE_STATE_STR_INSTALLED);
2807 	case ZONE_STATE_READY:
2808 		return (ZONE_STATE_STR_READY);
2809 	case ZONE_STATE_RUNNING:
2810 		return (ZONE_STATE_STR_RUNNING);
2811 	case ZONE_STATE_SHUTTING_DOWN:
2812 		return (ZONE_STATE_STR_SHUTTING_DOWN);
2813 	case ZONE_STATE_DOWN:
2814 		return (ZONE_STATE_STR_DOWN);
2815 	default:
2816 		return ("unknown");
2817 	}
2818 }
2819 
2820 /*
2821  * File-system convenience functions.
2822  */
2823 boolean_t
2824 zonecfg_valid_fs_type(const char *type)
2825 {
2826 	/*
2827 	 * We already know which FS types don't work.
2828 	 */
2829 	if (strcmp(type, "proc") == 0 ||
2830 	    strcmp(type, "mntfs") == 0 ||
2831 	    strcmp(type, "autofs") == 0 ||
2832 	    strncmp(type, "nfs", sizeof ("nfs") - 1) == 0 ||
2833 	    strcmp(type, "cachefs") == 0)
2834 		return (B_FALSE);
2835 	/*
2836 	 * The caller may do more detailed verification to make sure other
2837 	 * aspects of this filesystem type make sense.
2838 	 */
2839 	return (B_TRUE);
2840 }
2841 
2842 /*
2843  * Generally uninteresting rctl convenience functions.
2844  */
2845 
2846 int
2847 zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval,
2848     rctlblk_t *rctlblk)
2849 {
2850 	unsigned long long ull;
2851 	char *endp;
2852 	rctl_priv_t priv;
2853 	rctl_qty_t limit;
2854 	uint_t action;
2855 
2856 	/* Get the privilege */
2857 	if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) {
2858 		priv = RCPRIV_BASIC;
2859 	} else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) {
2860 		priv = RCPRIV_PRIVILEGED;
2861 	} else {
2862 		/* Invalid privilege */
2863 		return (Z_INVAL);
2864 	}
2865 
2866 	/* deal with negative input; strtoull(3c) doesn't do what we want */
2867 	if (rctlval->zone_rctlval_limit[0] == '-')
2868 		return (Z_INVAL);
2869 	/* Get the limit */
2870 	errno = 0;
2871 	ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0);
2872 	if (errno != 0 || *endp != '\0') {
2873 		/* parse failed */
2874 		return (Z_INVAL);
2875 	}
2876 	limit = (rctl_qty_t)ull;
2877 
2878 	/* Get the action */
2879 	if (strcmp(rctlval->zone_rctlval_action, "none") == 0) {
2880 		action = RCTL_LOCAL_NOACTION;
2881 	} else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) {
2882 		action = RCTL_LOCAL_SIGNAL;
2883 	} else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) {
2884 		action = RCTL_LOCAL_DENY;
2885 	} else {
2886 		/* Invalid Action */
2887 		return (Z_INVAL);
2888 	}
2889 	rctlblk_set_local_action(rctlblk, action, 0);
2890 	rctlblk_set_privilege(rctlblk, priv);
2891 	rctlblk_set_value(rctlblk, limit);
2892 	return (Z_OK);
2893 }
2894 
2895 static int
2896 rctl_check(const char *rctlname, void *arg)
2897 {
2898 	const char *attrname = arg;
2899 
2900 	/*
2901 	 * Returning 1 here is our signal to zonecfg_is_rctl() that it is
2902 	 * indeed an rctl name recognized by the system.
2903 	 */
2904 	return (strcmp(rctlname, attrname) == 0 ? 1 : 0);
2905 }
2906 
2907 boolean_t
2908 zonecfg_is_rctl(const char *name)
2909 {
2910 	return (rctl_walk(rctl_check, (void *)name) == 1);
2911 }
2912 
2913 boolean_t
2914 zonecfg_valid_rctlname(const char *name)
2915 {
2916 	const char *c;
2917 
2918 	if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0)
2919 		return (B_FALSE);
2920 	if (strlen(name) == sizeof ("zone.") - 1)
2921 		return (B_FALSE);
2922 	for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) {
2923 		if (!isalpha(*c) && *c != '-')
2924 			return (B_FALSE);
2925 	}
2926 	return (B_TRUE);
2927 }
2928 
2929 boolean_t
2930 zonecfg_valid_rctlblk(const rctlblk_t *rctlblk)
2931 {
2932 	rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk);
2933 	uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
2934 
2935 	if (priv != RCPRIV_PRIVILEGED)
2936 		return (B_FALSE);
2937 	if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY)
2938 		return (B_FALSE);
2939 	return (B_TRUE);
2940 }
2941 
2942 boolean_t
2943 zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk)
2944 {
2945 	rctlblk_t *current, *next;
2946 	rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk);
2947 	uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
2948 	uint_t global_flags;
2949 
2950 	if (!zonecfg_valid_rctlblk(rctlblk))
2951 		return (B_FALSE);
2952 	if (!zonecfg_valid_rctlname(name))
2953 		return (B_FALSE);
2954 
2955 	current = alloca(rctlblk_size());
2956 	if (getrctl(name, NULL, current, RCTL_FIRST) != 0)
2957 		return (B_TRUE);	/* not an rctl on this system */
2958 	/*
2959 	 * Make sure the proposed value isn't greater than the current system
2960 	 * value.
2961 	 */
2962 	next = alloca(rctlblk_size());
2963 	while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) {
2964 		rctlblk_t *tmp;
2965 
2966 		if (getrctl(name, current, next, RCTL_NEXT) != 0)
2967 			return (B_FALSE);	/* shouldn't happen */
2968 		tmp = current;
2969 		current = next;
2970 		next = tmp;
2971 	}
2972 	if (limit > rctlblk_get_value(current))
2973 		return (B_FALSE);
2974 
2975 	/*
2976 	 * Make sure the proposed action is allowed.
2977 	 */
2978 	global_flags = rctlblk_get_global_flags(current);
2979 	if ((global_flags & RCTL_GLOBAL_DENY_NEVER) &&
2980 	    action == RCTL_LOCAL_DENY)
2981 		return (B_FALSE);
2982 	if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) &&
2983 	    action == RCTL_LOCAL_NOACTION)
2984 		return (B_FALSE);
2985 
2986 	return (B_TRUE);
2987 }
2988