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