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