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