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