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