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