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