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