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