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