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_POSTATTACH     ((const xmlChar *) "postattach")
  67 #define DTD_ELEM_POSTCLONE      ((const xmlChar *) "postclone")
  68 #define DTD_ELEM_POSTINSTALL    ((const xmlChar *) "postinstall")
  69 #define DTD_ELEM_POSTSNAP       ((const xmlChar *) "postsnap")
  70 #define DTD_ELEM_POSTSTATECHG   ((const xmlChar *) "poststatechange")
  71 #define DTD_ELEM_PREDETACH      ((const xmlChar *) "predetach")
  72 #define DTD_ELEM_PRESNAP        ((const xmlChar *) "presnap")
  73 #define DTD_ELEM_PRESTATECHG    ((const xmlChar *) "prestatechange")
  74 #define DTD_ELEM_PREUNINSTALL   ((const xmlChar *) "preuninstall")
  75 #define DTD_ELEM_PRIVILEGE      ((const xmlChar *) "privilege")
  76 #define DTD_ELEM_QUERY          ((const xmlChar *) "query")
  77 #define DTD_ELEM_SHUTDOWN       ((const xmlChar *) "shutdown")
  78 #define DTD_ELEM_SYMLINK        ((const xmlChar *) "symlink")
  79 #define DTD_ELEM_SYSBOOT        ((const xmlChar *) "sysboot")
  80 #define DTD_ELEM_UNINSTALL      ((const xmlChar *) "uninstall")
  81 #define DTD_ELEM_USER_CMD       ((const xmlChar *) "user_cmd")
  82 #define DTD_ELEM_VALIDSNAP      ((const xmlChar *) "validatesnap")
  83 #define DTD_ELEM_VERIFY_CFG     ((const xmlChar *) "verify_cfg")
  84 #define DTD_ELEM_VERIFY_ADM     ((const xmlChar *) "verify_adm")
  85 
  86 #define DTD_ATTR_ALLOWEXCL      ((const xmlChar *) "allow-exclusive-ip")
  87 #define DTD_ATTR_ARCH           ((const xmlChar *) "arch")
  88 #define DTD_ATTR_DIRECTORY      ((const xmlChar *) "directory")
  89 #define DTD_ATTR_IPTYPE         ((const xmlChar *) "ip-type")
  90 #define DTD_ATTR_MATCH          ((const xmlChar *) "match")
  91 #define DTD_ATTR_MODE           ((const xmlChar *) "mode")
  92 #define DTD_ATTR_NAME           ((const xmlChar *) "name")
  93 #define DTD_ATTR_OPT            ((const xmlChar *) "opt")
  94 #define DTD_ATTR_PATH           ((const xmlChar *) "path")
  95 #define DTD_ATTR_SET            ((const xmlChar *) "set")
  96 #define DTD_ATTR_SOURCE         ((const xmlChar *) "source")
  97 #define DTD_ATTR_SPECIAL        ((const xmlChar *) "special")
  98 #define DTD_ATTR_TARGET         ((const xmlChar *) "target")
  99 #define DTD_ATTR_TYPE           ((const xmlChar *) "type")
 100 
 101 #define DTD_ENTITY_TRUE         "true"
 102 
 103 static volatile boolean_t       libbrand_initialized = B_FALSE;
 104 static char                     i_curr_arch[MAXNAMELEN];
 105 static char                     i_curr_zone[ZONENAME_MAX];
 106 
 107 /*ARGSUSED*/
 108 static void
 109 brand_error_func(void *ctx, const char *msg, ...)
 110 {
 111         /*
 112          * Ignore error messages from libxml
 113          */
 114 }
 115 
 116 static boolean_t
 117 libbrand_initialize()
 118 {
 119         static mutex_t initialize_lock = DEFAULTMUTEX;
 120 
 121         (void) mutex_lock(&initialize_lock);
 122 
 123         if (libbrand_initialized) {
 124                 (void) mutex_unlock(&initialize_lock);
 125                 return (B_TRUE);
 126         }
 127 
 128         if (sysinfo(SI_ARCHITECTURE, i_curr_arch, sizeof (i_curr_arch)) < 0) {
 129                 (void) mutex_unlock(&initialize_lock);
 130                 return (B_FALSE);
 131         }
 132 
 133         if (getzonenamebyid(getzoneid(), i_curr_zone,
 134             sizeof (i_curr_zone)) < 0) {
 135                 (void) mutex_unlock(&initialize_lock);
 136                 return (B_FALSE);
 137         }
 138 
 139         /*
 140          * Note that here we're initializing per-process libxml2
 141          * state.  By doing so we're implicitly assuming that
 142          * no other code in this process is also trying to
 143          * use libxml2.  But in most case we know this not to
 144          * be true since we're almost always used in conjunction
 145          * with libzonecfg, which also uses libxml2.  Lucky for
 146          * us, libzonecfg initializes libxml2 to essentially
 147          * the same defaults as we're using below.
 148          */
 149         (void) xmlLineNumbersDefault(1);
 150         xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
 151         xmlDoValidityCheckingDefaultValue = 1;
 152         (void) xmlKeepBlanksDefault(0);
 153         xmlGetWarningsDefaultValue = 0;
 154         xmlSetGenericErrorFunc(NULL, brand_error_func);
 155 
 156         libbrand_initialized = B_TRUE;
 157         (void) mutex_unlock(&initialize_lock);
 158         return (B_TRUE);
 159 }
 160 
 161 static const char *
 162 get_curr_arch(void)
 163 {
 164         if (!libbrand_initialize())
 165                 return (NULL);
 166 
 167         return (i_curr_arch);
 168 }
 169 
 170 static const char *
 171 get_curr_zone(void)
 172 {
 173         if (!libbrand_initialize())
 174                 return (NULL);
 175 
 176         return (i_curr_zone);
 177 }
 178 
 179 /*
 180  * Internal function to open an XML file
 181  *
 182  * Returns the XML doc pointer, or NULL on failure.  It will validate the
 183  * document, as well as removing any comments from the document structure.
 184  */
 185 static xmlDocPtr
 186 open_xml_file(const char *file)
 187 {
 188         xmlDocPtr doc;
 189         xmlValidCtxtPtr cvp;
 190         int valid;
 191 
 192         if (!libbrand_initialize())
 193                 return (NULL);
 194 
 195         /*
 196          * Parse the file
 197          */
 198         if ((doc = xmlParseFile(file)) == NULL)
 199                 return (NULL);
 200 
 201         /*
 202          * Validate the file
 203          */
 204         if ((cvp = xmlNewValidCtxt()) == NULL) {
 205                 xmlFreeDoc(doc);
 206                 return (NULL);
 207         }
 208         cvp->error = brand_error_func;
 209         cvp->warning = brand_error_func;
 210         valid = xmlValidateDocument(cvp, doc);
 211         xmlFreeValidCtxt(cvp);
 212         if (valid == 0) {
 213                 xmlFreeDoc(doc);
 214                 return (NULL);
 215         }
 216 
 217         return (doc);
 218 }
 219 /*
 220  * Open a handle to the named brand.
 221  *
 222  * Returns a handle to the named brand, which is used for all subsequent brand
 223  * interaction, or NULL if unable to open or initialize the brand.
 224  */
 225 brand_handle_t
 226 brand_open(const char *name)
 227 {
 228         struct brand_handle *bhp;
 229         char path[MAXPATHLEN];
 230         xmlNodePtr node;
 231         xmlChar *property;
 232         struct stat statbuf;
 233 
 234         /*
 235          * Make sure brand name isn't too long
 236          */
 237         if (strlen(name) >= MAXNAMELEN)
 238                 return (NULL);
 239 
 240         /*
 241          * Check that the brand exists
 242          */
 243         (void) snprintf(path, sizeof (path), "%s/%s", BRAND_DIR, name);
 244 
 245         if (stat(path, &statbuf) != 0)
 246                 return (NULL);
 247 
 248         /*
 249          * Allocate brand handle
 250          */
 251         if ((bhp = malloc(sizeof (struct brand_handle))) == NULL)
 252                 return (NULL);
 253         bzero(bhp, sizeof (struct brand_handle));
 254 
 255         (void) strcpy(bhp->bh_name, name);
 256 
 257         /*
 258          * Open the configuration file
 259          */
 260         (void) snprintf(path, sizeof (path), "%s/%s/%s", BRAND_DIR, name,
 261             BRAND_CONFIG);
 262         if ((bhp->bh_config = open_xml_file(path)) == NULL) {
 263                 brand_close((brand_handle_t)bhp);
 264                 return (NULL);
 265         }
 266 
 267         /*
 268          * Verify that the name of the brand matches the directory in which it
 269          * is installed.
 270          */
 271         if ((node = xmlDocGetRootElement(bhp->bh_config)) == NULL) {
 272                 brand_close((brand_handle_t)bhp);
 273                 return (NULL);
 274         }
 275 
 276         if (xmlStrcmp(node->name, DTD_ELEM_BRAND) != 0) {
 277                 brand_close((brand_handle_t)bhp);
 278                 return (NULL);
 279         }
 280 
 281         if ((property = xmlGetProp(node, DTD_ATTR_NAME)) == NULL) {
 282                 brand_close((brand_handle_t)bhp);
 283                 return (NULL);
 284         }
 285 
 286         if (strcmp((char *)property, name) != 0) {
 287                 xmlFree(property);
 288                 brand_close((brand_handle_t)bhp);
 289                 return (NULL);
 290         }
 291         xmlFree(property);
 292 
 293         /*
 294          * Open handle to platform configuration file.
 295          */
 296         (void) snprintf(path, sizeof (path), "%s/%s/%s", BRAND_DIR, name,
 297             BRAND_PLATFORM);
 298         if ((bhp->bh_platform = open_xml_file(path)) == NULL) {
 299                 brand_close((brand_handle_t)bhp);
 300                 return (NULL);
 301         }
 302 
 303         return ((brand_handle_t)bhp);
 304 }
 305 
 306 /*
 307  * Closes the given brand handle
 308  */
 309 void
 310 brand_close(brand_handle_t bh)
 311 {
 312         struct brand_handle *bhp = (struct brand_handle *)bh;
 313         if (bhp->bh_platform != NULL)
 314                 xmlFreeDoc(bhp->bh_platform);
 315         if (bhp->bh_config != NULL)
 316                 xmlFreeDoc(bhp->bh_config);
 317         free(bhp);
 318 }
 319 
 320 static int
 321 i_substitute_tokens(const char *sbuf, char *dbuf, int dbuf_size,
 322     const char *zonename, const char *zonepath, const char *username,
 323     const char *curr_zone)
 324 {
 325         int dst, src;
 326         static char *env_pool = NULL;
 327 
 328         /*
 329          * Walk through the characters, substituting values as needed.
 330          */
 331         dbuf[0] = '\0';
 332         dst = 0;
 333         for (src = 0; src < strlen((char *)sbuf) && dst < dbuf_size; src++) {
 334                 if (sbuf[src] != '%') {
 335                         dbuf[dst++] = sbuf[src];
 336                         continue;
 337                 }
 338 
 339                 switch (sbuf[++src]) {
 340                 case '%':
 341                         dst += strlcpy(dbuf + dst, "%", dbuf_size - dst);
 342                         break;
 343                 case 'P':
 344                         if (env_pool == NULL)
 345                                 env_pool = getenv("_ZONEADMD_ZPOOL");
 346                         if (env_pool == NULL)
 347                                 break;
 348                         dst += strlcpy(dbuf + dst, env_pool, 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_shutdown(brand_handle_t bh, const char *zonename,
 518     const char *zonepath, char *buf, size_t len)
 519 {
 520         struct brand_handle *bhp = (struct brand_handle *)bh;
 521         return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
 522             buf, len, DTD_ELEM_SHUTDOWN, B_TRUE, B_TRUE));
 523 }
 524 
 525 int
 526 brand_get_initname(brand_handle_t bh, char *buf, size_t len)
 527 {
 528         struct brand_handle *bhp = (struct brand_handle *)bh;
 529         return (brand_get_value(bhp, NULL, NULL, NULL, NULL,
 530             buf, len, DTD_ELEM_INITNAME, B_FALSE, B_FALSE));
 531 }
 532 
 533 boolean_t
 534 brand_restartinit(brand_handle_t bh)
 535 {
 536         struct brand_handle *bhp = (struct brand_handle *)bh;
 537         char val[80];
 538 
 539         if (brand_get_value(bhp, NULL, NULL, NULL, NULL,
 540             val, sizeof (val), DTD_ELEM_RESTARTINIT, B_FALSE, B_FALSE) != 0)
 541                 return (B_TRUE);
 542 
 543         if (strcmp(val, "false") == 0)
 544                 return (B_FALSE);
 545         return (B_TRUE);
 546 }
 547 
 548 int
 549 brand_get_login_cmd(brand_handle_t bh, const char *username,
 550     char *buf, size_t len)
 551 {
 552         struct brand_handle *bhp = (struct brand_handle *)bh;
 553         const char *curr_zone = get_curr_zone();
 554         return (brand_get_value(bhp, NULL, NULL, username, curr_zone,
 555             buf, len, DTD_ELEM_LOGIN_CMD, B_TRUE, B_FALSE));
 556 }
 557 
 558 int
 559 brand_get_forcedlogin_cmd(brand_handle_t bh, const char *username,
 560     char *buf, size_t len)
 561 {
 562         struct brand_handle *bhp = (struct brand_handle *)bh;
 563         const char *curr_zone = get_curr_zone();
 564         return (brand_get_value(bhp, NULL, NULL, username, curr_zone,
 565             buf, len, DTD_ELEM_FORCELOGIN_CMD, B_TRUE, B_FALSE));
 566 }
 567 
 568 int
 569 brand_get_user_cmd(brand_handle_t bh, const char *username,
 570     char *buf, size_t len)
 571 {
 572         struct brand_handle *bhp = (struct brand_handle *)bh;
 573 
 574         return (brand_get_value(bhp, NULL, NULL, username, NULL,
 575             buf, len, DTD_ELEM_USER_CMD, B_TRUE, B_FALSE));
 576 }
 577 
 578 int
 579 brand_get_install(brand_handle_t bh, const char *zonename,
 580     const char *zonepath, char *buf, size_t len)
 581 {
 582         struct brand_handle *bhp = (struct brand_handle *)bh;
 583         return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
 584             buf, len, DTD_ELEM_INSTALL, B_TRUE, B_FALSE));
 585 }
 586 
 587 int
 588 brand_get_installopts(brand_handle_t bh, char *buf, size_t len)
 589 {
 590         struct brand_handle *bhp = (struct brand_handle *)bh;
 591         return (brand_get_value(bhp, NULL, NULL, NULL, NULL,
 592             buf, len, DTD_ELEM_INSTALLOPTS, B_FALSE, B_TRUE));
 593 }
 594 
 595 int
 596 brand_get_modname(brand_handle_t bh, char *buf, size_t len)
 597 {
 598         struct brand_handle *bhp = (struct brand_handle *)bh;
 599         return (brand_get_value(bhp, NULL, NULL, NULL, NULL,
 600             buf, len, DTD_ELEM_MODNAME, B_FALSE, B_TRUE));
 601 }
 602 
 603 int
 604 brand_get_postattach(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_POSTATTACH, B_TRUE, B_TRUE));
 610 }
 611 
 612 int
 613 brand_get_postclone(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_POSTCLONE, B_TRUE, B_TRUE));
 619 }
 620 
 621 int
 622 brand_get_postinstall(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_POSTINSTALL, B_TRUE, B_TRUE));
 628 }
 629 
 630 int
 631 brand_get_postsnap(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_POSTSNAP, B_TRUE, B_TRUE));
 637 }
 638 
 639 int
 640 brand_get_poststatechange(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_POSTSTATECHG, B_TRUE, B_TRUE));
 646 }
 647 
 648 int
 649 brand_get_predetach(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_PREDETACH, B_TRUE, B_TRUE));
 655 }
 656 
 657 int
 658 brand_get_presnap(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_PRESNAP, B_TRUE, B_TRUE));
 664 }
 665 
 666 int
 667 brand_get_prestatechange(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_PRESTATECHG, B_TRUE, B_TRUE));
 673 }
 674 
 675 int
 676 brand_get_preuninstall(brand_handle_t bh, const char *zonename,
 677     const char *zonepath, char *buf, size_t len)
 678 {
 679         struct brand_handle *bhp = (struct brand_handle *)bh;
 680         return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
 681             buf, len, DTD_ELEM_PREUNINSTALL, B_TRUE, B_TRUE));
 682 }
 683 
 684 int
 685 brand_get_query(brand_handle_t bh, const char *zonename,
 686     const char *zonepath, char *buf, size_t len)
 687 {
 688         struct brand_handle *bhp = (struct brand_handle *)bh;
 689         return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
 690             buf, len, DTD_ELEM_QUERY, B_TRUE, B_TRUE));
 691 }
 692 
 693 int
 694 brand_get_uninstall(brand_handle_t bh, const char *zonename,
 695     const char *zonepath, char *buf, size_t len)
 696 {
 697         struct brand_handle *bhp = (struct brand_handle *)bh;
 698         return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
 699             buf, len, DTD_ELEM_UNINSTALL, B_TRUE, B_TRUE));
 700 }
 701 
 702 int
 703 brand_get_validatesnap(brand_handle_t bh, const char *zonename,
 704     const char *zonepath, char *buf, size_t len)
 705 {
 706         struct brand_handle *bhp = (struct brand_handle *)bh;
 707         return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
 708             buf, len, DTD_ELEM_VALIDSNAP, B_TRUE, B_TRUE));
 709 }
 710 
 711 int
 712 brand_get_verify_cfg(brand_handle_t bh, char *buf, size_t len)
 713 {
 714         struct brand_handle *bhp = (struct brand_handle *)bh;
 715         return (brand_get_value(bhp, NULL, NULL, NULL, NULL,
 716             buf, len, DTD_ELEM_VERIFY_CFG, B_FALSE, B_TRUE));
 717 }
 718 
 719 int
 720 brand_get_verify_adm(brand_handle_t bh, const char *zonename,
 721     const char *zonepath, char *buf, size_t len)
 722 {
 723         struct brand_handle *bhp = (struct brand_handle *)bh;
 724         return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
 725             buf, len, DTD_ELEM_VERIFY_ADM, B_TRUE, B_TRUE));
 726 }
 727 
 728 int
 729 brand_get_sysboot(brand_handle_t bh, const char *zonename,
 730     const char *zonepath, char *buf, size_t len)
 731 {
 732         struct brand_handle *bhp = (struct brand_handle *)bh;
 733         return (brand_get_value(bhp, zonename, zonepath, NULL, NULL,
 734             buf, len, DTD_ELEM_SYSBOOT, B_TRUE, B_TRUE));
 735 }
 736 
 737 boolean_t
 738 brand_allow_exclusive_ip(brand_handle_t bh)
 739 {
 740         struct brand_handle     *bhp = (struct brand_handle *)bh;
 741         xmlNodePtr              node;
 742         xmlChar                 *allow_excl;
 743         boolean_t               ret;
 744 
 745         assert(bhp != NULL);
 746 
 747         if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL)
 748                 return (B_FALSE);
 749 
 750         allow_excl = xmlGetProp(node, DTD_ATTR_ALLOWEXCL);
 751         if (allow_excl == NULL)
 752                 return (B_FALSE);
 753 
 754         /* Note: only return B_TRUE if it's "true" */
 755         if (strcmp((char *)allow_excl, DTD_ENTITY_TRUE) == 0)
 756                 ret = B_TRUE;
 757         else
 758                 ret = B_FALSE;
 759 
 760         xmlFree(allow_excl);
 761 
 762         return (ret);
 763 }
 764 
 765 /*
 766  * Iterate over brand privileges
 767  *
 768  * Walks the brand config, searching for <privilege> elements, calling the
 769  * specified callback for each.  Returns 0 on success, or -1 on failure.
 770  */
 771 int
 772 brand_config_iter_privilege(brand_handle_t bh,
 773     int (*func)(void *, priv_iter_t *), void *data)
 774 {
 775         struct brand_handle     *bhp = (struct brand_handle *)bh;
 776         xmlNodePtr              node;
 777         xmlChar                 *name, *set, *iptype;
 778         priv_iter_t             priv_iter;
 779         int                     ret;
 780 
 781         if ((node = xmlDocGetRootElement(bhp->bh_config)) == NULL)
 782                 return (-1);
 783 
 784         for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
 785 
 786                 if (xmlStrcmp(node->name, DTD_ELEM_PRIVILEGE) != 0)
 787                         continue;
 788 
 789                 name = xmlGetProp(node, DTD_ATTR_NAME);
 790                 set = xmlGetProp(node, DTD_ATTR_SET);
 791                 iptype = xmlGetProp(node, DTD_ATTR_IPTYPE);
 792 
 793                 if (name == NULL || set == NULL || iptype == NULL) {
 794                         if (name != NULL)
 795                                 xmlFree(name);
 796                         if (set != NULL)
 797                                 xmlFree(set);
 798                         if (iptype != NULL)
 799                                 xmlFree(iptype);
 800                         return (-1);
 801                 }
 802 
 803                 priv_iter.pi_name = (char *)name;
 804                 priv_iter.pi_set = (char *)set;
 805                 priv_iter.pi_iptype = (char *)iptype;
 806 
 807                 ret = func(data, &priv_iter);
 808 
 809                 xmlFree(name);
 810                 xmlFree(set);
 811                 xmlFree(iptype);
 812 
 813                 if (ret != 0)
 814                         return (-1);
 815         }
 816 
 817         return (0);
 818 }
 819 
 820 static int
 821 i_brand_platform_iter_mounts(struct brand_handle *bhp, const char *zonename,
 822     const char *zonepath, int (*func)(void *, const char *, const char *,
 823     const char *, const char *), void *data, const xmlChar *mount_type)
 824 {
 825         xmlNodePtr node;
 826         xmlChar *special, *dir, *type, *opt;
 827         char special_exp[MAXPATHLEN];
 828         char dir_exp[MAXPATHLEN];
 829         char opt_exp[MAXPATHLEN];
 830         int ret;
 831 
 832         if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL)
 833                 return (-1);
 834 
 835         for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
 836 
 837                 if (xmlStrcmp(node->name, mount_type) != 0)
 838                         continue;
 839 
 840                 special = xmlGetProp(node, DTD_ATTR_SPECIAL);
 841                 dir = xmlGetProp(node, DTD_ATTR_DIRECTORY);
 842                 type = xmlGetProp(node, DTD_ATTR_TYPE);
 843                 opt = xmlGetProp(node, DTD_ATTR_OPT);
 844                 if ((special == NULL) || (dir == NULL) || (type == NULL) ||
 845                     (opt == NULL)) {
 846                         ret = -1;
 847                         goto next;
 848                 }
 849 
 850                 /* Substitute token values as needed. */
 851                 if ((ret = i_substitute_tokens((char *)special,
 852                     special_exp, sizeof (special_exp),
 853                     zonename, zonepath, NULL, NULL)) != 0)
 854                         goto next;
 855                 if ((ret = i_substitute_tokens((char *)dir,
 856                     dir_exp, sizeof (dir_exp),
 857                     zonename, zonepath, NULL, NULL)) != 0)
 858                         goto next;
 859 
 860                 /* opt might not be defined */
 861                 if (strlen((const char *)opt) == 0) {
 862                         xmlFree(opt);
 863                         opt = NULL;
 864                 } else {
 865                         if ((ret = i_substitute_tokens((char *)opt,
 866                             opt_exp, sizeof (opt_exp),
 867                             zonename, zonepath, NULL, NULL)) != 0)
 868                                 goto next;
 869                 }
 870 
 871                 ret = func(data, (char *)special_exp, (char *)dir_exp,
 872                     (char *)type, ((opt != NULL) ? opt_exp : NULL));
 873 
 874 next:
 875                 if (special != NULL)
 876                         xmlFree(special);
 877                 if (dir != NULL)
 878                         xmlFree(dir);
 879                 if (type != NULL)
 880                         xmlFree(type);
 881                 if (opt != NULL)
 882                         xmlFree(opt);
 883                 if (ret != 0)
 884                         return (-1);
 885         }
 886         return (0);
 887 }
 888 
 889 
 890 /*
 891  * Iterate over global platform filesystems
 892  *
 893  * Walks the platform, searching for <global_mount> elements, calling the
 894  * specified callback for each.  Returns 0 on success, or -1 on failure.
 895  *
 896  * Perform the following substitutions as necessary:
 897  *
 898  *      %R      Zonepath of zone
 899  */
 900 int
 901 brand_platform_iter_gmounts(brand_handle_t bh, const char *zonename,
 902     const char *zonepath, int (*func)(void *, const char *, const char *,
 903     const char *, const char *), void *data)
 904 {
 905         struct brand_handle *bhp = (struct brand_handle *)bh;
 906         return (i_brand_platform_iter_mounts(bhp, zonename, zonepath, func,
 907             data, DTD_ELEM_GLOBAL_MOUNT));
 908 }
 909 
 910 /*
 911  * Iterate over non-global zone platform filesystems
 912  *
 913  * Walks the platform, searching for <mount> elements, calling the
 914  * specified callback for each.  Returns 0 on success, or -1 on failure.
 915  */
 916 int
 917 brand_platform_iter_mounts(brand_handle_t bh, int (*func)(void *,
 918     const char *, const char *, const char *, const char *), void *data)
 919 {
 920         struct brand_handle *bhp = (struct brand_handle *)bh;
 921         return (i_brand_platform_iter_mounts(bhp, NULL, NULL, func, data,
 922             DTD_ELEM_MOUNT));
 923 }
 924 
 925 /*
 926  * Iterate over platform symlinks
 927  *
 928  * Walks the platform, searching for <symlink> elements, calling the
 929  * specified callback for each.  Returns 0 on success, or -1 on failure.
 930  */
 931 int
 932 brand_platform_iter_link(brand_handle_t bh,
 933     int (*func)(void *, const char *, const char *), void *data)
 934 {
 935         struct brand_handle *bhp = (struct brand_handle *)bh;
 936         xmlNodePtr node;
 937         xmlChar *source, *target;
 938         int ret;
 939 
 940         if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL)
 941                 return (-1);
 942 
 943         for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
 944 
 945                 if (xmlStrcmp(node->name, DTD_ELEM_SYMLINK) != 0)
 946                         continue;
 947 
 948                 source = xmlGetProp(node, DTD_ATTR_SOURCE);
 949                 target = xmlGetProp(node, DTD_ATTR_TARGET);
 950 
 951                 if (source == NULL || target == NULL) {
 952                         if (source != NULL)
 953                                 xmlFree(source);
 954                         if (target != NULL)
 955                                 xmlFree(target);
 956                         return (-1);
 957                 }
 958 
 959                 ret = func(data, (char *)source, (char *)target);
 960 
 961                 xmlFree(source);
 962                 xmlFree(target);
 963 
 964                 if (ret != 0)
 965                         return (-1);
 966         }
 967 
 968         return (0);
 969 }
 970 
 971 /*
 972  * Iterate over platform devices
 973  *
 974  * Walks the platform, searching for <device> elements, calling the
 975  * specified callback for each.  Returns 0 on success, or -1 on failure.
 976  */
 977 int
 978 brand_platform_iter_devices(brand_handle_t bh, const char *zonename,
 979     int (*func)(void *, const char *, const char *), void *data,
 980     const char *curr_iptype)
 981 {
 982         struct brand_handle     *bhp = (struct brand_handle *)bh;
 983         const char              *curr_arch = get_curr_arch();
 984         xmlNodePtr              node;
 985         xmlChar                 *match, *name, *arch, *iptype;
 986         char                    match_exp[MAXPATHLEN];
 987         boolean_t               err = B_FALSE;
 988         int                     ret = 0;
 989 
 990 
 991         assert(bhp != NULL);
 992         assert(zonename != NULL);
 993         assert(func != NULL);
 994         assert(curr_iptype != NULL);
 995 
 996         if ((node = xmlDocGetRootElement(bhp->bh_platform)) == NULL)
 997                 return (-1);
 998 
 999         for (node = node->xmlChildrenNode; node != NULL; node = node->next) {
1000 
1001                 if (xmlStrcmp(node->name, DTD_ELEM_DEVICE) != 0)
1002                         continue;
1003 
1004                 match = xmlGetProp(node, DTD_ATTR_MATCH);
1005                 name = xmlGetProp(node, DTD_ATTR_NAME);
1006                 arch = xmlGetProp(node, DTD_ATTR_ARCH);
1007                 iptype = xmlGetProp(node, DTD_ATTR_IPTYPE);
1008                 if ((match == NULL) || (name == NULL) || (arch == NULL) ||
1009                     (iptype == NULL)) {
1010                         err = B_TRUE;
1011                         goto next;
1012                 }
1013 
1014                 /* check if the arch matches */
1015                 if ((strcmp((char *)arch, "all") != 0) &&
1016                     (strcmp((char *)arch, curr_arch) != 0))
1017                         goto next;
1018 
1019                 /* check if the iptype matches */
1020                 if ((strcmp((char *)iptype, "all") != 0) &&
1021                     (strcmp((char *)iptype, curr_iptype) != 0))
1022                         goto next;
1023 
1024                 /* Substitute token values as needed. */
1025                 if ((ret = i_substitute_tokens((char *)match,
1026                     match_exp, sizeof (match_exp),
1027                     zonename, NULL, NULL, NULL)) != 0) {
1028                         err = B_TRUE;
1029                         goto next;
1030                 }
1031 
1032                 /* name might not be defined */
1033                 if (strlen((const char *)name) == 0) {
1034                         xmlFree(name);
1035                         name = NULL;
1036                 }
1037 
1038                 /* invoke the callback */
1039                 ret = func(data, (const char *)match_exp, (const char *)name);
1040 
1041 next:
1042                 if (match != NULL)
1043                         xmlFree(match);
1044                 if (name != NULL)
1045                         xmlFree(name);
1046                 if (arch != NULL)
1047                         xmlFree(arch);
1048                 if (iptype != NULL)
1049                         xmlFree(iptype);
1050                 if (err)
1051                         return (-1);
1052                 if (ret != 0)
1053                         return (-1);
1054         }
1055 
1056         return (0);
1057 }