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