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