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