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