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