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