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