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