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