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