xref: /illumos-gate/usr/src/lib/libbrand/common/libbrand.c (revision 9b9d39d2a32ff806d2431dbcc50968ef1e6d46b2)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright (c) 2015, Joyent, Inc.
25  * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
26  */
27 
28 #include <assert.h>
29 #include <dirent.h>
30 #include <errno.h>
31 #include <fnmatch.h>
32 #include <signal.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <strings.h>
36 #include <synch.h>
37 #include <sys/brand.h>
38 #include <sys/fcntl.h>
39 #include <sys/param.h>
40 #include <sys/stat.h>
41 #include <sys/systeminfo.h>
42 #include <sys/types.h>
43 #include <thread.h>
44 #include <zone.h>
45 
46 #include <libbrand_impl.h>
47 #include <libbrand.h>
48 
49 #define	DTD_ELEM_ATTACH		((const xmlChar *) "attach")
50 #define	DTD_ELEM_BOOT		((const xmlChar *) "boot")
51 #define	DTD_ELEM_BRAND		((const xmlChar *) "brand")
52 #define	DTD_ELEM_CLONE		((const xmlChar *) "clone")
53 #define	DTD_ELEM_COMMENT	((const xmlChar *) "comment")
54 #define	DTD_ELEM_DETACH		((const xmlChar *) "detach")
55 #define	DTD_ELEM_DEVICE		((const xmlChar *) "device")
56 #define	DTD_ELEM_GLOBAL_MOUNT	((const xmlChar *) "global_mount")
57 #define	DTD_ELEM_HALT		((const xmlChar *) "halt")
58 #define	DTD_ELEM_INITNAME	((const xmlChar *) "initname")
59 #define	DTD_ELEM_INSTALL	((const xmlChar *) "install")
60 #define	DTD_ELEM_INSTALLOPTS	((const xmlChar *) "installopts")
61 #define	DTD_ELEM_LOGIN_CMD	((const xmlChar *) "login_cmd")
62 #define	DTD_ELEM_FORCELOGIN_CMD	((const xmlChar *) "forcedlogin_cmd")
63 #define	DTD_ELEM_MODNAME	((const xmlChar *) "modname")
64 #define	DTD_ELEM_MOUNT		((const xmlChar *) "mount")
65 #define	DTD_ELEM_RESTARTINIT	((const xmlChar *) "restartinit")
66 #define	DTD_ELEM_RESTARTINIT0	((const xmlChar *) "restartinit0")
67 #define	DTD_ELEM_RESTARTINITREBOOT	((const xmlChar *) "restartinitreboot")
68 #define	DTD_ELEM_POSTATTACH	((const xmlChar *) "postattach")
69 #define	DTD_ELEM_POSTCLONE	((const xmlChar *) "postclone")
70 #define	DTD_ELEM_POSTINSTALL	((const xmlChar *) "postinstall")
71 #define	DTD_ELEM_POSTSNAP	((const xmlChar *) "postsnap")
72 #define	DTD_ELEM_POSTSTATECHG	((const xmlChar *) "poststatechange")
73 #define	DTD_ELEM_PREDETACH	((const xmlChar *) "predetach")
74 #define	DTD_ELEM_PRESNAP	((const xmlChar *) "presnap")
75 #define	DTD_ELEM_PRESTATECHG	((const xmlChar *) "prestatechange")
76 #define	DTD_ELEM_PREUNINSTALL	((const xmlChar *) "preuninstall")
77 #define	DTD_ELEM_PRIVILEGE	((const xmlChar *) "privilege")
78 #define	DTD_ELEM_QUERY		((const xmlChar *) "query")
79 #define	DTD_ELEM_SECFLAGS	((const xmlChar *) "security-flags")
80 #define	DTD_ELEM_SHUTDOWN	((const xmlChar *) "shutdown")
81 #define	DTD_ELEM_SYMLINK	((const xmlChar *) "symlink")
82 #define	DTD_ELEM_SYSBOOT	((const xmlChar *) "sysboot")
83 #define	DTD_ELEM_UNINSTALL	((const xmlChar *) "uninstall")
84 #define	DTD_ELEM_USER_CMD	((const xmlChar *) "user_cmd")
85 #define	DTD_ELEM_VALIDSNAP	((const xmlChar *) "validatesnap")
86 #define	DTD_ELEM_VERIFY_CFG	((const xmlChar *) "verify_cfg")
87 #define	DTD_ELEM_VERIFY_ADM	((const xmlChar *) "verify_adm")
88 
89 #define	DTD_ATTR_ALLOWEXCL	((const xmlChar *) "allow-exclusive-ip")
90 #define	DTD_ATTR_ARCH		((const xmlChar *) "arch")
91 #define	DTD_ATTR_DIRECTORY	((const xmlChar *) "directory")
92 #define	DTD_ATTR_IPTYPE		((const xmlChar *) "ip-type")
93 #define	DTD_ATTR_MATCH		((const xmlChar *) "match")
94 #define	DTD_ATTR_MODE		((const xmlChar *) "mode")
95 #define	DTD_ATTR_NAME		((const xmlChar *) "name")
96 #define	DTD_ATTR_OPT		((const xmlChar *) "opt")
97 #define	DTD_ATTR_PATH		((const xmlChar *) "path")
98 #define	DTD_ATTR_SET		((const xmlChar *) "set")
99 #define	DTD_ATTR_SOURCE		((const xmlChar *) "source")
100 #define	DTD_ATTR_SPECIAL	((const xmlChar *) "special")
101 #define	DTD_ATTR_TARGET		((const xmlChar *) "target")
102 #define	DTD_ATTR_TYPE		((const xmlChar *) "type")
103 
104 #define	DTD_ENTITY_TRUE		"true"
105 
106 static volatile boolean_t	libbrand_initialized = B_FALSE;
107 static char			i_curr_arch[MAXNAMELEN];
108 static char			i_curr_zone[ZONENAME_MAX];
109 
110 /*ARGSUSED*/
111 static void
112 brand_error_func(void *ctx, const char *msg, ...)
113 {
114 	/*
115 	 * Ignore error messages from libxml
116 	 */
117 }
118 
119 static boolean_t
120 libbrand_initialize()
121 {
122 	static mutex_t initialize_lock = DEFAULTMUTEX;
123 
124 	(void) mutex_lock(&initialize_lock);
125 
126 	if (libbrand_initialized) {
127 		(void) mutex_unlock(&initialize_lock);
128 		return (B_TRUE);
129 	}
130 
131 	if (sysinfo(SI_ARCHITECTURE, i_curr_arch, sizeof (i_curr_arch)) < 0) {
132 		(void) mutex_unlock(&initialize_lock);
133 		return (B_FALSE);
134 	}
135 
136 	if (getzonenamebyid(getzoneid(), i_curr_zone,
137 	    sizeof (i_curr_zone)) < 0) {
138 		(void) mutex_unlock(&initialize_lock);
139 		return (B_FALSE);
140 	}
141 
142 	xmlSetGenericErrorFunc(NULL, brand_error_func);
143 
144 	libbrand_initialized = B_TRUE;
145 	(void) mutex_unlock(&initialize_lock);
146 	return (B_TRUE);
147 }
148 
149 static const char *
150 get_curr_arch(void)
151 {
152 	if (!libbrand_initialize())
153 		return (NULL);
154 
155 	return (i_curr_arch);
156 }
157 
158 static const char *
159 get_curr_zone(void)
160 {
161 	if (!libbrand_initialize())
162 		return (NULL);
163 
164 	return (i_curr_zone);
165 }
166 
167 /*
168  * Internal function to open an XML file
169  *
170  * Returns the XML doc pointer, or NULL on failure.  It will validate the
171  * document, as well as removing any comments from the document structure.
172  */
173 static xmlDocPtr
174 open_xml_file(const char *file)
175 {
176 	xmlDocPtr doc;
177 	xmlValidCtxtPtr cvp;
178 	int valid;
179 
180 	if (!libbrand_initialize())
181 		return (NULL);
182 
183 	/*
184 	 * Parse the file
185 	 */
186 	doc = xmlReadFile(file, NULL, XML_PARSE_DTDLOAD |
187 	    XML_PARSE_DTDVALID | XML_PARSE_NOBLANKS | XML_PARSE_NOWARNING);
188 	if (doc == NULL)
189 		return (NULL);
190 
191 	/*
192 	 * Validate the file
193 	 */
194 	if ((cvp = xmlNewValidCtxt()) == NULL) {
195 		xmlFreeDoc(doc);
196 		return (NULL);
197 	}
198 	cvp->error = brand_error_func;
199 	cvp->warning = brand_error_func;
200 	valid = xmlValidateDocument(cvp, doc);
201 	xmlFreeValidCtxt(cvp);
202 	if (valid == 0) {
203 		xmlFreeDoc(doc);
204 		return (NULL);
205 	}
206 
207 	return (doc);
208 }
209 /*
210  * Open a handle to the named brand.
211  *
212  * Returns a handle to the named brand, which is used for all subsequent brand
213  * interaction, or NULL if unable to open or initialize the brand.
214  */
215 brand_handle_t
216 brand_open(const char *name)
217 {
218 	struct brand_handle *bhp;
219 	char path[MAXPATHLEN];
220 	xmlNodePtr node;
221 	xmlChar *property;
222 	struct stat statbuf;
223 
224 	/*
225 	 * Make sure brand name isn't too long
226 	 */
227 	if (strlen(name) >= MAXNAMELEN)
228 		return (NULL);
229 
230 	/*
231 	 * Check that the brand exists
232 	 */
233 	(void) snprintf(path, sizeof (path), "%s/%s", BRAND_DIR, name);
234 
235 	if (stat(path, &statbuf) != 0)
236 		return (NULL);
237 
238 	/*
239 	 * Allocate brand handle
240 	 */
241 	if ((bhp = malloc(sizeof (struct brand_handle))) == NULL)
242 		return (NULL);
243 	bzero(bhp, sizeof (struct brand_handle));
244 
245 	(void) strcpy(bhp->bh_name, name);
246 
247 	/*
248 	 * Open the configuration file
249 	 */
250 	(void) snprintf(path, sizeof (path), "%s/%s/%s", BRAND_DIR, name,
251 	    BRAND_CONFIG);
252 	if ((bhp->bh_config = open_xml_file(path)) == NULL) {
253 		brand_close((brand_handle_t)bhp);
254 		return (NULL);
255 	}
256 
257 	/*
258 	 * Verify that the name of the brand matches the directory in which it
259 	 * is installed.
260 	 */
261 	if ((node = xmlDocGetRootElement(bhp->bh_config)) == NULL) {
262 		brand_close((brand_handle_t)bhp);
263 		return (NULL);
264 	}
265 
266 	if (xmlStrcmp(node->name, DTD_ELEM_BRAND) != 0) {
267 		brand_close((brand_handle_t)bhp);
268 		return (NULL);
269 	}
270 
271 	if ((property = xmlGetProp(node, DTD_ATTR_NAME)) == NULL) {
272 		brand_close((brand_handle_t)bhp);
273 		return (NULL);
274 	}
275 
276 	if (strcmp((char *)property, name) != 0) {
277 		xmlFree(property);
278 		brand_close((brand_handle_t)bhp);
279 		return (NULL);
280 	}
281 	xmlFree(property);
282 
283 	/*
284 	 * Open handle to platform configuration file.
285 	 */
286 	(void) snprintf(path, sizeof (path), "%s/%s/%s", BRAND_DIR, name,
287 	    BRAND_PLATFORM);
288 	if ((bhp->bh_platform = open_xml_file(path)) == NULL) {
289 		brand_close((brand_handle_t)bhp);
290 		return (NULL);
291 	}
292 
293 	return ((brand_handle_t)bhp);
294 }
295 
296 /*
297  * Closes the given brand handle
298  */
299 void
300 brand_close(brand_handle_t bh)
301 {
302 	struct brand_handle *bhp = (struct brand_handle *)bh;
303 	if (bhp->bh_platform != NULL)
304 		xmlFreeDoc(bhp->bh_platform);
305 	if (bhp->bh_config != NULL)
306 		xmlFreeDoc(bhp->bh_config);
307 	free(bhp);
308 }
309 
310 static int
311 i_substitute_tokens(const char *sbuf, char *dbuf, int dbuf_size,
312     const char *zonename, const char *zonepath, const char *username,
313     const char *curr_zone)
314 {
315 	int dst, src;
316 
317 	/*
318 	 * Walk through the characters, substituting values as needed.
319 	 */
320 	dbuf[0] = '\0';
321 	dst = 0;
322 	for (src = 0; src < strlen((char *)sbuf) && dst < dbuf_size; src++) {
323 		if (sbuf[src] != '%') {
324 			dbuf[dst++] = sbuf[src];
325 			continue;
326 		}
327 
328 		switch (sbuf[++src]) {
329 		case '%':
330 			dst += strlcpy(dbuf + dst, "%", dbuf_size - dst);
331 			break;
332 		case 'R':
333 			if (zonepath == NULL)
334 				break;
335 			dst += strlcpy(dbuf + dst, zonepath, dbuf_size - dst);
336 			break;
337 		case 'u':
338 			if (username == NULL)
339 				break;
340 			dst += strlcpy(dbuf + dst, username, dbuf_size - dst);
341 			break;
342 		case 'Z':
343 			if (curr_zone == NULL)
344 				break;
345 			/* name of the zone we're running in */
346 			dst += strlcpy(dbuf + dst, curr_zone, dbuf_size - dst);
347 			break;
348 		case 'z':
349 			/* name of the zone we're operating on */
350 			if (zonename == NULL)
351 				break;
352 			dst += strlcpy(dbuf + dst, zonename, dbuf_size - dst);
353 			break;
354 		}
355 	}
356 
357 	if (dst >= dbuf_size)
358 		return (-1);
359 
360 	dbuf[dst] = '\0';
361 	return (0);
362 }
363 
364 /*
365  * Retrieve the given tag from the brand.
366  * Perform the following substitutions as necessary:
367  *
368  *	%%	%
369  *	%u	Username
370  *	%z	Name of target zone
371  *	%Z	Name of current zone
372  *	%R	Zonepath of zone
373  *
374  * Returns 0 on success, -1 on failure.
375  */
376 static int
377 brand_get_value(struct brand_handle *bhp, const char *zonename,
378     const char *zonepath, const char *username, const char *curr_zone,
379     char *buf, size_t len, const xmlChar *tagname,
380     boolean_t substitute, boolean_t optional)
381 {
382 	xmlNodePtr node;
383 	xmlChar *content;
384 	int err = 0;
385 
386 	/*
387 	 * Retrieve the specified value from the XML doc
388 	 */
389 	if ((node = xmlDocGetRootElement(bhp->bh_config)) == NULL)
390 		return (-1);
391 
392 	if (xmlStrcmp(node->name, DTD_ELEM_BRAND) != 0)
393 		return (-1);
394 
395 	for (node = node->xmlChildrenNode; node != NULL;
396 	    node = node->next) {
397 		if (xmlStrcmp(node->name, tagname) == 0)
398 			break;
399 	}
400 
401 	if (node == NULL) {
402 		if (optional) {
403 			buf[0] = '\0';
404 			return (0);
405 		} else {
406 			return (-1);
407 		}
408 	}
409 
410 	if ((content = xmlNodeGetContent(node)) == NULL)
411 		return (-1);
412 
413 	if (strlen((char *)content) == 0) {
414 		/*
415 		 * If the entry in the config file is empty, check to see
416 		 * whether this is an optional field.  If so, we return the
417 		 * empty buffer.  If not, we return an error.
418 		 */
419 		if (optional) {
420 			buf[0] = '\0';
421 		} else {
422 			err = -1;
423 		}
424 	} else {
425 		/* Substitute token values as needed. */
426 		if (substitute) {
427 			if (i_substitute_tokens((char *)content, buf, len,
428 			    zonename, zonepath, username, curr_zone) != 0)
429 				err = -1;
430 		} else {
431 			if (strlcpy(buf, (char *)content, len) >= len)
432 				err = -1;
433 		}
434 	}
435 
436 	xmlFree(content);
437 
438 	return (err);
439 }
440 
441 int
442 brand_get_attach(brand_handle_t bh, const char *zonename,
443     const char *zonepath, char *buf, size_t len)
444 {
445 	struct brand_handle *bhp = (struct brand_handle *)bh;
446 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
447 	    buf, len, DTD_ELEM_ATTACH, B_TRUE, B_TRUE));
448 }
449 
450 int
451 brand_get_boot(brand_handle_t bh, const char *zonename,
452     const char *zonepath, char *buf, size_t len)
453 {
454 	struct brand_handle *bhp = (struct brand_handle *)bh;
455 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
456 	    buf, len, DTD_ELEM_BOOT, B_TRUE, B_TRUE));
457 }
458 
459 int
460 brand_get_brandname(brand_handle_t bh, char *buf, size_t len)
461 {
462 	struct brand_handle *bhp = (struct brand_handle *)bh;
463 	if (len <= strlen(bhp->bh_name))
464 		return (-1);
465 
466 	(void) strcpy(buf, bhp->bh_name);
467 
468 	return (0);
469 }
470 
471 int
472 brand_get_clone(brand_handle_t bh, const char *zonename,
473     const char *zonepath, char *buf, size_t len)
474 {
475 	struct brand_handle *bhp = (struct brand_handle *)bh;
476 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
477 	    buf, len, DTD_ELEM_CLONE, B_TRUE, B_TRUE));
478 }
479 
480 int
481 brand_get_detach(brand_handle_t bh, const char *zonename,
482     const char *zonepath, char *buf, size_t len)
483 {
484 	struct brand_handle *bhp = (struct brand_handle *)bh;
485 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
486 	    buf, len, DTD_ELEM_DETACH, B_TRUE, B_TRUE));
487 }
488 
489 int
490 brand_get_halt(brand_handle_t bh, const char *zonename,
491     const char *zonepath, char *buf, size_t len)
492 {
493 	struct brand_handle *bhp = (struct brand_handle *)bh;
494 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
495 	    buf, len, DTD_ELEM_HALT, B_TRUE, B_TRUE));
496 }
497 
498 int
499 brand_get_shutdown(brand_handle_t bh, const char *zonename,
500     const char *zonepath, char *buf, size_t len)
501 {
502 	struct brand_handle *bhp = (struct brand_handle *)bh;
503 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
504 	    buf, len, DTD_ELEM_SHUTDOWN, B_TRUE, B_TRUE));
505 }
506 
507 int
508 brand_get_initname(brand_handle_t bh, char *buf, size_t len)
509 {
510 	struct brand_handle *bhp = (struct brand_handle *)bh;
511 	return (brand_get_value(bhp, NULL, NULL, NULL, NULL,
512 	    buf, len, DTD_ELEM_INITNAME, B_FALSE, B_FALSE));
513 }
514 
515 static boolean_t
516 i_brand_restartinit(brand_handle_t bh, const xmlChar *tagname, boolean_t deflt)
517 {
518 	struct brand_handle *bhp = (struct brand_handle *)bh;
519 	char val[80];
520 
521 	if (brand_get_value(bhp, NULL, NULL, NULL, NULL,
522 	    val, sizeof (val), tagname, B_FALSE, B_FALSE) != 0) {
523 		return (deflt);
524 	}
525 
526 	if (strcmp(val, "false") == 0)
527 		return (B_FALSE);
528 	return (B_TRUE);
529 }
530 
531 boolean_t
532 brand_restartinit(brand_handle_t bh)
533 {
534 	return (i_brand_restartinit(bh, DTD_ELEM_RESTARTINIT, B_TRUE));
535 }
536 
537 boolean_t
538 brand_restartinit0(brand_handle_t bh)
539 {
540 	return (i_brand_restartinit(bh, DTD_ELEM_RESTARTINIT0, B_FALSE));
541 }
542 
543 boolean_t
544 brand_restartinitreboot(brand_handle_t bh)
545 {
546 	return (i_brand_restartinit(bh, DTD_ELEM_RESTARTINITREBOOT, B_FALSE));
547 }
548 
549 int
550 brand_get_login_cmd(brand_handle_t bh, const char *username,
551     char *buf, size_t len)
552 {
553 	struct brand_handle *bhp = (struct brand_handle *)bh;
554 	const char *curr_zone = get_curr_zone();
555 	return (brand_get_value(bhp, NULL, NULL, username, curr_zone,
556 	    buf, len, DTD_ELEM_LOGIN_CMD, B_TRUE, B_FALSE));
557 }
558 
559 int
560 brand_get_forcedlogin_cmd(brand_handle_t bh, const char *username,
561     char *buf, size_t len)
562 {
563 	struct brand_handle *bhp = (struct brand_handle *)bh;
564 	const char *curr_zone = get_curr_zone();
565 	return (brand_get_value(bhp, NULL, NULL, username, curr_zone,
566 	    buf, len, DTD_ELEM_FORCELOGIN_CMD, B_TRUE, B_FALSE));
567 }
568 
569 int
570 brand_get_user_cmd(brand_handle_t bh, const char *username,
571     char *buf, size_t len)
572 {
573 	struct brand_handle *bhp = (struct brand_handle *)bh;
574 
575 	return (brand_get_value(bhp, NULL, NULL, username, NULL,
576 	    buf, len, DTD_ELEM_USER_CMD, B_TRUE, B_FALSE));
577 }
578 
579 int
580 brand_get_install(brand_handle_t bh, const char *zonename,
581     const char *zonepath, char *buf, size_t len)
582 {
583 	struct brand_handle *bhp = (struct brand_handle *)bh;
584 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
585 	    buf, len, DTD_ELEM_INSTALL, B_TRUE, B_FALSE));
586 }
587 
588 int
589 brand_get_installopts(brand_handle_t bh, char *buf, size_t len)
590 {
591 	struct brand_handle *bhp = (struct brand_handle *)bh;
592 	return (brand_get_value(bhp, NULL, NULL, NULL, NULL,
593 	    buf, len, DTD_ELEM_INSTALLOPTS, B_FALSE, B_TRUE));
594 }
595 
596 int
597 brand_get_modname(brand_handle_t bh, char *buf, size_t len)
598 {
599 	struct brand_handle *bhp = (struct brand_handle *)bh;
600 	return (brand_get_value(bhp, NULL, NULL, NULL, NULL,
601 	    buf, len, DTD_ELEM_MODNAME, B_FALSE, B_TRUE));
602 }
603 
604 int
605 brand_get_postattach(brand_handle_t bh, const char *zonename,
606     const char *zonepath, char *buf, size_t len)
607 {
608 	struct brand_handle *bhp = (struct brand_handle *)bh;
609 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
610 	    buf, len, DTD_ELEM_POSTATTACH, B_TRUE, B_TRUE));
611 }
612 
613 int
614 brand_get_postclone(brand_handle_t bh, const char *zonename,
615     const char *zonepath, char *buf, size_t len)
616 {
617 	struct brand_handle *bhp = (struct brand_handle *)bh;
618 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
619 	    buf, len, DTD_ELEM_POSTCLONE, B_TRUE, B_TRUE));
620 }
621 
622 int
623 brand_get_postinstall(brand_handle_t bh, const char *zonename,
624     const char *zonepath, char *buf, size_t len)
625 {
626 	struct brand_handle *bhp = (struct brand_handle *)bh;
627 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
628 	    buf, len, DTD_ELEM_POSTINSTALL, B_TRUE, B_TRUE));
629 }
630 
631 int
632 brand_get_postsnap(brand_handle_t bh, const char *zonename,
633     const char *zonepath, char *buf, size_t len)
634 {
635 	struct brand_handle *bhp = (struct brand_handle *)bh;
636 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
637 	    buf, len, DTD_ELEM_POSTSNAP, B_TRUE, B_TRUE));
638 }
639 
640 int
641 brand_get_poststatechange(brand_handle_t bh, const char *zonename,
642     const char *zonepath, char *buf, size_t len)
643 {
644 	struct brand_handle *bhp = (struct brand_handle *)bh;
645 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
646 	    buf, len, DTD_ELEM_POSTSTATECHG, B_TRUE, B_TRUE));
647 }
648 
649 int
650 brand_get_predetach(brand_handle_t bh, const char *zonename,
651     const char *zonepath, char *buf, size_t len)
652 {
653 	struct brand_handle *bhp = (struct brand_handle *)bh;
654 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
655 	    buf, len, DTD_ELEM_PREDETACH, B_TRUE, B_TRUE));
656 }
657 
658 int
659 brand_get_presnap(brand_handle_t bh, const char *zonename,
660     const char *zonepath, char *buf, size_t len)
661 {
662 	struct brand_handle *bhp = (struct brand_handle *)bh;
663 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
664 	    buf, len, DTD_ELEM_PRESNAP, B_TRUE, B_TRUE));
665 }
666 
667 int
668 brand_get_prestatechange(brand_handle_t bh, const char *zonename,
669     const char *zonepath, char *buf, size_t len)
670 {
671 	struct brand_handle *bhp = (struct brand_handle *)bh;
672 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
673 	    buf, len, DTD_ELEM_PRESTATECHG, B_TRUE, B_TRUE));
674 }
675 
676 int
677 brand_get_preuninstall(brand_handle_t bh, const char *zonename,
678     const char *zonepath, char *buf, size_t len)
679 {
680 	struct brand_handle *bhp = (struct brand_handle *)bh;
681 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
682 	    buf, len, DTD_ELEM_PREUNINSTALL, B_TRUE, B_TRUE));
683 }
684 
685 int
686 brand_get_query(brand_handle_t bh, const char *zonename,
687     const char *zonepath, char *buf, size_t len)
688 {
689 	struct brand_handle *bhp = (struct brand_handle *)bh;
690 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
691 	    buf, len, DTD_ELEM_QUERY, B_TRUE, B_TRUE));
692 }
693 
694 int
695 brand_get_secflags(brand_handle_t bh, char *buf, size_t len)
696 {
697 	struct brand_handle *bhp = (struct brand_handle *)bh;
698 	return (brand_get_value(bhp, NULL, NULL, NULL, NULL,
699 	    buf, len, DTD_ELEM_SECFLAGS, B_FALSE, B_TRUE));
700 }
701 
702 int
703 brand_get_uninstall(brand_handle_t bh, const char *zonename,
704     const char *zonepath, char *buf, size_t len)
705 {
706 	struct brand_handle *bhp = (struct brand_handle *)bh;
707 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
708 	    buf, len, DTD_ELEM_UNINSTALL, B_TRUE, B_TRUE));
709 }
710 
711 int
712 brand_get_validatesnap(brand_handle_t bh, const char *zonename,
713     const char *zonepath, char *buf, size_t len)
714 {
715 	struct brand_handle *bhp = (struct brand_handle *)bh;
716 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
717 	    buf, len, DTD_ELEM_VALIDSNAP, B_TRUE, B_TRUE));
718 }
719 
720 int
721 brand_get_verify_cfg(brand_handle_t bh, char *buf, size_t len)
722 {
723 	struct brand_handle *bhp = (struct brand_handle *)bh;
724 	return (brand_get_value(bhp, NULL, NULL, NULL, NULL,
725 	    buf, len, DTD_ELEM_VERIFY_CFG, B_FALSE, B_TRUE));
726 }
727 
728 int
729 brand_get_verify_adm(brand_handle_t bh, const char *zonename,
730     const char *zonepath, char *buf, size_t len)
731 {
732 	struct brand_handle *bhp = (struct brand_handle *)bh;
733 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
734 	    buf, len, DTD_ELEM_VERIFY_ADM, B_TRUE, B_TRUE));
735 }
736 
737 int
738 brand_get_sysboot(brand_handle_t bh, const char *zonename,
739     const char *zonepath, char *buf, size_t len)
740 {
741 	struct brand_handle *bhp = (struct brand_handle *)bh;
742 	return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
743 	    buf, len, DTD_ELEM_SYSBOOT, B_TRUE, B_TRUE));
744 }
745 
746 boolean_t
747 brand_allow_exclusive_ip(brand_handle_t bh)
748 {
749 	struct brand_handle	*bhp = (struct brand_handle *)bh;
750 	xmlNodePtr		node;
751 	xmlChar			*allow_excl;
752 	boolean_t		ret;
753 
754 	assert(bhp != NULL);
755 
756 	if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL)
757 		return (B_FALSE);
758 
759 	allow_excl = xmlGetProp(node, DTD_ATTR_ALLOWEXCL);
760 	if (allow_excl == NULL)
761 		return (B_FALSE);
762 
763 	/* Note: only return B_TRUE if it's "true" */
764 	if (strcmp((char *)allow_excl, DTD_ENTITY_TRUE) == 0)
765 		ret = B_TRUE;
766 	else
767 		ret = B_FALSE;
768 
769 	xmlFree(allow_excl);
770 
771 	return (ret);
772 }
773 
774 /*
775  * Iterate over brand privileges
776  *
777  * Walks the brand config, searching for <privilege> elements, calling the
778  * specified callback for each.  Returns 0 on success, or -1 on failure.
779  */
780 int
781 brand_config_iter_privilege(brand_handle_t bh,
782     int (*func)(void *, priv_iter_t *), void *data)
783 {
784 	struct brand_handle	*bhp = (struct brand_handle *)bh;
785 	xmlNodePtr		node;
786 	xmlChar			*name, *set, *iptype;
787 	priv_iter_t		priv_iter;
788 	int			ret;
789 
790 	if ((node = xmlDocGetRootElement(bhp->bh_config)) == NULL)
791 		return (-1);
792 
793 	for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
794 
795 		if (xmlStrcmp(node->name, DTD_ELEM_PRIVILEGE) != 0)
796 			continue;
797 
798 		name = xmlGetProp(node, DTD_ATTR_NAME);
799 		set = xmlGetProp(node, DTD_ATTR_SET);
800 		iptype = xmlGetProp(node, DTD_ATTR_IPTYPE);
801 
802 		if (name == NULL || set == NULL || iptype == NULL) {
803 			if (name != NULL)
804 				xmlFree(name);
805 			if (set != NULL)
806 				xmlFree(set);
807 			if (iptype != NULL)
808 				xmlFree(iptype);
809 			return (-1);
810 		}
811 
812 		priv_iter.pi_name = (char *)name;
813 		priv_iter.pi_set = (char *)set;
814 		priv_iter.pi_iptype = (char *)iptype;
815 
816 		ret = func(data, &priv_iter);
817 
818 		xmlFree(name);
819 		xmlFree(set);
820 		xmlFree(iptype);
821 
822 		if (ret != 0)
823 			return (-1);
824 	}
825 
826 	return (0);
827 }
828 
829 static int
830 i_brand_platform_iter_mounts(struct brand_handle *bhp, const char *zonename,
831     const char *zonepath, int (*func)(void *, const char *, const char *,
832     const char *, const char *), void *data, const xmlChar *mount_type)
833 {
834 	xmlNodePtr node;
835 	xmlChar *special, *dir, *type, *opt;
836 	char special_exp[MAXPATHLEN];
837 	char opt_exp[MAXPATHLEN];
838 	int ret;
839 
840 	if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL)
841 		return (-1);
842 
843 	for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
844 
845 		if (xmlStrcmp(node->name, mount_type) != 0)
846 			continue;
847 
848 		special = xmlGetProp(node, DTD_ATTR_SPECIAL);
849 		dir = xmlGetProp(node, DTD_ATTR_DIRECTORY);
850 		type = xmlGetProp(node, DTD_ATTR_TYPE);
851 		opt = xmlGetProp(node, DTD_ATTR_OPT);
852 		if ((special == NULL) || (dir == NULL) || (type == NULL) ||
853 		    (opt == NULL)) {
854 			ret = -1;
855 			goto next;
856 		}
857 
858 		/* Substitute token values as needed. */
859 		if ((ret = i_substitute_tokens((char *)special,
860 		    special_exp, sizeof (special_exp),
861 		    zonename, zonepath, NULL, NULL)) != 0)
862 			goto next;
863 
864 		/* opt might not be defined */
865 		if (strlen((const char *)opt) == 0) {
866 			xmlFree(opt);
867 			opt = NULL;
868 		} else {
869 			if ((ret = i_substitute_tokens((char *)opt,
870 			    opt_exp, sizeof (opt_exp),
871 			    zonename, zonepath, NULL, NULL)) != 0)
872 				goto next;
873 		}
874 
875 		ret = func(data, (char *)special_exp, (char *)dir,
876 		    (char *)type, ((opt != NULL) ? opt_exp : NULL));
877 
878 next:
879 		if (special != NULL)
880 			xmlFree(special);
881 		if (dir != NULL)
882 			xmlFree(dir);
883 		if (type != NULL)
884 			xmlFree(type);
885 		if (opt != NULL)
886 			xmlFree(opt);
887 		if (ret != 0)
888 			return (-1);
889 	}
890 	return (0);
891 }
892 
893 
894 /*
895  * Iterate over global platform filesystems
896  *
897  * Walks the platform, searching for <global_mount> elements, calling the
898  * specified callback for each.  Returns 0 on success, or -1 on failure.
899  *
900  * Perform the following substitutions as necessary:
901  *
902  *	%R	Zonepath of zone
903  */
904 int
905 brand_platform_iter_gmounts(brand_handle_t bh, const char *zonename,
906     const char *zonepath, int (*func)(void *, const char *, const char *,
907     const char *, const char *), void *data)
908 {
909 	struct brand_handle *bhp = (struct brand_handle *)bh;
910 	return (i_brand_platform_iter_mounts(bhp, zonename, zonepath, func,
911 	    data, DTD_ELEM_GLOBAL_MOUNT));
912 }
913 
914 /*
915  * Iterate over non-global zone platform filesystems
916  *
917  * Walks the platform, searching for <mount> elements, calling the
918  * specified callback for each.  Returns 0 on success, or -1 on failure.
919  */
920 int
921 brand_platform_iter_mounts(brand_handle_t bh, int (*func)(void *,
922     const char *, const char *, const char *, const char *), void *data)
923 {
924 	struct brand_handle *bhp = (struct brand_handle *)bh;
925 	return (i_brand_platform_iter_mounts(bhp, NULL, NULL, func, data,
926 	    DTD_ELEM_MOUNT));
927 }
928 
929 /*
930  * Iterate over platform symlinks
931  *
932  * Walks the platform, searching for <symlink> elements, calling the
933  * specified callback for each.  Returns 0 on success, or -1 on failure.
934  */
935 int
936 brand_platform_iter_link(brand_handle_t bh,
937     int (*func)(void *, const char *, const char *), void *data)
938 {
939 	struct brand_handle *bhp = (struct brand_handle *)bh;
940 	xmlNodePtr node;
941 	xmlChar *source, *target;
942 	int ret;
943 
944 	if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL)
945 		return (-1);
946 
947 	for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
948 
949 		if (xmlStrcmp(node->name, DTD_ELEM_SYMLINK) != 0)
950 			continue;
951 
952 		source = xmlGetProp(node, DTD_ATTR_SOURCE);
953 		target = xmlGetProp(node, DTD_ATTR_TARGET);
954 
955 		if (source == NULL || target == NULL) {
956 			if (source != NULL)
957 				xmlFree(source);
958 			if (target != NULL)
959 				xmlFree(target);
960 			return (-1);
961 		}
962 
963 		ret = func(data, (char *)source, (char *)target);
964 
965 		xmlFree(source);
966 		xmlFree(target);
967 
968 		if (ret != 0)
969 			return (-1);
970 	}
971 
972 	return (0);
973 }
974 
975 /*
976  * Iterate over platform devices
977  *
978  * Walks the platform, searching for <device> elements, calling the
979  * specified callback for each.  Returns 0 on success, or -1 on failure.
980  */
981 int
982 brand_platform_iter_devices(brand_handle_t bh, const char *zonename,
983     int (*func)(void *, const char *, const char *), void *data,
984     const char *curr_iptype)
985 {
986 	struct brand_handle	*bhp = (struct brand_handle *)bh;
987 	const char		*curr_arch = get_curr_arch();
988 	xmlNodePtr		node;
989 	xmlChar			*match, *name, *arch, *iptype;
990 	char			match_exp[MAXPATHLEN];
991 	boolean_t		err = B_FALSE;
992 	int			ret = 0;
993 
994 
995 	assert(bhp != NULL);
996 	assert(zonename != NULL);
997 	assert(func != NULL);
998 	assert(curr_iptype != NULL);
999 
1000 	if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL)
1001 		return (-1);
1002 
1003 	for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
1004 
1005 		if (xmlStrcmp(node->name, DTD_ELEM_DEVICE) != 0)
1006 			continue;
1007 
1008 		match = xmlGetProp(node, DTD_ATTR_MATCH);
1009 		name = xmlGetProp(node, DTD_ATTR_NAME);
1010 		arch = xmlGetProp(node, DTD_ATTR_ARCH);
1011 		iptype = xmlGetProp(node, DTD_ATTR_IPTYPE);
1012 		if ((match == NULL) || (name == NULL) || (arch == NULL) ||
1013 		    (iptype == NULL)) {
1014 			err = B_TRUE;
1015 			goto next;
1016 		}
1017 
1018 		/* check if the arch matches */
1019 		if ((strcmp((char *)arch, "all") != 0) &&
1020 		    (strcmp((char *)arch, curr_arch) != 0))
1021 			goto next;
1022 
1023 		/* check if the iptype matches */
1024 		if ((strcmp((char *)iptype, "all") != 0) &&
1025 		    (strcmp((char *)iptype, curr_iptype) != 0))
1026 			goto next;
1027 
1028 		/* Substitute token values as needed. */
1029 		if ((ret = i_substitute_tokens((char *)match,
1030 		    match_exp, sizeof (match_exp),
1031 		    zonename, NULL, NULL, NULL)) != 0) {
1032 			err = B_TRUE;
1033 			goto next;
1034 		}
1035 
1036 		/* name might not be defined */
1037 		if (strlen((const char *)name) == 0) {
1038 			xmlFree(name);
1039 			name = NULL;
1040 		}
1041 
1042 		/* invoke the callback */
1043 		ret = func(data, (const char *)match_exp, (const char *)name);
1044 
1045 next:
1046 		if (match != NULL)
1047 			xmlFree(match);
1048 		if (name != NULL)
1049 			xmlFree(name);
1050 		if (arch != NULL)
1051 			xmlFree(arch);
1052 		if (iptype != NULL)
1053 			xmlFree(iptype);
1054 		if (err)
1055 			return (-1);
1056 		if (ret != 0)
1057 			return (-1);
1058 	}
1059 
1060 	return (0);
1061 }
1062