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