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