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