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 2014 Gary Mills
  24  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  25  * Copyright (c) 2018, Joyent, Inc.
  26  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
  27  */
  28 
  29 #include <libsysevent.h>
  30 #include <pthread.h>
  31 #include <stdlib.h>
  32 #include <errno.h>
  33 #include <fnmatch.h>
  34 #include <strings.h>
  35 #include <unistd.h>
  36 #include <assert.h>
  37 #include <libgen.h>
  38 #include <libintl.h>
  39 #include <alloca.h>
  40 #include <ctype.h>
  41 #include <sys/acl.h>
  42 #include <sys/stat.h>
  43 #include <sys/brand.h>
  44 #include <sys/mntio.h>
  45 #include <sys/mnttab.h>
  46 #include <sys/nvpair.h>
  47 #include <sys/types.h>
  48 #include <sys/sockio.h>
  49 #include <sys/systeminfo.h>
  50 #include <ftw.h>
  51 #include <pool.h>
  52 #include <libscf.h>
  53 #include <libproc.h>
  54 #include <sys/priocntl.h>
  55 #include <libuutil.h>
  56 #include <wait.h>
  57 #include <bsm/adt.h>
  58 #include <auth_attr.h>
  59 #include <auth_list.h>
  60 #include <secdb.h>
  61 #include <user_attr.h>
  62 #include <prof_attr.h>
  63 
  64 #include <arpa/inet.h>
  65 #include <netdb.h>
  66 
  67 #include <libxml/xmlmemory.h>
  68 #include <libxml/parser.h>
  69 
  70 #include <libdevinfo.h>
  71 #include <uuid/uuid.h>
  72 #include <dirent.h>
  73 #include <libbrand.h>
  74 
  75 #include <libzonecfg.h>
  76 #include "zonecfg_impl.h"
  77 
  78 #define _PATH_TMPFILE   "/zonecfg.XXXXXX"
  79 #define ZONE_CB_RETRY_COUNT             10
  80 #define ZONE_EVENT_PING_SUBCLASS        "ping"
  81 #define ZONE_EVENT_PING_PUBLISHER       "solaris"
  82 
  83 #define DEBUGID_FILE    "/etc/zones/did.txt"
  84 
  85 /* Hard-code the DTD element/attribute/entity names just once, here. */
  86 #define DTD_ELEM_ATTR           (const xmlChar *) "attr"
  87 #define DTD_ELEM_COMMENT        (const xmlChar *) "comment"
  88 #define DTD_ELEM_DEVICE         (const xmlChar *) "device"
  89 #define DTD_ELEM_FS             (const xmlChar *) "filesystem"
  90 #define DTD_ELEM_FSOPTION       (const xmlChar *) "fsoption"
  91 #define DTD_ELEM_NET            (const xmlChar *) "network"
  92 #define DTD_ELEM_RCTL           (const xmlChar *) "rctl"
  93 #define DTD_ELEM_RCTLVALUE      (const xmlChar *) "rctl-value"
  94 #define DTD_ELEM_ZONE           (const xmlChar *) "zone"
  95 #define DTD_ELEM_DATASET        (const xmlChar *) "dataset"
  96 #define DTD_ELEM_TMPPOOL        (const xmlChar *) "tmp_pool"
  97 #define DTD_ELEM_PSET           (const xmlChar *) "pset"
  98 #define DTD_ELEM_MCAP           (const xmlChar *) "mcap"
  99 #define DTD_ELEM_PACKAGE        (const xmlChar *) "package"
 100 #define DTD_ELEM_OBSOLETES      (const xmlChar *) "obsoletes"
 101 #define DTD_ELEM_DEV_PERM       (const xmlChar *) "dev-perm"
 102 #define DTD_ELEM_ADMIN          (const xmlChar *) "admin"
 103 #define DTD_ELEM_SECFLAGS       (const xmlChar *) "security-flags"
 104 
 105 #define DTD_ATTR_ACTION         (const xmlChar *) "action"
 106 #define DTD_ATTR_ADDRESS        (const xmlChar *) "address"
 107 #define DTD_ATTR_ALLOWED_ADDRESS        (const xmlChar *) "allowed-address"
 108 #define DTD_ATTR_AUTOBOOT       (const xmlChar *) "autoboot"
 109 #define DTD_ATTR_IPTYPE         (const xmlChar *) "ip-type"
 110 #define DTD_ATTR_DEFROUTER      (const xmlChar *) "defrouter"
 111 #define DTD_ATTR_DIR            (const xmlChar *) "directory"
 112 #define DTD_ATTR_LIMIT          (const xmlChar *) "limit"
 113 #define DTD_ATTR_LIMITPRIV      (const xmlChar *) "limitpriv"
 114 #define DTD_ATTR_BOOTARGS       (const xmlChar *) "bootargs"
 115 #define DTD_ATTR_SCHED          (const xmlChar *) "scheduling-class"
 116 #define DTD_ATTR_MATCH          (const xmlChar *) "match"
 117 #define DTD_ATTR_NAME           (const xmlChar *) "name"
 118 #define DTD_ATTR_PHYSICAL       (const xmlChar *) "physical"
 119 #define DTD_ATTR_POOL           (const xmlChar *) "pool"
 120 #define DTD_ATTR_PRIV           (const xmlChar *) "priv"
 121 #define DTD_ATTR_RAW            (const xmlChar *) "raw"
 122 #define DTD_ATTR_SPECIAL        (const xmlChar *) "special"
 123 #define DTD_ATTR_TYPE           (const xmlChar *) "type"
 124 #define DTD_ATTR_VALUE          (const xmlChar *) "value"
 125 #define DTD_ATTR_ZONEPATH       (const xmlChar *) "zonepath"
 126 #define DTD_ATTR_NCPU_MIN       (const xmlChar *) "ncpu_min"
 127 #define DTD_ATTR_NCPU_MAX       (const xmlChar *) "ncpu_max"
 128 #define DTD_ATTR_IMPORTANCE     (const xmlChar *) "importance"
 129 #define DTD_ATTR_PHYSCAP        (const xmlChar *) "physcap"
 130 #define DTD_ATTR_VERSION        (const xmlChar *) "version"
 131 #define DTD_ATTR_ID             (const xmlChar *) "id"
 132 #define DTD_ATTR_UID            (const xmlChar *) "uid"
 133 #define DTD_ATTR_GID            (const xmlChar *) "gid"
 134 #define DTD_ATTR_MODE           (const xmlChar *) "mode"
 135 #define DTD_ATTR_ACL            (const xmlChar *) "acl"
 136 #define DTD_ATTR_BRAND          (const xmlChar *) "brand"
 137 #define DTD_ATTR_DID            (const xmlChar *) "debugid"
 138 #define DTD_ATTR_HOSTID         (const xmlChar *) "hostid"
 139 #define DTD_ATTR_USER           (const xmlChar *) "user"
 140 #define DTD_ATTR_AUTHS          (const xmlChar *) "auths"
 141 #define DTD_ATTR_FS_ALLOWED     (const xmlChar *) "fs-allowed"
 142 #define DTD_ATTR_DEFAULT        (const xmlChar *) "default"
 143 #define DTD_ATTR_LOWER          (const xmlChar *) "lower"
 144 #define DTD_ATTR_UPPER          (const xmlChar *) "upper"
 145 
 146 
 147 #define DTD_ENTITY_BOOLEAN      "boolean"
 148 #define DTD_ENTITY_DEVPATH      "devpath"
 149 #define DTD_ENTITY_DRIVER       "driver"
 150 #define DTD_ENTITY_DRVMIN       "drv_min"
 151 #define DTD_ENTITY_FALSE        "false"
 152 #define DTD_ENTITY_INT          "int"
 153 #define DTD_ENTITY_STRING       "string"
 154 #define DTD_ENTITY_TRUE         "true"
 155 #define DTD_ENTITY_UINT         "uint"
 156 
 157 #define DTD_ENTITY_BOOL_LEN     6       /* "false" */
 158 
 159 #define ATTACH_FORCED   "SUNWattached.xml"
 160 
 161 #define TMP_POOL_NAME   "SUNWtmp_%s"
 162 #define MAX_TMP_POOL_NAME       (ZONENAME_MAX + 9)
 163 #define RCAP_SERVICE    "system/rcap:default"
 164 #define POOLD_SERVICE   "system/pools/dynamic:default"
 165 
 166 /*
 167  * rctl alias definitions
 168  *
 169  * This holds the alias, the full rctl name, the default priv value, action
 170  * and lower limit.  The functions that handle rctl aliases step through
 171  * this table, matching on the alias, and using the full values for setting
 172  * the rctl entry as well the limit for validation.
 173  */
 174 static struct alias {
 175         char *shortname;
 176         char *realname;
 177         char *priv;
 178         char *action;
 179         uint64_t low_limit;
 180 } aliases[] = {
 181         {ALIAS_MAXLWPS, "zone.max-lwps", "privileged", "deny", 100},
 182         {ALIAS_MAXSHMMEM, "zone.max-shm-memory", "privileged", "deny", 0},
 183         {ALIAS_MAXSHMIDS, "zone.max-shm-ids", "privileged", "deny", 0},
 184         {ALIAS_MAXMSGIDS, "zone.max-msg-ids", "privileged", "deny", 0},
 185         {ALIAS_MAXSEMIDS, "zone.max-sem-ids", "privileged", "deny", 0},
 186         {ALIAS_MAXLOCKEDMEM, "zone.max-locked-memory", "privileged", "deny", 0},
 187         {ALIAS_MAXSWAP, "zone.max-swap", "privileged", "deny", 0},
 188         {ALIAS_SHARES, "zone.cpu-shares", "privileged", "none", 0},
 189         {ALIAS_CPUCAP, "zone.cpu-cap", "privileged", "deny", 0},
 190         {ALIAS_MAXPROCS, "zone.max-processes", "privileged", "deny", 100},
 191         {NULL, NULL, NULL, NULL, 0}
 192 };
 193 
 194 /*
 195  * Structure for applying rctls to a running zone.  It allows important
 196  * process values to be passed together easily.
 197  */
 198 typedef struct pr_info_handle {
 199         struct ps_prochandle *pr;
 200         pid_t pid;
 201 } pr_info_handle_t;
 202 
 203 struct zone_dochandle {
 204         char            *zone_dh_rootdir;
 205         xmlDocPtr       zone_dh_doc;
 206         xmlNodePtr      zone_dh_cur;
 207         xmlNodePtr      zone_dh_top;
 208         boolean_t       zone_dh_newzone;
 209         boolean_t       zone_dh_snapshot;
 210         boolean_t       zone_dh_sw_inv;
 211         zone_userauths_t        *zone_dh_userauths;
 212         char            zone_dh_delete_name[ZONENAME_MAX];
 213 };
 214 
 215 struct znotify {
 216         void * zn_private;
 217         evchan_t *zn_eventchan;
 218         int (*zn_callback)(const  char *zonename, zoneid_t zid,
 219             const char *newstate, const char *oldstate, hrtime_t when, void *p);
 220         pthread_mutex_t zn_mutex;
 221         pthread_cond_t zn_cond;
 222         pthread_mutex_t zn_bigmutex;
 223         volatile enum {ZN_UNLOCKED, ZN_LOCKED, ZN_PING_INFLIGHT,
 224             ZN_PING_RECEIVED} zn_state;
 225         char zn_subscriber_id[MAX_SUBID_LEN];
 226         volatile boolean_t zn_failed;
 227         int zn_failure_count;
 228 };
 229 
 230 /* used to track nested zone-lock operations */
 231 static int zone_lock_cnt = 0;
 232 
 233 /* used to communicate lock status to children */
 234 #define LOCK_ENV_VAR    "_ZONEADM_LOCK_HELD"
 235 static char zoneadm_lock_held[] = LOCK_ENV_VAR"=1";
 236 static char zoneadm_lock_not_held[] = LOCK_ENV_VAR"=0";
 237 
 238 char *zonecfg_root = "";
 239 
 240 /*
 241  * For functions which return int, which is most of the functions herein,
 242  * the return values should be from the Z_foo set defined in <libzonecfg.h>.
 243  * In some instances, we take pains mapping some libc errno values to Z_foo
 244  * values from this set.
 245  */
 246 
 247 /*
 248  * Set the root (/) path for all zonecfg configuration files.  This is a
 249  * private interface used by Live Upgrade extensions to access zone
 250  * configuration inside mounted alternate boot environments.
 251  * This interface is also used by zoneadm mount and unmount subcommands.
 252  */
 253 void
 254 zonecfg_set_root(const char *rootpath)
 255 {
 256         if (*zonecfg_root != '\0')
 257                 free(zonecfg_root);
 258         if (rootpath == NULL || rootpath[0] == '\0' || rootpath[1] == '\0' ||
 259             (zonecfg_root = strdup(rootpath)) == NULL)
 260                 zonecfg_root = "";
 261 }
 262 
 263 const char *
 264 zonecfg_get_root(void)
 265 {
 266         return (zonecfg_root);
 267 }
 268 
 269 boolean_t
 270 zonecfg_in_alt_root(void)
 271 {
 272         return (*zonecfg_root != '\0');
 273 }
 274 
 275 /*
 276  * Callers of the _file_path() functions are expected to have the second
 277  * parameter be a (char foo[MAXPATHLEN]).
 278  */
 279 
 280 static boolean_t
 281 config_file_path(const char *zonename, char *answer)
 282 {
 283         return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root,
 284             ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN);
 285 }
 286 
 287 static boolean_t
 288 snap_file_path(const char *zonename, char *answer)
 289 {
 290         return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml",
 291             zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN);
 292 }
 293 
 294 /*ARGSUSED*/
 295 static void
 296 zonecfg_error_func(void *ctx, const char *msg, ...)
 297 {
 298         /*
 299          * This function does nothing by design.  Its purpose is to prevent
 300          * libxml from dumping unwanted messages to stdout/stderr.
 301          */
 302 }
 303 
 304 zone_dochandle_t
 305 zonecfg_init_handle(void)
 306 {
 307         zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle));
 308         if (handle == NULL) {
 309                 errno = Z_NOMEM;
 310                 return (NULL);
 311         }
 312 
 313         /* generic libxml initialization */
 314         (void) xmlLineNumbersDefault(1);
 315         xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
 316         xmlDoValidityCheckingDefaultValue = 1;
 317         (void) xmlKeepBlanksDefault(0);
 318         xmlGetWarningsDefaultValue = 0;
 319         xmlSetGenericErrorFunc(NULL, zonecfg_error_func);
 320 
 321         return (handle);
 322 }
 323 
 324 int
 325 zonecfg_check_handle(zone_dochandle_t handle)
 326 {
 327         if (handle == NULL || handle->zone_dh_doc == NULL)
 328                 return (Z_BAD_HANDLE);
 329         return (Z_OK);
 330 }
 331 
 332 void
 333 zonecfg_fini_handle(zone_dochandle_t handle)
 334 {
 335         if (zonecfg_check_handle(handle) == Z_OK)
 336                 xmlFreeDoc(handle->zone_dh_doc);
 337         if (handle != NULL)
 338                 free(handle);
 339 }
 340 
 341 static int
 342 zonecfg_destroy_impl(char *filename)
 343 {
 344         if (unlink(filename) == -1) {
 345                 if (errno == EACCES)
 346                         return (Z_ACCES);
 347                 if (errno == ENOENT)
 348                         return (Z_NO_ZONE);
 349                 return (Z_MISC_FS);
 350         }
 351         return (Z_OK);
 352 }
 353 
 354 int
 355 zonecfg_destroy(const char *zonename, boolean_t force)
 356 {
 357         char path[MAXPATHLEN];
 358         struct zoneent ze;
 359         int err, state_err;
 360         zone_state_t state;
 361 
 362         if (!config_file_path(zonename, path))
 363                 return (Z_MISC_FS);
 364 
 365         state_err = zone_get_state((char *)zonename, &state);
 366         err = access(path, W_OK);
 367 
 368         /*
 369          * If there is no file, and no index entry, reliably indicate that no
 370          * such zone exists.
 371          */
 372         if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT))
 373                 return (Z_NO_ZONE);
 374 
 375         /*
 376          * Handle any other filesystem related errors (except if the XML
 377          * file is missing, which we treat silently), unless we're forcing,
 378          * in which case we plow on.
 379          */
 380         if (err == -1 && errno != ENOENT) {
 381                 if (errno == EACCES)
 382                         return (Z_ACCES);
 383                 else if (!force)
 384                         return (Z_MISC_FS);
 385         }
 386 
 387         if (state > ZONE_STATE_INSTALLED)
 388                 return (Z_BAD_ZONE_STATE);
 389 
 390         if (!force && state > ZONE_STATE_CONFIGURED)
 391                 return (Z_BAD_ZONE_STATE);
 392 
 393         /*
 394          * Index deletion succeeds even if the entry doesn't exist.  So this
 395          * will fail only if we've had some more severe problem.
 396          */
 397         bzero(&ze, sizeof (ze));
 398         (void) strlcpy(ze.zone_name, zonename, sizeof (ze.zone_name));
 399         if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK)
 400                 if (!force)
 401                         return (err);
 402 
 403         err = zonecfg_destroy_impl(path);
 404 
 405         /*
 406          * Treat failure to find the XML file silently, since, well, it's
 407          * gone, and with the index file cleaned up, we're done.
 408          */
 409         if (err == Z_OK || err == Z_NO_ZONE)
 410                 return (Z_OK);
 411         return (err);
 412 }
 413 
 414 int
 415 zonecfg_destroy_snapshot(const char *zonename)
 416 {
 417         char path[MAXPATHLEN];
 418 
 419         if (!snap_file_path(zonename, path))
 420                 return (Z_MISC_FS);
 421         return (zonecfg_destroy_impl(path));
 422 }
 423 
 424 static int
 425 getroot(zone_dochandle_t handle, xmlNodePtr *root)
 426 {
 427         if (zonecfg_check_handle(handle) == Z_BAD_HANDLE)
 428                 return (Z_BAD_HANDLE);
 429 
 430         *root = xmlDocGetRootElement(handle->zone_dh_doc);
 431 
 432         if (*root == NULL)
 433                 return (Z_EMPTY_DOCUMENT);
 434 
 435         if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE))
 436                 return (Z_WRONG_DOC_TYPE);
 437 
 438         return (Z_OK);
 439 }
 440 
 441 static int
 442 operation_prep(zone_dochandle_t handle)
 443 {
 444         xmlNodePtr root;
 445         int err;
 446 
 447         if ((err = getroot(handle, &root)) != 0)
 448                 return (err);
 449 
 450         handle->zone_dh_cur = root;
 451         handle->zone_dh_top = root;
 452         return (Z_OK);
 453 }
 454 
 455 static int
 456 fetchprop(xmlNodePtr cur, const xmlChar *propname, char *dst, size_t dstsize)
 457 {
 458         xmlChar *property;
 459         size_t srcsize;
 460 
 461         if ((property = xmlGetProp(cur, propname)) == NULL)
 462                 return (Z_BAD_PROPERTY);
 463         srcsize = strlcpy(dst, (char *)property, dstsize);
 464         xmlFree(property);
 465         if (srcsize >= dstsize)
 466                 return (Z_TOO_BIG);
 467         return (Z_OK);
 468 }
 469 
 470 static int
 471 fetch_alloc_prop(xmlNodePtr cur, const xmlChar *propname, char **dst)
 472 {
 473         xmlChar *property;
 474 
 475         if ((property = xmlGetProp(cur, propname)) == NULL)
 476                 return (Z_BAD_PROPERTY);
 477         if ((*dst = strdup((char *)property)) == NULL) {
 478                 xmlFree(property);
 479                 return (Z_NOMEM);
 480         }
 481         xmlFree(property);
 482         return (Z_OK);
 483 }
 484 
 485 static int
 486 getrootattr(zone_dochandle_t handle, const xmlChar *propname,
 487     char *propval, size_t propsize)
 488 {
 489         xmlNodePtr root;
 490         int err;
 491 
 492         if ((err = getroot(handle, &root)) != 0)
 493                 return (err);
 494 
 495         return (fetchprop(root, propname, propval, propsize));
 496 }
 497 
 498 static int
 499 get_alloc_rootattr(zone_dochandle_t handle, const xmlChar *propname,
 500     char **propval)
 501 {
 502         xmlNodePtr root;
 503         int err;
 504 
 505         if ((err = getroot(handle, &root)) != 0)
 506                 return (err);
 507 
 508         return (fetch_alloc_prop(root, propname, propval));
 509 }
 510 
 511 static int
 512 setrootattr(zone_dochandle_t handle, const xmlChar *propname,
 513     const char *propval)
 514 {
 515         int err;
 516         xmlNodePtr root;
 517 
 518         if ((err = getroot(handle, &root)) != Z_OK)
 519                 return (err);
 520 
 521         /*
 522          * If we get a null propval remove the property (ignore return since it
 523          * may not be set to begin with).
 524          */
 525         if (propval == NULL) {
 526                 (void) xmlUnsetProp(root, propname);
 527         } else {
 528                 if (xmlSetProp(root, propname, (const xmlChar *) propval)
 529                     == NULL)
 530                         return (Z_INVAL);
 531         }
 532         return (Z_OK);
 533 }
 534 
 535 static void
 536 addcomment(zone_dochandle_t handle, const char *comment)
 537 {
 538         xmlNodePtr node;
 539         node = xmlNewComment((xmlChar *) comment);
 540 
 541         if (node != NULL)
 542                 (void) xmlAddPrevSibling(handle->zone_dh_top, node);
 543 }
 544 
 545 static void
 546 stripcomments(zone_dochandle_t handle)
 547 {
 548         xmlDocPtr top;
 549         xmlNodePtr child, next;
 550 
 551         top = handle->zone_dh_doc;
 552         for (child = top->xmlChildrenNode; child != NULL; child = next) {
 553                 next = child->next;
 554                 if (child->name == NULL)
 555                         continue;
 556                 if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) {
 557                         next = child->next;
 558                         xmlUnlinkNode(child);
 559                         xmlFreeNode(child);
 560                 }
 561         }
 562 }
 563 
 564 static void
 565 strip_sw_inv(zone_dochandle_t handle)
 566 {
 567         xmlNodePtr root, child, next;
 568 
 569         root = xmlDocGetRootElement(handle->zone_dh_doc);
 570         for (child = root->xmlChildrenNode; child != NULL; child = next) {
 571                 next = child->next;
 572                 if (child->name == NULL)
 573                         continue;
 574                 if (xmlStrcmp(child->name, DTD_ELEM_PACKAGE) == 0) {
 575                         next = child->next;
 576                         xmlUnlinkNode(child);
 577                         xmlFreeNode(child);
 578                 }
 579         }
 580 }
 581 
 582 static int
 583 zonecfg_get_handle_impl(const char *zonename, const char *filename,
 584     zone_dochandle_t handle)
 585 {
 586         xmlValidCtxtPtr cvp;
 587         struct stat statbuf;
 588         int valid;
 589 
 590         if (zonename == NULL)
 591                 return (Z_NO_ZONE);
 592 
 593         if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) {
 594                 /* distinguish file not found vs. found but not parsed */
 595                 if (stat(filename, &statbuf) == 0)
 596                         return (Z_INVALID_DOCUMENT);
 597                 return (Z_NO_ZONE);
 598         }
 599         if ((cvp = xmlNewValidCtxt()) == NULL)
 600                 return (Z_NOMEM);
 601         cvp->error = zonecfg_error_func;
 602         cvp->warning = zonecfg_error_func;
 603         valid = xmlValidateDocument(cvp, handle->zone_dh_doc);
 604         xmlFreeValidCtxt(cvp);
 605         if (valid == 0)
 606                 return (Z_INVALID_DOCUMENT);
 607 
 608         /* delete any comments such as inherited Sun copyright / ident str */
 609         stripcomments(handle);
 610         return (Z_OK);
 611 }
 612 
 613 int
 614 zonecfg_get_handle(const char *zonename, zone_dochandle_t handle)
 615 {
 616         char path[MAXPATHLEN];
 617 
 618         if (!config_file_path(zonename, path))
 619                 return (Z_MISC_FS);
 620         handle->zone_dh_newzone = B_FALSE;
 621 
 622         return (zonecfg_get_handle_impl(zonename, path, handle));
 623 }
 624 
 625 int
 626 zonecfg_get_attach_handle(const char *path, const char *fname,
 627     const char *zonename, boolean_t preserve_sw, zone_dochandle_t handle)
 628 {
 629         char            migpath[MAXPATHLEN];
 630         int             err;
 631         struct stat     buf;
 632 
 633         if (snprintf(migpath, sizeof (migpath), "%s/root", path) >=
 634             sizeof (migpath))
 635                 return (Z_NOMEM);
 636 
 637         if (stat(migpath, &buf) == -1 || !S_ISDIR(buf.st_mode))
 638                 return (Z_NO_ZONE);
 639 
 640         if (snprintf(migpath, sizeof (migpath), "%s/%s", path, fname) >=
 641             sizeof (migpath))
 642                 return (Z_NOMEM);
 643 
 644         if ((err = zonecfg_get_handle_impl(zonename, migpath, handle)) != Z_OK)
 645                 return (err);
 646 
 647         if (!preserve_sw)
 648                 strip_sw_inv(handle);
 649 
 650         handle->zone_dh_newzone = B_TRUE;
 651         if ((err = setrootattr(handle, DTD_ATTR_ZONEPATH, path)) != Z_OK)
 652                 return (err);
 653 
 654         return (setrootattr(handle, DTD_ATTR_NAME, zonename));
 655 }
 656 
 657 int
 658 zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle)
 659 {
 660         char path[MAXPATHLEN];
 661 
 662         if (!snap_file_path(zonename, path))
 663                 return (Z_MISC_FS);
 664         handle->zone_dh_newzone = B_FALSE;
 665         return (zonecfg_get_handle_impl(zonename, path, handle));
 666 }
 667 
 668 int
 669 zonecfg_get_template_handle(const char *template, const char *zonename,
 670     zone_dochandle_t handle)
 671 {
 672         char path[MAXPATHLEN];
 673         int err;
 674 
 675         if (!config_file_path(template, path))
 676                 return (Z_MISC_FS);
 677 
 678         if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK)
 679                 return (err);
 680         handle->zone_dh_newzone = B_TRUE;
 681         return (setrootattr(handle, DTD_ATTR_NAME, zonename));
 682 }
 683 
 684 int
 685 zonecfg_get_xml_handle(const char *path, zone_dochandle_t handle)
 686 {
 687         struct stat buf;
 688         int err;
 689 
 690         if (stat(path, &buf) == -1)
 691                 return (Z_MISC_FS);
 692 
 693         if ((err = zonecfg_get_handle_impl("xml", path, handle)) != Z_OK)
 694                 return (err);
 695         handle->zone_dh_newzone = B_TRUE;
 696         return (Z_OK);
 697 }
 698 
 699 /*
 700  * Initialize two handles from the manifest read on fd.  The rem_handle
 701  * is initialized from the input file, including the sw inventory.  The
 702  * local_handle is initialized with the same zone configuration but with
 703  * no sw inventory.
 704  */
 705 int
 706 zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle,
 707     zone_dochandle_t rem_handle)
 708 {
 709         xmlValidCtxtPtr cvp;
 710         int valid;
 711 
 712         /* load the manifest into the handle for the remote system */
 713         if ((rem_handle->zone_dh_doc = xmlReadFd(fd, NULL, NULL, 0)) == NULL) {
 714                 return (Z_INVALID_DOCUMENT);
 715         }
 716         if ((cvp = xmlNewValidCtxt()) == NULL)
 717                 return (Z_NOMEM);
 718         cvp->error = zonecfg_error_func;
 719         cvp->warning = zonecfg_error_func;
 720         valid = xmlValidateDocument(cvp, rem_handle->zone_dh_doc);
 721         xmlFreeValidCtxt(cvp);
 722         if (valid == 0)
 723                 return (Z_INVALID_DOCUMENT);
 724 
 725         /* delete any comments such as inherited Sun copyright / ident str */
 726         stripcomments(rem_handle);
 727 
 728         rem_handle->zone_dh_newzone = B_TRUE;
 729         rem_handle->zone_dh_sw_inv = B_TRUE;
 730 
 731         /*
 732          * Now use the remote system handle to generate a local system handle
 733          * with an identical zones configuration but no sw inventory.
 734          */
 735         if ((local_handle->zone_dh_doc = xmlCopyDoc(rem_handle->zone_dh_doc,
 736             1)) == NULL) {
 737                 return (Z_INVALID_DOCUMENT);
 738         }
 739 
 740         /*
 741          * We need to re-run xmlValidateDocument on local_handle to properly
 742          * update the in-core representation of the configuration.
 743          */
 744         if ((cvp = xmlNewValidCtxt()) == NULL)
 745                 return (Z_NOMEM);
 746         cvp->error = zonecfg_error_func;
 747         cvp->warning = zonecfg_error_func;
 748         valid = xmlValidateDocument(cvp, local_handle->zone_dh_doc);
 749         xmlFreeValidCtxt(cvp);
 750         if (valid == 0)
 751                 return (Z_INVALID_DOCUMENT);
 752 
 753         strip_sw_inv(local_handle);
 754 
 755         local_handle->zone_dh_newzone = B_TRUE;
 756         local_handle->zone_dh_sw_inv = B_FALSE;
 757 
 758         return (Z_OK);
 759 }
 760 
 761 static boolean_t
 762 is_renaming(zone_dochandle_t handle)
 763 {
 764         if (handle->zone_dh_newzone)
 765                 return (B_FALSE);
 766         if (strlen(handle->zone_dh_delete_name) > 0)
 767                 return (B_TRUE);
 768         return (B_FALSE);
 769 }
 770 
 771 static boolean_t
 772 is_new(zone_dochandle_t handle)
 773 {
 774         return (handle->zone_dh_newzone || handle->zone_dh_snapshot);
 775 }
 776 
 777 static boolean_t
 778 is_snapshot(zone_dochandle_t handle)
 779 {
 780         return (handle->zone_dh_snapshot);
 781 }
 782 
 783 /*
 784  * It would be great to be able to use libc's ctype(3c) macros, but we
 785  * can't, as they are locale sensitive, and it would break our limited thread
 786  * safety if this routine had to change the app locale on the fly.
 787  */
 788 int
 789 zonecfg_validate_zonename(const char *zone)
 790 {
 791         int i;
 792 
 793         if (strcmp(zone, GLOBAL_ZONENAME) == 0)
 794                 return (Z_BOGUS_ZONE_NAME);
 795 
 796         if (strlen(zone) >= ZONENAME_MAX)
 797                 return (Z_BOGUS_ZONE_NAME);
 798 
 799         if (!((zone[0] >= 'a' && zone[0] <= 'z') ||
 800             (zone[0] >= 'A' && zone[0] <= 'Z') ||
 801             (zone[0] >= '0' && zone[0] <= '9')))
 802                 return (Z_BOGUS_ZONE_NAME);
 803 
 804         for (i = 1; zone[i] != '\0'; i++) {
 805                 if (!((zone[i] >= 'a' && zone[i] <= 'z') ||
 806                     (zone[i] >= 'A' && zone[i] <= 'Z') ||
 807                     (zone[i] >= '0' && zone[i] <= '9') ||
 808                     (zone[i] == '-') || (zone[i] == '_') || (zone[i] == '.')))
 809                         return (Z_BOGUS_ZONE_NAME);
 810         }
 811 
 812         return (Z_OK);
 813 }
 814 
 815 /*
 816  * Changing the zone name requires us to track both the old and new
 817  * name of the zone until commit time.
 818  */
 819 int
 820 zonecfg_get_name(zone_dochandle_t handle, char *name, size_t namesize)
 821 {
 822         return (getrootattr(handle, DTD_ATTR_NAME, name, namesize));
 823 }
 824 
 825 static int
 826 insert_admins(zone_dochandle_t handle, char *zonename)
 827 {
 828         int err;
 829         struct zone_admintab admintab;
 830 
 831         if ((err = zonecfg_setadminent(handle)) != Z_OK) {
 832                 return (err);
 833         }
 834         while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
 835                 err = zonecfg_insert_userauths(handle,
 836                     admintab.zone_admin_user, zonename);
 837                 if (err != Z_OK) {
 838                         (void) zonecfg_endadminent(handle);
 839                         return (err);
 840                 }
 841         }
 842         (void) zonecfg_endadminent(handle);
 843         return (Z_OK);
 844 }
 845 
 846 int
 847 zonecfg_set_name(zone_dochandle_t handle, char *name)
 848 {
 849         zone_state_t state;
 850         char curname[ZONENAME_MAX], old_delname[ZONENAME_MAX];
 851         int err;
 852 
 853         if ((err = getrootattr(handle, DTD_ATTR_NAME, curname,
 854             sizeof (curname))) != Z_OK)
 855                 return (err);
 856 
 857         if (strcmp(name, curname) == 0)
 858                 return (Z_OK);
 859 
 860         /*
 861          * Switching zone names to one beginning with SUNW is not permitted.
 862          */
 863         if (strncmp(name, "SUNW", 4) == 0)
 864                 return (Z_BOGUS_ZONE_NAME);
 865 
 866         if ((err = zonecfg_validate_zonename(name)) != Z_OK)
 867                 return (err);
 868 
 869         /*
 870          * Setting the name back to the original name (effectively a revert of
 871          * the name) is fine.  But if we carry on, we'll falsely identify the
 872          * name as "in use," so special case here.
 873          */
 874         if (strcmp(name, handle->zone_dh_delete_name) == 0) {
 875                 err = setrootattr(handle, DTD_ATTR_NAME, name);
 876                 handle->zone_dh_delete_name[0] = '\0';
 877                 return (err);
 878         }
 879 
 880         /* Check to see if new name chosen is already in use */
 881         if (zone_get_state(name, &state) != Z_NO_ZONE)
 882                 return (Z_NAME_IN_USE);
 883 
 884         /*
 885          * If this isn't already "new" or in a renaming transition, then
 886          * we're initiating a rename here; so stash the "delete name"
 887          * (i.e. the name of the zone we'll be removing) for the rename.
 888          */
 889         (void) strlcpy(old_delname, handle->zone_dh_delete_name,
 890             sizeof (old_delname));
 891         if (!is_new(handle) && !is_renaming(handle)) {
 892                 /*
 893                  * Name change is allowed only when the zone we're altering
 894                  * is not ready or running.
 895                  */
 896                 err = zone_get_state(curname, &state);
 897                 if (err == Z_OK) {
 898                         if (state > ZONE_STATE_INSTALLED)
 899                                 return (Z_BAD_ZONE_STATE);
 900                 } else if (err != Z_NO_ZONE) {
 901                         return (err);
 902                 }
 903 
 904                 (void) strlcpy(handle->zone_dh_delete_name, curname,
 905                     sizeof (handle->zone_dh_delete_name));
 906                 assert(is_renaming(handle));
 907         } else if (is_renaming(handle)) {
 908                 err = zone_get_state(handle->zone_dh_delete_name, &state);
 909                 if (err == Z_OK) {
 910                         if (state > ZONE_STATE_INSTALLED)
 911                                 return (Z_BAD_ZONE_STATE);
 912                 } else if (err != Z_NO_ZONE) {
 913                         return (err);
 914                 }
 915         }
 916 
 917         if ((err = setrootattr(handle, DTD_ATTR_NAME, name)) != Z_OK) {
 918                 /*
 919                  * Restore the deletename to whatever it was at the
 920                  * top of the routine, since we've had a failure.
 921                  */
 922                 (void) strlcpy(handle->zone_dh_delete_name, old_delname,
 923                     sizeof (handle->zone_dh_delete_name));
 924                 return (err);
 925         }
 926 
 927         /*
 928          * Record the old admins from the old zonename
 929          * so that they can be deleted when the operation is committed.
 930          */
 931         if ((err = insert_admins(handle, curname)) != Z_OK)
 932                 return (err);
 933         else
 934                 return (Z_OK);
 935 }
 936 
 937 int
 938 zonecfg_get_zonepath(zone_dochandle_t handle, char *path, size_t pathsize)
 939 {
 940         size_t len;
 941 
 942         if ((len = strlcpy(path, zonecfg_root, pathsize)) >= pathsize)
 943                 return (Z_TOO_BIG);
 944         return (getrootattr(handle, DTD_ATTR_ZONEPATH, path + len,
 945             pathsize - len));
 946 }
 947 
 948 int
 949 zonecfg_set_zonepath(zone_dochandle_t handle, char *zonepath)
 950 {
 951         size_t len;
 952         char *modpath, *copy_mp, *curr_mp;      /* modified path ptrs */
 953         char last_copied;
 954         int ret;
 955 
 956         /*
 957          * Collapse multiple contiguous slashes and remove trailing slash.
 958          */
 959         modpath = strdup(zonepath);
 960         if (modpath == NULL)
 961                 return (Z_NOMEM);
 962         last_copied = '\0';
 963         for (copy_mp = curr_mp = modpath; *curr_mp != '\0'; curr_mp++) {
 964                 if (*curr_mp != '/' || last_copied != '/') {
 965                         last_copied = *copy_mp = *curr_mp;
 966                         copy_mp++;
 967                 }
 968         }
 969         if (last_copied == '/')
 970                 copy_mp--;
 971         *copy_mp = '\0';
 972 
 973         /*
 974          * The user deals in absolute paths in the running global zone, but the
 975          * internal configuration files deal with boot environment relative
 976          * paths.  Strip out the alternate root when specified.
 977          */
 978         len = strlen(zonecfg_root);
 979         if (strncmp(modpath, zonecfg_root, len) != 0 || modpath[len] != '/') {
 980                 free(modpath);
 981                 return (Z_BAD_PROPERTY);
 982         }
 983         curr_mp = modpath + len;
 984         ret = setrootattr(handle, DTD_ATTR_ZONEPATH, curr_mp);
 985         free(modpath);
 986         return (ret);
 987 }
 988 
 989 static int
 990 i_zonecfg_get_brand(zone_dochandle_t handle, char *brand, size_t brandsize,
 991     boolean_t default_query)
 992 {
 993         int ret, sz;
 994 
 995         ret = getrootattr(handle, DTD_ATTR_BRAND, brand, brandsize);
 996 
 997         /*
 998          * If the lookup failed, or succeeded in finding a non-null brand
 999          * string then return.
1000          */
1001         if (ret != Z_OK || brand[0] != '\0')
1002                 return (ret);
1003 
1004         if (!default_query) {
1005                 /* If the zone has no brand, it is the default brand. */
1006                 return (zonecfg_default_brand(brand, brandsize));
1007         }
1008 
1009         /* if SUNWdefault didn't specify a brand, fallback to "native" */
1010         sz = strlcpy(brand, NATIVE_BRAND_NAME, brandsize);
1011         if (sz >= brandsize)
1012                 return (Z_TOO_BIG);
1013         return (Z_OK);
1014 }
1015 
1016 int
1017 zonecfg_get_brand(zone_dochandle_t handle, char *brand, size_t brandsize)
1018 {
1019         return (i_zonecfg_get_brand(handle, brand, brandsize, B_FALSE));
1020 }
1021 
1022 int
1023 zonecfg_set_brand(zone_dochandle_t handle, char *brand)
1024 {
1025         return (setrootattr(handle, DTD_ATTR_BRAND, brand));
1026 }
1027 
1028 int
1029 zonecfg_get_autoboot(zone_dochandle_t handle, boolean_t *autoboot)
1030 {
1031         char autobootstr[DTD_ENTITY_BOOL_LEN];
1032         int ret;
1033 
1034         if ((ret = getrootattr(handle, DTD_ATTR_AUTOBOOT, autobootstr,
1035             sizeof (autobootstr))) != Z_OK)
1036                 return (ret);
1037 
1038         if (strcmp(autobootstr, DTD_ENTITY_TRUE) == 0)
1039                 *autoboot = B_TRUE;
1040         else if (strcmp(autobootstr, DTD_ENTITY_FALSE) == 0)
1041                 *autoboot = B_FALSE;
1042         else
1043                 ret = Z_BAD_PROPERTY;
1044         return (ret);
1045 }
1046 
1047 int
1048 zonecfg_set_autoboot(zone_dochandle_t handle, boolean_t autoboot)
1049 {
1050         return (setrootattr(handle, DTD_ATTR_AUTOBOOT,
1051             autoboot ? DTD_ENTITY_TRUE : DTD_ENTITY_FALSE));
1052 }
1053 
1054 int
1055 zonecfg_get_pool(zone_dochandle_t handle, char *pool, size_t poolsize)
1056 {
1057         return (getrootattr(handle, DTD_ATTR_POOL, pool, poolsize));
1058 }
1059 
1060 int
1061 zonecfg_set_pool(zone_dochandle_t handle, char *pool)
1062 {
1063         return (setrootattr(handle, DTD_ATTR_POOL, pool));
1064 }
1065 
1066 int
1067 zonecfg_get_limitpriv(zone_dochandle_t handle, char **limitpriv)
1068 {
1069         return (get_alloc_rootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv));
1070 }
1071 
1072 int
1073 zonecfg_set_limitpriv(zone_dochandle_t handle, char *limitpriv)
1074 {
1075         return (setrootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv));
1076 }
1077 
1078 int
1079 zonecfg_get_bootargs(zone_dochandle_t handle, char *bargs, size_t bargssize)
1080 {
1081         return (getrootattr(handle, DTD_ATTR_BOOTARGS, bargs, bargssize));
1082 }
1083 
1084 int
1085 zonecfg_set_bootargs(zone_dochandle_t handle, char *bargs)
1086 {
1087         return (setrootattr(handle, DTD_ATTR_BOOTARGS, bargs));
1088 }
1089 
1090 int
1091 zonecfg_get_sched_class(zone_dochandle_t handle, char *sched, size_t schedsize)
1092 {
1093         return (getrootattr(handle, DTD_ATTR_SCHED, sched, schedsize));
1094 }
1095 
1096 int
1097 zonecfg_set_sched(zone_dochandle_t handle, char *sched)
1098 {
1099         return (setrootattr(handle, DTD_ATTR_SCHED, sched));
1100 }
1101 
1102 /*
1103  * /etc/zones/index caches a vital piece of information which is also
1104  * in the <zonename>.xml file: the path to the zone.  This is for performance,
1105  * since we need to walk all zonepath's in order to be able to detect conflicts
1106  * (see crosscheck_zonepaths() in the zoneadm command).
1107  *
1108  * An additional complexity is that when doing a rename, we'd like the entire
1109  * index update operation (rename, and potential state changes) to be atomic.
1110  * In general, the operation of this function should succeed or fail as
1111  * a unit.
1112  */
1113 int
1114 zonecfg_refresh_index_file(zone_dochandle_t handle)
1115 {
1116         char name[ZONENAME_MAX], zonepath[MAXPATHLEN];
1117         struct zoneent ze;
1118         int err;
1119         int opcode;
1120         char *zn;
1121 
1122         bzero(&ze, sizeof (ze));
1123         ze.zone_state = -1;     /* Preserve existing state in index */
1124 
1125         if ((err = zonecfg_get_name(handle, name, sizeof (name))) != Z_OK)
1126                 return (err);
1127         (void) strlcpy(ze.zone_name, name, sizeof (ze.zone_name));
1128 
1129         if ((err = zonecfg_get_zonepath(handle, zonepath,
1130             sizeof (zonepath))) != Z_OK)
1131                 return (err);
1132         (void) strlcpy(ze.zone_path, zonepath + strlen(zonecfg_root),
1133             sizeof (ze.zone_path));
1134 
1135         if (is_renaming(handle)) {
1136                 opcode = PZE_MODIFY;
1137                 (void) strlcpy(ze.zone_name, handle->zone_dh_delete_name,
1138                     sizeof (ze.zone_name));
1139                 (void) strlcpy(ze.zone_newname, name, sizeof (ze.zone_newname));
1140         } else if (is_new(handle)) {
1141                 FILE *cookie;
1142                 /*
1143                  * Be tolerant of the zone already existing in the index file,
1144                  * since we might be forcibly overwriting an existing
1145                  * configuration with a new one (for example 'create -F'
1146                  * in zonecfg).
1147                  */
1148                 opcode = PZE_ADD;
1149                 cookie = setzoneent();
1150                 while ((zn = getzoneent(cookie)) != NULL) {
1151                         if (strcmp(zn, name) == 0) {
1152                                 opcode = PZE_MODIFY;
1153                                 free(zn);
1154                                 break;
1155                         }
1156                         free(zn);
1157                 }
1158                 endzoneent(cookie);
1159                 ze.zone_state = ZONE_STATE_CONFIGURED;
1160         } else {
1161                 opcode = PZE_MODIFY;
1162         }
1163 
1164         if ((err = putzoneent(&ze, opcode)) != Z_OK)
1165                 return (err);
1166 
1167         return (Z_OK);
1168 }
1169 
1170 /*
1171  * The goal of this routine is to cause the index file update and the
1172  * document save to happen as an atomic operation.  We do the document
1173  * first, saving a backup copy using a hard link; if that succeeds, we go
1174  * on to the index.  If that fails, we roll the document back into place.
1175  *
1176  * Strategy:
1177  *
1178  * New zone 'foo' configuration:
1179  *      Create tmpfile (zonecfg.xxxxxx)
1180  *      Write XML to tmpfile
1181  *      Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
1182  *      Add entry to index file
1183  *      If it fails, delete foo.xml, leaving nothing behind.
1184  *
1185  * Save existing zone 'foo':
1186  *      Make backup of foo.xml -> .backup
1187  *      Create tmpfile (zonecfg.xxxxxx)
1188  *      Write XML to tmpfile
1189  *      Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
1190  *      Modify index file as needed
1191  *      If it fails, recover from .backup -> foo.xml
1192  *
1193  * Rename 'foo' to 'bar':
1194  *      Create tmpfile (zonecfg.xxxxxx)
1195  *      Write XML to tmpfile
1196  *      Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml)
1197  *      Add entry for 'bar' to index file, Remove entry for 'foo' (refresh)
1198  *      If it fails, delete bar.xml; foo.xml is left behind.
1199  */
1200 static int
1201 zonecfg_save_impl(zone_dochandle_t handle, char *filename)
1202 {
1203         char tmpfile[MAXPATHLEN];
1204         char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN];
1205         int tmpfd, err, valid;
1206         xmlValidCtxt cvp = { NULL };
1207         boolean_t backup;
1208 
1209         (void) strlcpy(tmpfile, filename, sizeof (tmpfile));
1210         (void) dirname(tmpfile);
1211         (void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile));
1212 
1213         tmpfd = mkstemp(tmpfile);
1214         if (tmpfd == -1) {
1215                 (void) unlink(tmpfile);
1216                 return (Z_TEMP_FILE);
1217         }
1218         (void) close(tmpfd);
1219 
1220         cvp.error = zonecfg_error_func;
1221         cvp.warning = zonecfg_error_func;
1222 
1223         /*
1224          * We do a final validation of the document.  Since the library has
1225          * malfunctioned if it fails to validate, we follow-up with an
1226          * assert() that the doc is valid.
1227          */
1228         valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1229         assert(valid != 0);
1230 
1231         if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0)
1232                 goto err;
1233 
1234         (void) chmod(tmpfile, 0644);
1235 
1236         /*
1237          * In the event we are doing a standard save, hard link a copy of the
1238          * original file in .backup.<pid>.filename so we can restore it if
1239          * something goes wrong.
1240          */
1241         if (!is_new(handle) && !is_renaming(handle)) {
1242                 backup = B_TRUE;
1243 
1244                 (void) strlcpy(bakdir, filename, sizeof (bakdir));
1245                 (void) strlcpy(bakbase, filename, sizeof (bakbase));
1246                 (void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s",
1247                     dirname(bakdir), getpid(), basename(bakbase));
1248 
1249                 if (link(filename, bakfile) == -1) {
1250                         err = errno;
1251                         (void) unlink(tmpfile);
1252                         if (errno == EACCES)
1253                                 return (Z_ACCES);
1254                         return (Z_MISC_FS);
1255                 }
1256         }
1257 
1258         /*
1259          * Move the new document over top of the old.
1260          * i.e.:   zonecfg.XXXXXX  ->  myzone.xml
1261          */
1262         if (rename(tmpfile, filename) == -1) {
1263                 err = errno;
1264                 (void) unlink(tmpfile);
1265                 if (backup)
1266                         (void) unlink(bakfile);
1267                 if (err == EACCES)
1268                         return (Z_ACCES);
1269                 return (Z_MISC_FS);
1270         }
1271 
1272         /*
1273          * If this is a snapshot, we're done-- don't add an index entry.
1274          */
1275         if (is_snapshot(handle))
1276                 return (Z_OK);
1277 
1278         /* now update the index file to reflect whatever we just did */
1279         if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) {
1280                 if (backup) {
1281                         /*
1282                          * Try to restore from our backup.
1283                          */
1284                         (void) unlink(filename);
1285                         (void) rename(bakfile, filename);
1286                 } else {
1287                         /*
1288                          * Either the zone is new, in which case we can delete
1289                          * new.xml, or we're doing a rename, so ditto.
1290                          */
1291                         assert(is_new(handle) || is_renaming(handle));
1292                         (void) unlink(filename);
1293                 }
1294                 return (Z_UPDATING_INDEX);
1295         }
1296 
1297         if (backup)
1298                 (void) unlink(bakfile);
1299 
1300         return (Z_OK);
1301 
1302 err:
1303         (void) unlink(tmpfile);
1304         return (Z_SAVING_FILE);
1305 }
1306 
1307 int
1308 zonecfg_save(zone_dochandle_t handle)
1309 {
1310         char zname[ZONENAME_MAX], path[MAXPATHLEN];
1311         char delpath[MAXPATHLEN];
1312         int err = Z_SAVING_FILE;
1313 
1314         if (zonecfg_check_handle(handle) != Z_OK)
1315                 return (Z_BAD_HANDLE);
1316 
1317         /*
1318          * We don't support saving snapshots or a tree containing a sw
1319          * inventory at this time.
1320          */
1321         if (handle->zone_dh_snapshot || handle->zone_dh_sw_inv)
1322                 return (Z_INVAL);
1323 
1324         if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK)
1325                 return (err);
1326 
1327         if (!config_file_path(zname, path))
1328                 return (Z_MISC_FS);
1329 
1330         addcomment(handle, "\n    DO NOT EDIT THIS "
1331             "FILE.  Use zonecfg(1M) instead.\n");
1332 
1333         /*
1334          * Update user_attr first so that it will be older
1335          * than the config file.
1336          */
1337         (void) zonecfg_authorize_users(handle, zname);
1338         err = zonecfg_save_impl(handle, path);
1339 
1340         stripcomments(handle);
1341 
1342         if (err != Z_OK)
1343                 return (err);
1344 
1345         handle->zone_dh_newzone = B_FALSE;
1346 
1347         if (is_renaming(handle)) {
1348                 if (config_file_path(handle->zone_dh_delete_name, delpath))
1349                         (void) unlink(delpath);
1350                 handle->zone_dh_delete_name[0] = '\0';
1351         }
1352 
1353         return (Z_OK);
1354 }
1355 
1356 int
1357 zonecfg_verify_save(zone_dochandle_t handle, char *filename)
1358 {
1359         int valid;
1360 
1361         xmlValidCtxt cvp = { NULL };
1362 
1363         if (zonecfg_check_handle(handle) != Z_OK)
1364                 return (Z_BAD_HANDLE);
1365 
1366         cvp.error = zonecfg_error_func;
1367         cvp.warning = zonecfg_error_func;
1368 
1369         /*
1370          * We do a final validation of the document.  Since the library has
1371          * malfunctioned if it fails to validate, we follow-up with an
1372          * assert() that the doc is valid.
1373          */
1374         valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1375         assert(valid != 0);
1376 
1377         if (xmlSaveFormatFile(filename, handle->zone_dh_doc, 1) <= 0)
1378                 return (Z_SAVING_FILE);
1379 
1380         return (Z_OK);
1381 }
1382 
1383 int
1384 zonecfg_detach_save(zone_dochandle_t handle, uint_t flags)
1385 {
1386         char zname[ZONENAME_MAX];
1387         char path[MAXPATHLEN];
1388         char migpath[MAXPATHLEN];
1389         xmlValidCtxt cvp = { NULL };
1390         int err = Z_SAVING_FILE;
1391         int valid;
1392 
1393         if (zonecfg_check_handle(handle) != Z_OK)
1394                 return (Z_BAD_HANDLE);
1395 
1396         if (flags & ZONE_DRY_RUN) {
1397                 (void) strlcpy(migpath, "-", sizeof (migpath));
1398         } else {
1399                 if ((err = zonecfg_get_name(handle, zname, sizeof (zname)))
1400                     != Z_OK)
1401                         return (err);
1402 
1403                 if ((err = zone_get_zonepath(zname, path, sizeof (path)))
1404                     != Z_OK)
1405                         return (err);
1406 
1407                 if (snprintf(migpath, sizeof (migpath), "%s/%s", path,
1408                     ZONE_DETACHED) >= sizeof (migpath))
1409                         return (Z_NOMEM);
1410         }
1411 
1412         if ((err = operation_prep(handle)) != Z_OK)
1413                 return (err);
1414 
1415         addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
1416             "Use zonecfg(1M) and zoneadm(1M) attach.\n");
1417 
1418         cvp.error = zonecfg_error_func;
1419         cvp.warning = zonecfg_error_func;
1420 
1421         /*
1422          * We do a final validation of the document.  Since the library has
1423          * malfunctioned if it fails to validate, we follow-up with an
1424          * assert() that the doc is valid.
1425          */
1426         valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1427         assert(valid != 0);
1428 
1429         if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0)
1430                 return (Z_SAVING_FILE);
1431 
1432         if (!(flags & ZONE_DRY_RUN))
1433                 (void) chmod(migpath, 0644);
1434 
1435         stripcomments(handle);
1436 
1437         handle->zone_dh_newzone = B_FALSE;
1438 
1439         return (Z_OK);
1440 }
1441 
1442 boolean_t
1443 zonecfg_detached(const char *path)
1444 {
1445         char            migpath[MAXPATHLEN];
1446         struct stat     buf;
1447 
1448         if (snprintf(migpath, sizeof (migpath), "%s/%s", path, ZONE_DETACHED) >=
1449             sizeof (migpath))
1450                 return (B_FALSE);
1451 
1452         if (stat(migpath, &buf) != -1)
1453                 return (B_TRUE);
1454 
1455         return (B_FALSE);
1456 }
1457 
1458 void
1459 zonecfg_rm_detached(zone_dochandle_t handle, boolean_t forced)
1460 {
1461         char zname[ZONENAME_MAX];
1462         char path[MAXPATHLEN];
1463         char detached[MAXPATHLEN];
1464         char attached[MAXPATHLEN];
1465 
1466         if (zonecfg_check_handle(handle) != Z_OK)
1467                 return;
1468 
1469         if (zonecfg_get_name(handle, zname, sizeof (zname)) != Z_OK)
1470                 return;
1471 
1472         if (zone_get_zonepath(zname, path, sizeof (path)) != Z_OK)
1473                 return;
1474 
1475         (void) snprintf(detached, sizeof (detached), "%s/%s", path,
1476             ZONE_DETACHED);
1477         (void) snprintf(attached, sizeof (attached), "%s/%s", path,
1478             ATTACH_FORCED);
1479 
1480         if (forced) {
1481                 (void) rename(detached, attached);
1482         } else {
1483                 (void) unlink(attached);
1484                 (void) unlink(detached);
1485         }
1486 }
1487 
1488 /*
1489  * Special case: if access(2) fails with ENOENT, then try again using
1490  * ZONE_CONFIG_ROOT instead of config_file_path(zonename).  This is how we
1491  * work around the case of a config file which has not been created yet:
1492  * the user will need access to the directory so use that as a heuristic.
1493  */
1494 
1495 int
1496 zonecfg_access(const char *zonename, int amode)
1497 {
1498         char path[MAXPATHLEN];
1499 
1500         if (!config_file_path(zonename, path))
1501                 return (Z_INVAL);
1502         if (access(path, amode) == 0)
1503                 return (Z_OK);
1504         if (errno == ENOENT) {
1505                 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1506                     ZONE_CONFIG_ROOT) >= sizeof (path))
1507                         return (Z_INVAL);
1508                 if (access(path, amode) == 0)
1509                         return (Z_OK);
1510         }
1511         if (errno == EACCES)
1512                 return (Z_ACCES);
1513         if (errno == EINVAL)
1514                 return (Z_INVAL);
1515         return (Z_MISC_FS);
1516 }
1517 
1518 int
1519 zonecfg_create_snapshot(const char *zonename)
1520 {
1521         zone_dochandle_t handle;
1522         char path[MAXPATHLEN], zonepath[MAXPATHLEN], rpath[MAXPATHLEN];
1523         int error = Z_OK, res;
1524 
1525         if ((handle = zonecfg_init_handle()) == NULL) {
1526                 return (Z_NOMEM);
1527         }
1528 
1529         handle->zone_dh_newzone = B_TRUE;
1530         handle->zone_dh_snapshot = B_TRUE;
1531 
1532         if ((error = zonecfg_get_handle(zonename, handle)) != Z_OK)
1533                 goto out;
1534         if ((error = operation_prep(handle)) != Z_OK)
1535                 goto out;
1536         error = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath));
1537         if (error != Z_OK)
1538                 goto out;
1539         if ((res = resolvepath(zonepath, rpath, sizeof (rpath))) == -1) {
1540                 error = Z_RESOLVED_PATH;
1541                 goto out;
1542         }
1543         /*
1544          * If the resolved path is not the same as the original path, then
1545          * save the resolved path in the snapshot, thus preventing any
1546          * potential problems down the line when zoneadmd goes to unmount
1547          * file systems and depends on initial string matches with resolved
1548          * paths.
1549          */
1550         rpath[res] = '\0';
1551         if (strcmp(zonepath, rpath) != 0) {
1552                 if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK)
1553                         goto out;
1554         }
1555         if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1556             ZONE_SNAPSHOT_ROOT) >= sizeof (path)) {
1557                 error = Z_MISC_FS;
1558                 goto out;
1559         }
1560         if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) {
1561                 error = Z_MISC_FS;
1562                 goto out;
1563         }
1564 
1565         if (!snap_file_path(zonename, path)) {
1566                 error = Z_MISC_FS;
1567                 goto out;
1568         }
1569 
1570         addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
1571             "It is a snapshot of running zone state.\n");
1572 
1573         error = zonecfg_save_impl(handle, path);
1574 
1575         stripcomments(handle);
1576 
1577 out:
1578         zonecfg_fini_handle(handle);
1579         return (error);
1580 }
1581 
1582 int
1583 zonecfg_get_iptype(zone_dochandle_t handle, zone_iptype_t *iptypep)
1584 {
1585         char property[10]; /* 10 is big enough for "shared"/"exclusive" */
1586         int err;
1587 
1588         err = getrootattr(handle, DTD_ATTR_IPTYPE, property, sizeof (property));
1589         if (err == Z_BAD_PROPERTY) {
1590                 /* Return default value */
1591                 *iptypep = ZS_SHARED;
1592                 return (Z_OK);
1593         } else if (err != Z_OK) {
1594                 return (err);
1595         }
1596 
1597         if (strlen(property) == 0 ||
1598             strcmp(property, "shared") == 0)
1599                 *iptypep = ZS_SHARED;
1600         else if (strcmp(property, "exclusive") == 0)
1601                 *iptypep = ZS_EXCLUSIVE;
1602         else
1603                 return (Z_INVAL);
1604 
1605         return (Z_OK);
1606 }
1607 
1608 int
1609 zonecfg_set_iptype(zone_dochandle_t handle, zone_iptype_t iptype)
1610 {
1611         xmlNodePtr cur;
1612 
1613         if (handle == NULL)
1614                 return (Z_INVAL);
1615 
1616         cur = xmlDocGetRootElement(handle->zone_dh_doc);
1617         if (cur == NULL) {
1618                 return (Z_EMPTY_DOCUMENT);
1619         }
1620 
1621         if (xmlStrcmp(cur->name, DTD_ELEM_ZONE) != 0) {
1622                 return (Z_WRONG_DOC_TYPE);
1623         }
1624         switch (iptype) {
1625         case ZS_SHARED:
1626                 /*
1627                  * Since "shared" is the default, we don't write it to the
1628                  * configuration file, so that it's easier to migrate those
1629                  * zones elsewhere, eg., to systems which are not IP-Instances
1630                  * aware.
1631                  * xmlUnsetProp only fails when the attribute doesn't exist,
1632                  * which we don't care.
1633                  */
1634                 (void) xmlUnsetProp(cur, DTD_ATTR_IPTYPE);
1635                 break;
1636         case ZS_EXCLUSIVE:
1637                 if (xmlSetProp(cur, DTD_ATTR_IPTYPE,
1638                     (const xmlChar *) "exclusive") == NULL)
1639                         return (Z_INVAL);
1640                 break;
1641         }
1642         return (Z_OK);
1643 }
1644 
1645 static int
1646 newprop(xmlNodePtr node, const xmlChar *attrname, char *src)
1647 {
1648         xmlAttrPtr newattr;
1649 
1650         newattr = xmlNewProp(node, attrname, (xmlChar *)src);
1651         if (newattr == NULL) {
1652                 xmlUnlinkNode(node);
1653                 xmlFreeNode(node);
1654                 return (Z_BAD_PROPERTY);
1655         }
1656         return (Z_OK);
1657 }
1658 
1659 static int
1660 zonecfg_add_filesystem_core(zone_dochandle_t handle, struct zone_fstab *tabptr)
1661 {
1662         xmlNodePtr newnode, cur = handle->zone_dh_cur, options_node;
1663         zone_fsopt_t *ptr;
1664         int err;
1665 
1666         newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_FS, NULL);
1667         if ((err = newprop(newnode, DTD_ATTR_SPECIAL,
1668             tabptr->zone_fs_special)) != Z_OK)
1669                 return (err);
1670         if (tabptr->zone_fs_raw[0] != '\0' &&
1671             (err = newprop(newnode, DTD_ATTR_RAW, tabptr->zone_fs_raw)) != Z_OK)
1672                 return (err);
1673         if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK)
1674                 return (err);
1675         if ((err = newprop(newnode, DTD_ATTR_TYPE,
1676             tabptr->zone_fs_type)) != Z_OK)
1677                 return (err);
1678         if (tabptr->zone_fs_options != NULL) {
1679                 for (ptr = tabptr->zone_fs_options; ptr != NULL;
1680                     ptr = ptr->zone_fsopt_next) {
1681                         options_node = xmlNewTextChild(newnode, NULL,
1682                             DTD_ELEM_FSOPTION, NULL);
1683                         if ((err = newprop(options_node, DTD_ATTR_NAME,
1684                             ptr->zone_fsopt_opt)) != Z_OK)
1685                                 return (err);
1686                 }
1687         }
1688         return (Z_OK);
1689 }
1690 
1691 int
1692 zonecfg_add_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
1693 {
1694         int err;
1695 
1696         if (tabptr == NULL)
1697                 return (Z_INVAL);
1698 
1699         if ((err = operation_prep(handle)) != Z_OK)
1700                 return (err);
1701 
1702         if ((err = zonecfg_add_filesystem_core(handle, tabptr)) != Z_OK)
1703                 return (err);
1704 
1705         return (Z_OK);
1706 }
1707 
1708 int
1709 zonecfg_add_fs_option(struct zone_fstab *tabptr, char *option)
1710 {
1711         zone_fsopt_t *last, *old, *new;
1712 
1713         last = tabptr->zone_fs_options;
1714         for (old = last; old != NULL; old = old->zone_fsopt_next)
1715                 last = old;     /* walk to the end of the list */
1716         new = (zone_fsopt_t *)malloc(sizeof (zone_fsopt_t));
1717         if (new == NULL)
1718                 return (Z_NOMEM);
1719         (void) strlcpy(new->zone_fsopt_opt, option,
1720             sizeof (new->zone_fsopt_opt));
1721         new->zone_fsopt_next = NULL;
1722         if (last == NULL)
1723                 tabptr->zone_fs_options = new;
1724         else
1725                 last->zone_fsopt_next = new;
1726         return (Z_OK);
1727 }
1728 
1729 int
1730 zonecfg_remove_fs_option(struct zone_fstab *tabptr, char *option)
1731 {
1732         zone_fsopt_t *last, *this, *next;
1733 
1734         last = tabptr->zone_fs_options;
1735         for (this = last; this != NULL; this = this->zone_fsopt_next) {
1736                 if (strcmp(this->zone_fsopt_opt, option) == 0) {
1737                         next = this->zone_fsopt_next;
1738                         if (this == tabptr->zone_fs_options)
1739                                 tabptr->zone_fs_options = next;
1740                         else
1741                                 last->zone_fsopt_next = next;
1742                         free(this);
1743                         return (Z_OK);
1744                 } else
1745                         last = this;
1746         }
1747         return (Z_NO_PROPERTY_ID);
1748 }
1749 
1750 void
1751 zonecfg_free_fs_option_list(zone_fsopt_t *list)
1752 {
1753         zone_fsopt_t *this, *next;
1754 
1755         for (this = list; this != NULL; this = next) {
1756                 next = this->zone_fsopt_next;
1757                 free(this);
1758         }
1759 }
1760 
1761 void
1762 zonecfg_free_rctl_value_list(struct zone_rctlvaltab *valtab)
1763 {
1764         if (valtab == NULL)
1765                 return;
1766         zonecfg_free_rctl_value_list(valtab->zone_rctlval_next);
1767         free(valtab);
1768 }
1769 
1770 static boolean_t
1771 match_prop(xmlNodePtr cur, const xmlChar *attr, char *user_prop)
1772 {
1773         xmlChar *gotten_prop;
1774         int prop_result;
1775 
1776         gotten_prop = xmlGetProp(cur, attr);
1777         if (gotten_prop == NULL)        /* shouldn't happen */
1778                 return (B_FALSE);
1779         prop_result = xmlStrcmp(gotten_prop, (const xmlChar *) user_prop);
1780         xmlFree(gotten_prop);
1781         return ((prop_result == 0));    /* empty strings will match */
1782 }
1783 
1784 static int
1785 zonecfg_delete_filesystem_core(zone_dochandle_t handle,
1786     struct zone_fstab *tabptr)
1787 {
1788         xmlNodePtr cur = handle->zone_dh_cur;
1789         boolean_t dir_match, spec_match, raw_match, type_match;
1790 
1791         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1792                 if (xmlStrcmp(cur->name, DTD_ELEM_FS))
1793                         continue;
1794                 dir_match = match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir);
1795                 spec_match = match_prop(cur, DTD_ATTR_SPECIAL,
1796                     tabptr->zone_fs_special);
1797                 raw_match = match_prop(cur, DTD_ATTR_RAW,
1798                     tabptr->zone_fs_raw);
1799                 type_match = match_prop(cur, DTD_ATTR_TYPE,
1800                     tabptr->zone_fs_type);
1801                 if (dir_match && spec_match && raw_match && type_match) {
1802                         xmlUnlinkNode(cur);
1803                         xmlFreeNode(cur);
1804                         return (Z_OK);
1805                 }
1806         }
1807         return (Z_NO_RESOURCE_ID);
1808 }
1809 
1810 int
1811 zonecfg_delete_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
1812 {
1813         int err;
1814 
1815         if (tabptr == NULL)
1816                 return (Z_INVAL);
1817 
1818         if ((err = operation_prep(handle)) != Z_OK)
1819                 return (err);
1820 
1821         if ((err = zonecfg_delete_filesystem_core(handle, tabptr)) != Z_OK)
1822                 return (err);
1823 
1824         return (Z_OK);
1825 }
1826 
1827 int
1828 zonecfg_modify_filesystem(
1829         zone_dochandle_t handle,
1830         struct zone_fstab *oldtabptr,
1831         struct zone_fstab *newtabptr)
1832 {
1833         int err;
1834 
1835         if (oldtabptr == NULL || newtabptr == NULL)
1836                 return (Z_INVAL);
1837 
1838         if ((err = operation_prep(handle)) != Z_OK)
1839                 return (err);
1840 
1841         if ((err = zonecfg_delete_filesystem_core(handle, oldtabptr)) != Z_OK)
1842                 return (err);
1843 
1844         if ((err = zonecfg_add_filesystem_core(handle, newtabptr)) != Z_OK)
1845                 return (err);
1846 
1847         return (Z_OK);
1848 }
1849 
1850 int
1851 zonecfg_lookup_filesystem(
1852         zone_dochandle_t handle,
1853         struct zone_fstab *tabptr)
1854 {
1855         xmlNodePtr cur, options, firstmatch;
1856         int err;
1857         char dirname[MAXPATHLEN], special[MAXPATHLEN], raw[MAXPATHLEN];
1858         char type[FSTYPSZ];
1859         char options_str[MAX_MNTOPT_STR];
1860 
1861         if (tabptr == NULL)
1862                 return (Z_INVAL);
1863 
1864         if ((err = operation_prep(handle)) != Z_OK)
1865                 return (err);
1866 
1867         /*
1868          * Walk the list of children looking for matches on any properties
1869          * specified in the fstab parameter.  If more than one resource
1870          * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return
1871          * Z_NO_RESOURCE_ID.
1872          */
1873         cur = handle->zone_dh_cur;
1874         firstmatch = NULL;
1875         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1876                 if (xmlStrcmp(cur->name, DTD_ELEM_FS))
1877                         continue;
1878                 if (strlen(tabptr->zone_fs_dir) > 0) {
1879                         if ((fetchprop(cur, DTD_ATTR_DIR, dirname,
1880                             sizeof (dirname)) == Z_OK) &&
1881                             (strcmp(tabptr->zone_fs_dir, dirname) == 0)) {
1882                                 if (firstmatch == NULL)
1883                                         firstmatch = cur;
1884                                 else
1885                                         return (Z_INSUFFICIENT_SPEC);
1886                         }
1887                 }
1888                 if (strlen(tabptr->zone_fs_special) > 0) {
1889                         if ((fetchprop(cur, DTD_ATTR_SPECIAL, special,
1890                             sizeof (special)) == Z_OK)) {
1891                                 if (strcmp(tabptr->zone_fs_special,
1892                                     special) == 0) {
1893                                         if (firstmatch == NULL)
1894                                                 firstmatch = cur;
1895                                         else if (firstmatch != cur)
1896                                                 return (Z_INSUFFICIENT_SPEC);
1897                                 } else {
1898                                         /*
1899                                          * If another property matched but this
1900                                          * one doesn't then reset firstmatch.
1901                                          */
1902                                         if (firstmatch == cur)
1903                                                 firstmatch = NULL;
1904                                 }
1905                         }
1906                 }
1907                 if (strlen(tabptr->zone_fs_raw) > 0) {
1908                         if ((fetchprop(cur, DTD_ATTR_RAW, raw,
1909                             sizeof (raw)) == Z_OK)) {
1910                                 if (strcmp(tabptr->zone_fs_raw, raw) == 0) {
1911                                         if (firstmatch == NULL)
1912                                                 firstmatch = cur;
1913                                         else if (firstmatch != cur)
1914                                                 return (Z_INSUFFICIENT_SPEC);
1915                                 } else {
1916                                         /*
1917                                          * If another property matched but this
1918                                          * one doesn't then reset firstmatch.
1919                                          */
1920                                         if (firstmatch == cur)
1921                                                 firstmatch = NULL;
1922                                 }
1923                         }
1924                 }
1925                 if (strlen(tabptr->zone_fs_type) > 0) {
1926                         if ((fetchprop(cur, DTD_ATTR_TYPE, type,
1927                             sizeof (type)) == Z_OK)) {
1928                                 if (strcmp(tabptr->zone_fs_type, type) == 0) {
1929                                         if (firstmatch == NULL)
1930                                                 firstmatch = cur;
1931                                         else if (firstmatch != cur)
1932                                                 return (Z_INSUFFICIENT_SPEC);
1933                                 } else {
1934                                         /*
1935                                          * If another property matched but this
1936                                          * one doesn't then reset firstmatch.
1937                                          */
1938                                         if (firstmatch == cur)
1939                                                 firstmatch = NULL;
1940                                 }
1941                         }
1942                 }
1943         }
1944 
1945         if (firstmatch == NULL)
1946                 return (Z_NO_RESOURCE_ID);
1947 
1948         cur = firstmatch;
1949 
1950         if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
1951             sizeof (tabptr->zone_fs_dir))) != Z_OK)
1952                 return (err);
1953 
1954         if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
1955             sizeof (tabptr->zone_fs_special))) != Z_OK)
1956                 return (err);
1957 
1958         if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
1959             sizeof (tabptr->zone_fs_raw))) != Z_OK)
1960                 return (err);
1961 
1962         if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
1963             sizeof (tabptr->zone_fs_type))) != Z_OK)
1964                 return (err);
1965 
1966         /* options are optional */
1967         tabptr->zone_fs_options = NULL;
1968         for (options = cur->xmlChildrenNode; options != NULL;
1969             options = options->next) {
1970                 if ((fetchprop(options, DTD_ATTR_NAME, options_str,
1971                     sizeof (options_str)) != Z_OK))
1972                         break;
1973                 if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
1974                         break;
1975         }
1976         return (Z_OK);
1977 }
1978 
1979 /*
1980  * Compare two IP addresses in string form.  Allow for the possibility that
1981  * one might have "/<prefix-length>" at the end: allow a match on just the
1982  * IP address (or host name) part.
1983  */
1984 
1985 boolean_t
1986 zonecfg_same_net_address(char *a1, char *a2)
1987 {
1988         char *slashp, *slashp1, *slashp2;
1989         int result;
1990 
1991         if (strcmp(a1, a2) == 0)
1992                 return (B_TRUE);
1993 
1994         /*
1995          * If neither has a slash or both do, they need to match to be
1996          * considered the same, but they did not match above, so fail.
1997          */
1998         slashp1 = strchr(a1, '/');
1999         slashp2 = strchr(a2, '/');
2000         if ((slashp1 == NULL && slashp2 == NULL) ||
2001             (slashp1 != NULL && slashp2 != NULL))
2002                 return (B_FALSE);
2003 
2004         /*
2005          * Only one had a slash: pick that one, zero out the slash, compare
2006          * the "address only" strings, restore the slash, and return the
2007          * result of the comparison.
2008          */
2009         slashp = (slashp1 == NULL) ? slashp2 : slashp1;
2010         *slashp = '\0';
2011         result = strcmp(a1, a2);
2012         *slashp = '/';
2013         return ((result == 0));
2014 }
2015 
2016 int
2017 zonecfg_valid_net_address(char *address, struct lifreq *lifr)
2018 {
2019         struct sockaddr_in *sin4;
2020         struct sockaddr_in6 *sin6;
2021         struct addrinfo hints, *result;
2022         char *slashp = strchr(address, '/');
2023 
2024         bzero(lifr, sizeof (struct lifreq));
2025         sin4 = (struct sockaddr_in *)&lifr->lifr_addr;
2026         sin6 = (struct sockaddr_in6 *)&lifr->lifr_addr;
2027         if (slashp != NULL)
2028                 *slashp = '\0';
2029         if (inet_pton(AF_INET, address, &sin4->sin_addr) == 1) {
2030                 sin4->sin_family = AF_INET;
2031         } else if (inet_pton(AF_INET6, address, &sin6->sin6_addr) == 1) {
2032                 if (slashp == NULL)
2033                         return (Z_IPV6_ADDR_PREFIX_LEN);
2034                 sin6->sin6_family = AF_INET6;
2035         } else {
2036                 /* "address" may be a host name */
2037                 (void) memset(&hints, 0, sizeof (hints));
2038                 hints.ai_family = PF_INET;
2039                 if (getaddrinfo(address, NULL, &hints, &result) != 0)
2040                         return (Z_BOGUS_ADDRESS);
2041                 sin4->sin_family = result->ai_family;
2042 
2043                 (void) memcpy(&sin4->sin_addr,
2044                     /* LINTED E_BAD_PTR_CAST_ALIGN */
2045                     &((struct sockaddr_in *)result->ai_addr)->sin_addr,
2046                     sizeof (struct in_addr));
2047 
2048                 freeaddrinfo(result);
2049         }
2050         return (Z_OK);
2051 }
2052 
2053 boolean_t
2054 zonecfg_ifname_exists(sa_family_t af, char *ifname)
2055 {
2056         struct lifreq lifr;
2057         int so;
2058         int save_errno;
2059 
2060         (void) memset(&lifr, 0, sizeof (lifr));
2061         (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
2062         lifr.lifr_addr.ss_family = af;
2063         if ((so = socket(af, SOCK_DGRAM, 0)) < 0) {
2064                 /* Odd - can't tell if the ifname exists */
2065                 return (B_FALSE);
2066         }
2067         if (ioctl(so, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
2068                 save_errno = errno;
2069                 (void) close(so);
2070                 errno = save_errno;
2071                 return (B_FALSE);
2072         }
2073         (void) close(so);
2074         return (B_TRUE);
2075 }
2076 
2077 /*
2078  * Determines whether there is a net resource with the physical interface, IP
2079  * address, and default router specified by 'tabptr' in the zone configuration
2080  * to which 'handle' refers.  'tabptr' must have an interface, an address, a
2081  * default router, or a combination of the three.  This function returns Z_OK
2082  * iff there is exactly one net resource matching the query specified by
2083  * 'tabptr'.  The function returns Z_INSUFFICIENT_SPEC if there are multiple
2084  * matches or 'tabptr' does not specify a physical interface, address, or
2085  * default router.  The function returns Z_NO_RESOURCE_ID if are no matches.
2086  *
2087  * Errors might also be returned if the entry that exactly matches the
2088  * query lacks critical network resource information.
2089  *
2090  * If there is a single match, then the matching entry's physical interface, IP
2091  * address, and default router information are stored in 'tabptr'.
2092  */
2093 int
2094 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2095 {
2096         xmlNodePtr cur;
2097         xmlNodePtr firstmatch;
2098         int err;
2099         char address[INET6_ADDRSTRLEN];
2100         char physical[LIFNAMSIZ];
2101         size_t addrspec;                /* nonzero if tabptr has IP addr */
2102         size_t physspec;                /* nonzero if tabptr has interface */
2103         size_t defrouterspec;           /* nonzero if tabptr has def. router */
2104         size_t allowed_addrspec;
2105         zone_iptype_t iptype;
2106 
2107         if (tabptr == NULL)
2108                 return (Z_INVAL);
2109 
2110         /*
2111          * Determine the fields that will be searched.  There must be at least
2112          * one.
2113          *
2114          * zone_nwif_address, zone_nwif_physical, and zone_nwif_defrouter are
2115          * arrays, so no NULL checks are necessary.
2116          */
2117         addrspec = strlen(tabptr->zone_nwif_address);
2118         physspec = strlen(tabptr->zone_nwif_physical);
2119         defrouterspec = strlen(tabptr->zone_nwif_defrouter);
2120         allowed_addrspec = strlen(tabptr->zone_nwif_allowed_address);
2121         if (addrspec != 0 && allowed_addrspec != 0)
2122                 return (Z_INVAL); /* can't specify both */
2123         if (addrspec == 0 && physspec == 0 && defrouterspec == 0 &&
2124             allowed_addrspec == 0)
2125                 return (Z_INSUFFICIENT_SPEC);
2126 
2127         if ((err = operation_prep(handle)) != Z_OK)
2128                 return (err);
2129 
2130         if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK)
2131                 return (err);
2132         /*
2133          * Iterate over the configuration's elements and look for net elements
2134          * that match the query.
2135          */
2136         firstmatch = NULL;
2137         cur = handle->zone_dh_cur;
2138         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2139                 /* Skip non-net elements */
2140                 if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2141                         continue;
2142 
2143                 /*
2144                  * If any relevant fields don't match the query, then skip
2145                  * the current net element.
2146                  */
2147                 if (physspec != 0 && (fetchprop(cur, DTD_ATTR_PHYSICAL,
2148                     physical, sizeof (physical)) != Z_OK ||
2149                     strcmp(tabptr->zone_nwif_physical, physical) != 0))
2150                         continue;
2151                 if (iptype == ZS_SHARED && addrspec != 0 &&
2152                     (fetchprop(cur, DTD_ATTR_ADDRESS, address,
2153                     sizeof (address)) != Z_OK ||
2154                     !zonecfg_same_net_address(tabptr->zone_nwif_address,
2155                     address)))
2156                         continue;
2157                 if (iptype == ZS_EXCLUSIVE && allowed_addrspec != 0 &&
2158                     (fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS, address,
2159                     sizeof (address)) != Z_OK ||
2160                     !zonecfg_same_net_address(tabptr->zone_nwif_allowed_address,
2161                     address)))
2162                         continue;
2163                 if (defrouterspec != 0 && (fetchprop(cur, DTD_ATTR_DEFROUTER,
2164                     address, sizeof (address)) != Z_OK ||
2165                     !zonecfg_same_net_address(tabptr->zone_nwif_defrouter,
2166                     address)))
2167                         continue;
2168 
2169                 /*
2170                  * The current net element matches the query.  Select it if
2171                  * it's the first match; otherwise, abort the search.
2172                  */
2173                 if (firstmatch == NULL)
2174                         firstmatch = cur;
2175                 else
2176                         return (Z_INSUFFICIENT_SPEC);
2177         }
2178         if (firstmatch == NULL)
2179                 return (Z_NO_RESOURCE_ID);
2180 
2181         cur = firstmatch;
2182 
2183         if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
2184             sizeof (tabptr->zone_nwif_physical))) != Z_OK)
2185                 return (err);
2186 
2187         if (iptype == ZS_SHARED &&
2188             (err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
2189             sizeof (tabptr->zone_nwif_address))) != Z_OK)
2190                 return (err);
2191 
2192         if (iptype == ZS_EXCLUSIVE &&
2193             (err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
2194             tabptr->zone_nwif_allowed_address,
2195             sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK)
2196                 return (err);
2197 
2198         if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
2199             tabptr->zone_nwif_defrouter,
2200             sizeof (tabptr->zone_nwif_defrouter))) != Z_OK)
2201                 return (err);
2202 
2203         return (Z_OK);
2204 }
2205 
2206 static int
2207 zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2208 {
2209         xmlNodePtr newnode, cur = handle->zone_dh_cur;
2210         int err;
2211 
2212         newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL);
2213         if (strlen(tabptr->zone_nwif_address) > 0 &&
2214             (err = newprop(newnode, DTD_ATTR_ADDRESS,
2215             tabptr->zone_nwif_address)) != Z_OK)
2216                 return (err);
2217         if (strlen(tabptr->zone_nwif_allowed_address) > 0 &&
2218             (err = newprop(newnode, DTD_ATTR_ALLOWED_ADDRESS,
2219             tabptr->zone_nwif_allowed_address)) != Z_OK)
2220                 return (err);
2221         if ((err = newprop(newnode, DTD_ATTR_PHYSICAL,
2222             tabptr->zone_nwif_physical)) != Z_OK)
2223                 return (err);
2224         /*
2225          * Do not add this property when it is not set, for backwards
2226          * compatibility and because it is optional.
2227          */
2228         if ((strlen(tabptr->zone_nwif_defrouter) > 0) &&
2229             ((err = newprop(newnode, DTD_ATTR_DEFROUTER,
2230             tabptr->zone_nwif_defrouter)) != Z_OK))
2231                 return (err);
2232         return (Z_OK);
2233 }
2234 
2235 int
2236 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2237 {
2238         int err;
2239 
2240         if (tabptr == NULL)
2241                 return (Z_INVAL);
2242 
2243         if ((err = operation_prep(handle)) != Z_OK)
2244                 return (err);
2245 
2246         if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK)
2247                 return (err);
2248 
2249         return (Z_OK);
2250 }
2251 
2252 static int
2253 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2254 {
2255         xmlNodePtr cur = handle->zone_dh_cur;
2256         boolean_t addr_match, phys_match, allowed_addr_match;
2257 
2258         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2259                 if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2260                         continue;
2261 
2262                 addr_match = match_prop(cur, DTD_ATTR_ADDRESS,
2263                     tabptr->zone_nwif_address);
2264                 allowed_addr_match = match_prop(cur, DTD_ATTR_ALLOWED_ADDRESS,
2265                     tabptr->zone_nwif_allowed_address);
2266                 phys_match = match_prop(cur, DTD_ATTR_PHYSICAL,
2267                     tabptr->zone_nwif_physical);
2268 
2269                 if (addr_match && allowed_addr_match && phys_match) {
2270                         xmlUnlinkNode(cur);
2271                         xmlFreeNode(cur);
2272                         return (Z_OK);
2273                 }
2274         }
2275         return (Z_NO_RESOURCE_ID);
2276 }
2277 
2278 int
2279 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2280 {
2281         int err;
2282 
2283         if (tabptr == NULL)
2284                 return (Z_INVAL);
2285 
2286         if ((err = operation_prep(handle)) != Z_OK)
2287                 return (err);
2288 
2289         if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK)
2290                 return (err);
2291 
2292         return (Z_OK);
2293 }
2294 
2295 int
2296 zonecfg_modify_nwif(
2297         zone_dochandle_t handle,
2298         struct zone_nwiftab *oldtabptr,
2299         struct zone_nwiftab *newtabptr)
2300 {
2301         int err;
2302 
2303         if (oldtabptr == NULL || newtabptr == NULL)
2304                 return (Z_INVAL);
2305 
2306         if ((err = operation_prep(handle)) != Z_OK)
2307                 return (err);
2308 
2309         if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK)
2310                 return (err);
2311 
2312         if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK)
2313                 return (err);
2314 
2315         return (Z_OK);
2316 }
2317 
2318 /*
2319  * Must be a comma-separated list of alpha-numeric file system names.
2320  */
2321 static int
2322 zonecfg_valid_fs_allowed(const char *fsallowedp)
2323 {
2324         char tmp[ZONE_FS_ALLOWED_MAX];
2325         char *cp = tmp;
2326         char *p;
2327 
2328         if (strlen(fsallowedp) > ZONE_FS_ALLOWED_MAX)
2329                 return (Z_TOO_BIG);
2330 
2331         (void) strlcpy(tmp, fsallowedp, sizeof (tmp));
2332 
2333         while (*cp != '\0') {
2334                 p = cp;
2335                 while (*p != '\0' && *p != ',') {
2336                         if (!isalnum(*p) && *p != '-')
2337                                 return (Z_INVALID_PROPERTY);
2338                         p++;
2339                 }
2340 
2341                 if (*p == ',') {
2342                         if (p == cp)
2343                                 return (Z_INVALID_PROPERTY);
2344 
2345                         p++;
2346 
2347                         if (*p == '\0')
2348                                 return (Z_INVALID_PROPERTY);
2349                 }
2350 
2351                 cp = p;
2352         }
2353 
2354         return (Z_OK);
2355 }
2356 
2357 int
2358 zonecfg_get_fs_allowed(zone_dochandle_t handle, char *bufp, size_t buflen)
2359 {
2360         int err;
2361 
2362         if ((err = getrootattr(handle, DTD_ATTR_FS_ALLOWED,
2363             bufp, buflen)) != Z_OK)
2364                 return (err);
2365         if (bufp[0] == '\0')
2366                 return (Z_BAD_PROPERTY);
2367         return (zonecfg_valid_fs_allowed(bufp));
2368 }
2369 
2370 int
2371 zonecfg_set_fs_allowed(zone_dochandle_t handle, const char *bufp)
2372 {
2373         int err;
2374 
2375         if (bufp == NULL || (err = zonecfg_valid_fs_allowed(bufp)) == Z_OK)
2376                 return (setrootattr(handle, DTD_ATTR_FS_ALLOWED, bufp));
2377         return (err);
2378 }
2379 
2380 /*
2381  * Determines if the specified string is a valid hostid string.  This function
2382  * returns Z_OK if the string is a valid hostid string.  It returns Z_INVAL if
2383  * 'hostidp' is NULL, Z_TOO_BIG if 'hostidp' refers to a string buffer
2384  * containing a hex string with more than 8 digits, and Z_INVALID_PROPERTY if
2385  * the string has an invalid format.
2386  */
2387 static int
2388 zonecfg_valid_hostid(const char *hostidp)
2389 {
2390         char *currentp;
2391         u_longlong_t hostidval;
2392         size_t len;
2393 
2394         if (hostidp == NULL)
2395                 return (Z_INVAL);
2396 
2397         /* Empty strings and strings with whitespace are invalid. */
2398         if (*hostidp == '\0')
2399                 return (Z_INVALID_PROPERTY);
2400         for (currentp = (char *)hostidp; *currentp != '\0'; ++currentp) {
2401                 if (isspace(*currentp))
2402                         return (Z_INVALID_PROPERTY);
2403         }
2404         len = (size_t)(currentp - hostidp);
2405 
2406         /*
2407          * The caller might pass a hostid that is larger than the maximum
2408          * unsigned 32-bit integral value.  Check for this!  Also, make sure
2409          * that the whole string is converted (this helps us find illegal
2410          * characters) and that the whole string fits within a buffer of size
2411          * HW_HOSTID_LEN.
2412          */
2413         currentp = (char *)hostidp;
2414         if (strncmp(hostidp, "0x", 2) == 0 || strncmp(hostidp, "0X", 2) == 0)
2415                 currentp += 2;
2416         hostidval = strtoull(currentp, &currentp, 16);
2417         if ((size_t)(currentp - hostidp) >= HW_HOSTID_LEN)
2418                 return (Z_TOO_BIG);
2419         if (hostidval > UINT_MAX || hostidval == HW_INVALID_HOSTID ||
2420             currentp != hostidp + len)
2421                 return (Z_INVALID_PROPERTY);
2422         return (Z_OK);
2423 }
2424 
2425 /*
2426  * Gets the zone hostid string stored in the specified zone configuration
2427  * document.  This function returns Z_OK on success.  Z_BAD_PROPERTY is returned
2428  * if the config file doesn't specify a hostid or if the hostid is blank.
2429  *
2430  * Note that buflen should be at least HW_HOSTID_LEN.
2431  */
2432 int
2433 zonecfg_get_hostid(zone_dochandle_t handle, char *bufp, size_t buflen)
2434 {
2435         int err;
2436 
2437         if ((err = getrootattr(handle, DTD_ATTR_HOSTID, bufp, buflen)) != Z_OK)
2438                 return (err);
2439         if (bufp[0] == '\0')
2440                 return (Z_BAD_PROPERTY);
2441         return (zonecfg_valid_hostid(bufp));
2442 }
2443 
2444 /*
2445  * Sets the hostid string in the specified zone config document to the given
2446  * string value.  If 'hostidp' is NULL, then the config document's hostid
2447  * attribute is cleared.  Non-NULL hostids are validated.  This function returns
2448  * Z_OK on success.  Any other return value indicates failure.
2449  */
2450 int
2451 zonecfg_set_hostid(zone_dochandle_t handle, const char *hostidp)
2452 {
2453         int err;
2454 
2455         /*
2456          * A NULL hostid string is interpreted as a request to clear the
2457          * hostid.
2458          */
2459         if (hostidp == NULL || (err = zonecfg_valid_hostid(hostidp)) == Z_OK)
2460                 return (setrootattr(handle, DTD_ATTR_HOSTID, hostidp));
2461         return (err);
2462 }
2463 
2464 int
2465 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2466 {
2467         xmlNodePtr cur, firstmatch;
2468         int err;
2469         char match[MAXPATHLEN];
2470 
2471         if (tabptr == NULL)
2472                 return (Z_INVAL);
2473 
2474         if ((err = operation_prep(handle)) != Z_OK)
2475                 return (err);
2476 
2477         cur = handle->zone_dh_cur;
2478         firstmatch = NULL;
2479         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2480                 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2481                         continue;
2482                 if (strlen(tabptr->zone_dev_match) == 0)
2483                         continue;
2484 
2485                 if ((fetchprop(cur, DTD_ATTR_MATCH, match,
2486                     sizeof (match)) == Z_OK)) {
2487                         if (strcmp(tabptr->zone_dev_match,
2488                             match) == 0) {
2489                                 if (firstmatch == NULL)
2490                                         firstmatch = cur;
2491                                 else if (firstmatch != cur)
2492                                         return (Z_INSUFFICIENT_SPEC);
2493                         } else {
2494                                 /*
2495                                  * If another property matched but this
2496                                  * one doesn't then reset firstmatch.
2497                                  */
2498                                 if (firstmatch == cur)
2499                                         firstmatch = NULL;
2500                         }
2501                 }
2502         }
2503         if (firstmatch == NULL)
2504                 return (Z_NO_RESOURCE_ID);
2505 
2506         cur = firstmatch;
2507 
2508         if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
2509             sizeof (tabptr->zone_dev_match))) != Z_OK)
2510                 return (err);
2511 
2512         return (Z_OK);
2513 }
2514 
2515 static int
2516 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
2517 {
2518         xmlNodePtr newnode, cur = handle->zone_dh_cur;
2519         int err;
2520 
2521         newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL);
2522 
2523         if ((err = newprop(newnode, DTD_ATTR_MATCH,
2524             tabptr->zone_dev_match)) != Z_OK)
2525                 return (err);
2526 
2527         return (Z_OK);
2528 }
2529 
2530 int
2531 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2532 {
2533         int err;
2534 
2535         if (tabptr == NULL)
2536                 return (Z_INVAL);
2537 
2538         if ((err = operation_prep(handle)) != Z_OK)
2539                 return (err);
2540 
2541         if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK)
2542                 return (err);
2543 
2544         return (Z_OK);
2545 }
2546 
2547 static int
2548 zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
2549 {
2550         xmlNodePtr cur = handle->zone_dh_cur;
2551         int match_match;
2552 
2553         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2554                 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2555                         continue;
2556 
2557                 match_match = match_prop(cur, DTD_ATTR_MATCH,
2558                     tabptr->zone_dev_match);
2559 
2560                 if (match_match) {
2561                         xmlUnlinkNode(cur);
2562                         xmlFreeNode(cur);
2563                         return (Z_OK);
2564                 }
2565         }
2566         return (Z_NO_RESOURCE_ID);
2567 }
2568 
2569 int
2570 zonecfg_delete_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2571 {
2572         int err;
2573 
2574         if (tabptr == NULL)
2575                 return (Z_INVAL);
2576 
2577         if ((err = operation_prep(handle)) != Z_OK)
2578                 return (err);
2579 
2580         if ((err = zonecfg_delete_dev_core(handle, tabptr)) != Z_OK)
2581                 return (err);
2582 
2583         return (Z_OK);
2584 }
2585 
2586 int
2587 zonecfg_modify_dev(
2588         zone_dochandle_t handle,
2589         struct zone_devtab *oldtabptr,
2590         struct zone_devtab *newtabptr)
2591 {
2592         int err;
2593 
2594         if (oldtabptr == NULL || newtabptr == NULL)
2595                 return (Z_INVAL);
2596 
2597         if ((err = operation_prep(handle)) != Z_OK)
2598                 return (err);
2599 
2600         if ((err = zonecfg_delete_dev_core(handle, oldtabptr)) != Z_OK)
2601                 return (err);
2602 
2603         if ((err = zonecfg_add_dev_core(handle, newtabptr)) != Z_OK)
2604                 return (err);
2605 
2606         return (Z_OK);
2607 }
2608 
2609 static int
2610 zonecfg_add_auth_core(zone_dochandle_t handle, struct zone_admintab *tabptr,
2611     char *zonename)
2612 {
2613         xmlNodePtr newnode, cur = handle->zone_dh_cur;
2614         int err;
2615 
2616         newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ADMIN, NULL);
2617         err = newprop(newnode, DTD_ATTR_USER, tabptr->zone_admin_user);
2618         if (err != Z_OK)
2619                 return (err);
2620         err = newprop(newnode, DTD_ATTR_AUTHS, tabptr->zone_admin_auths);
2621         if (err != Z_OK)
2622                 return (err);
2623         if ((err = zonecfg_remove_userauths(
2624             handle, tabptr->zone_admin_user, zonename, B_FALSE)) != Z_OK)
2625                 return (err);
2626         return (Z_OK);
2627 }
2628 
2629 int
2630 zonecfg_add_admin(zone_dochandle_t handle, struct zone_admintab *tabptr,
2631     char *zonename)
2632 {
2633         int err;
2634 
2635         if (tabptr == NULL)
2636                 return (Z_INVAL);
2637 
2638         if ((err = operation_prep(handle)) != Z_OK)
2639                 return (err);
2640 
2641         if ((err = zonecfg_add_auth_core(handle, tabptr,
2642             zonename)) != Z_OK)
2643                 return (err);
2644 
2645         return (Z_OK);
2646 }
2647 
2648 static int
2649 zonecfg_delete_auth_core(zone_dochandle_t handle, struct zone_admintab *tabptr,
2650     char *zonename)
2651 {
2652         xmlNodePtr cur = handle->zone_dh_cur;
2653         boolean_t auth_match;
2654         int err;
2655 
2656         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2657                 if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
2658                         continue;
2659                 auth_match = match_prop(cur, DTD_ATTR_USER,
2660                     tabptr->zone_admin_user);
2661                 if (auth_match) {
2662                         if ((err = zonecfg_insert_userauths(
2663                             handle, tabptr->zone_admin_user,
2664                             zonename)) != Z_OK)
2665                                 return (err);
2666                         xmlUnlinkNode(cur);
2667                         xmlFreeNode(cur);
2668                         return (Z_OK);
2669                 }
2670         }
2671         return (Z_NO_RESOURCE_ID);
2672 }
2673 
2674 int
2675 zonecfg_delete_admin(zone_dochandle_t handle, struct zone_admintab *tabptr,
2676     char *zonename)
2677 {
2678         int err;
2679 
2680         if (tabptr == NULL)
2681                 return (Z_INVAL);
2682 
2683         if ((err = operation_prep(handle)) != Z_OK)
2684                 return (err);
2685 
2686         if ((err = zonecfg_delete_auth_core(handle, tabptr, zonename)) != Z_OK)
2687                 return (err);
2688 
2689         return (Z_OK);
2690 }
2691 
2692 int
2693 zonecfg_modify_admin(zone_dochandle_t handle, struct zone_admintab *oldtabptr,
2694     struct zone_admintab *newtabptr, char *zonename)
2695 {
2696         int err;
2697 
2698         if (oldtabptr == NULL || newtabptr == NULL)
2699                 return (Z_INVAL);
2700 
2701         if ((err = operation_prep(handle)) != Z_OK)
2702                 return (err);
2703 
2704         if ((err = zonecfg_delete_auth_core(handle, oldtabptr, zonename))
2705             != Z_OK)
2706                 return (err);
2707 
2708         if ((err = zonecfg_add_auth_core(handle, newtabptr,
2709             zonename)) != Z_OK)
2710                 return (err);
2711 
2712         return (Z_OK);
2713 }
2714 
2715 int
2716 zonecfg_lookup_admin(zone_dochandle_t handle, struct zone_admintab *tabptr)
2717 {
2718         xmlNodePtr cur, firstmatch;
2719         int err;
2720         char user[MAXUSERNAME];
2721 
2722         if (tabptr == NULL)
2723                 return (Z_INVAL);
2724 
2725         if ((err = operation_prep(handle)) != Z_OK)
2726                 return (err);
2727 
2728         cur = handle->zone_dh_cur;
2729         firstmatch = NULL;
2730         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2731                 if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
2732                         continue;
2733                 if (strlen(tabptr->zone_admin_user) > 0) {
2734                         if ((fetchprop(cur, DTD_ATTR_USER, user,
2735                             sizeof (user)) == Z_OK) &&
2736                             (strcmp(tabptr->zone_admin_user, user) == 0)) {
2737                                 if (firstmatch == NULL)
2738                                         firstmatch = cur;
2739                                 else
2740                                         return (Z_INSUFFICIENT_SPEC);
2741                         }
2742                 }
2743         }
2744         if (firstmatch == NULL)
2745                 return (Z_NO_RESOURCE_ID);
2746 
2747         cur = firstmatch;
2748 
2749         if ((err = fetchprop(cur, DTD_ATTR_USER, tabptr->zone_admin_user,
2750             sizeof (tabptr->zone_admin_user))) != Z_OK)
2751                 return (err);
2752 
2753         if ((err = fetchprop(cur, DTD_ATTR_AUTHS, tabptr->zone_admin_auths,
2754             sizeof (tabptr->zone_admin_auths))) != Z_OK)
2755                 return (err);
2756 
2757         return (Z_OK);
2758 }
2759 
2760 static int
2761 zonecfg_add_secflags_core(zone_dochandle_t handle,
2762     struct zone_secflagstab *tabptr)
2763 {
2764         xmlNodePtr newnode, cur = handle->zone_dh_cur;
2765         int err;
2766 
2767         newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_SECFLAGS, NULL);
2768         err = newprop(newnode, DTD_ATTR_DEFAULT, tabptr->zone_secflags_default);
2769         if (err != Z_OK)
2770                 return (err);
2771         err = newprop(newnode, DTD_ATTR_LOWER, tabptr->zone_secflags_lower);
2772         if (err != Z_OK)
2773                 return (err);
2774         err = newprop(newnode, DTD_ATTR_UPPER, tabptr->zone_secflags_upper);
2775         if (err != Z_OK)
2776                 return (err);
2777 
2778         return (Z_OK);
2779 }
2780 
2781 int
2782 zonecfg_add_secflags(zone_dochandle_t handle, struct zone_secflagstab *tabptr)
2783 {
2784         int err;
2785 
2786 
2787         if (tabptr == NULL)
2788                 return (Z_INVAL);
2789 
2790         if ((err = operation_prep(handle)) != Z_OK)
2791                 return (err);
2792 
2793         if ((err = zonecfg_add_secflags_core(handle, tabptr)) != Z_OK)
2794                 return (err);
2795 
2796         return (Z_OK);
2797 }
2798 
2799 static int
2800 zonecfg_delete_secflags_core(zone_dochandle_t handle,
2801     struct zone_secflagstab *tabptr)
2802 {
2803         xmlNodePtr cur = handle->zone_dh_cur;
2804         boolean_t def_match, low_match, up_match;
2805 
2806         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2807                 if (xmlStrcmp(cur->name, DTD_ELEM_SECFLAGS) != 0)
2808                         continue;
2809 
2810                 def_match = match_prop(cur, DTD_ATTR_DEFAULT,
2811                     tabptr->zone_secflags_default);
2812                 low_match = match_prop(cur, DTD_ATTR_LOWER,
2813                     tabptr->zone_secflags_lower);
2814                 up_match = match_prop(cur, DTD_ATTR_UPPER,
2815                     tabptr->zone_secflags_upper);
2816 
2817                 if (def_match && low_match && up_match) {
2818                         xmlUnlinkNode(cur);
2819                         xmlFreeNode(cur);
2820                         return (Z_OK);
2821                 }
2822 
2823         }
2824         return (Z_NO_RESOURCE_ID);
2825 }
2826 
2827 int
2828 zonecfg_delete_secflags(zone_dochandle_t handle,
2829     struct zone_secflagstab *tabptr)
2830 {
2831         int err;
2832 
2833         if (tabptr == NULL)
2834                 return (Z_INVAL);
2835 
2836         if ((err = operation_prep(handle)) != Z_OK)
2837                 return (err);
2838 
2839         if ((err = zonecfg_delete_secflags_core(handle, tabptr)) != Z_OK)
2840                 return (err);
2841 
2842         return (Z_OK);
2843 }
2844 
2845 int
2846 zonecfg_modify_secflags(zone_dochandle_t handle,
2847     struct zone_secflagstab *oldtabptr,
2848     struct zone_secflagstab *newtabptr)
2849 {
2850         int err;
2851 
2852         if (oldtabptr == NULL || newtabptr == NULL)
2853                 return (Z_INVAL);
2854 
2855         if ((err = operation_prep(handle)) != Z_OK)
2856                 return (err);
2857 
2858         if ((err = zonecfg_delete_secflags_core(handle, oldtabptr))
2859             != Z_OK)
2860                 return (err);
2861 
2862         if ((err = zonecfg_add_secflags_core(handle, newtabptr)) != Z_OK)
2863                 return (err);
2864 
2865         return (Z_OK);
2866 }
2867 
2868 int
2869 zonecfg_lookup_secflags(zone_dochandle_t handle,
2870     struct zone_secflagstab *tabptr)
2871 {
2872         xmlNodePtr cur;
2873         int err;
2874 
2875         if (tabptr == NULL)
2876                 return (Z_INVAL);
2877 
2878         if ((err = operation_prep(handle)) != Z_OK)
2879                 return (err);
2880 
2881         cur = handle->zone_dh_cur;
2882 
2883         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2884                 if (xmlStrcmp(cur->name, DTD_ELEM_SECFLAGS) != 0)
2885                         continue;
2886 
2887                 if ((err = fetchprop(cur, DTD_ATTR_DEFAULT,
2888                     tabptr->zone_secflags_default,
2889                     sizeof (tabptr->zone_secflags_default))) != Z_OK) {
2890                         handle->zone_dh_cur = handle->zone_dh_top;
2891                         return (err);
2892                 }
2893 
2894                 if ((err = fetchprop(cur, DTD_ATTR_LOWER,
2895                     tabptr->zone_secflags_lower,
2896                     sizeof (tabptr->zone_secflags_lower))) != Z_OK) {
2897                         handle->zone_dh_cur = handle->zone_dh_top;
2898                         return (err);
2899                 }
2900 
2901                 if ((err = fetchprop(cur, DTD_ATTR_UPPER,
2902                     tabptr->zone_secflags_upper,
2903                     sizeof (tabptr->zone_secflags_upper))) != Z_OK) {
2904                         handle->zone_dh_cur = handle->zone_dh_top;
2905                         return (err);
2906                 }
2907 
2908                 return (Z_OK);
2909         }
2910 
2911         return (Z_NO_ENTRY);
2912 }
2913 
2914 /* Lock to serialize all devwalks */
2915 static pthread_mutex_t zonecfg_devwalk_lock = PTHREAD_MUTEX_INITIALIZER;
2916 /*
2917  * Global variables used to pass data from zonecfg_dev_manifest to the nftw
2918  * call-back (zonecfg_devwalk_cb).  g_devwalk_data is really the void*
2919  * parameter and g_devwalk_cb is really the *cb parameter from
2920  * zonecfg_dev_manifest.
2921  */
2922 typedef struct __g_devwalk_data *g_devwalk_data_t;
2923 static g_devwalk_data_t g_devwalk_data;
2924 static int (*g_devwalk_cb)(const char *, uid_t, gid_t, mode_t, const char *,
2925     void *);
2926 static size_t g_devwalk_skip_prefix;
2927 
2928 /*
2929  * zonecfg_dev_manifest call-back function used during detach to generate the
2930  * dev info in the manifest.
2931  */
2932 static int
2933 get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode,
2934     const char *acl, void *hdl)
2935 {
2936         zone_dochandle_t handle = (zone_dochandle_t)hdl;
2937         xmlNodePtr newnode;
2938         xmlNodePtr cur;
2939         int err;
2940         char buf[128];
2941 
2942         if ((err = operation_prep(handle)) != Z_OK)
2943                 return (err);
2944 
2945         cur = handle->zone_dh_cur;
2946         newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL);
2947         if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK)
2948                 return (err);
2949         (void) snprintf(buf, sizeof (buf), "%lu", uid);
2950         if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK)
2951                 return (err);
2952         (void) snprintf(buf, sizeof (buf), "%lu", gid);
2953         if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK)
2954                 return (err);
2955         (void) snprintf(buf, sizeof (buf), "%o", mode);
2956         if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK)
2957                 return (err);
2958         if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK)
2959                 return (err);
2960         return (Z_OK);
2961 }
2962 
2963 /*
2964  * This is the nftw call-back function used by zonecfg_dev_manifest.  It is
2965  * responsible for calling the actual call-back.
2966  */
2967 /* ARGSUSED2 */
2968 static int
2969 zonecfg_devwalk_cb(const char *path, const struct stat *st, int f,
2970     struct FTW *ftw)
2971 {
2972         acl_t *acl;
2973         char *acl_txt = NULL;
2974 
2975         /* skip all but character and block devices */
2976         if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode))
2977                 return (0);
2978 
2979         if ((acl_get(path, ACL_NO_TRIVIAL, &acl) == 0) &&
2980             acl != NULL) {
2981                 acl_txt = acl_totext(acl, ACL_NORESOLVE);
2982                 acl_free(acl);
2983         }
2984 
2985         if (strlen(path) <= g_devwalk_skip_prefix)
2986                 return (0);
2987 
2988         (void) g_devwalk_cb(path + g_devwalk_skip_prefix, st->st_uid,
2989             st->st_gid, st->st_mode & S_IAMB, acl_txt != NULL ? acl_txt : "",
2990             g_devwalk_data);
2991         free(acl_txt);
2992         return (0);
2993 }
2994 
2995 /*
2996  * Walk the dev tree for the zone specified by hdl and call the
2997  * get_detach_dev_entry call-back function for each entry in the tree.  The
2998  * call-back will be passed the name, uid, gid, mode, acl string and the
2999  * handle input parameter for each dev entry.
3000  *
3001  * Data is passed to get_detach_dev_entry through the global variables
3002  * g_devwalk_data, *g_devwalk_cb, and g_devwalk_skip_prefix.  The
3003  * zonecfg_devwalk_cb function will actually call get_detach_dev_entry.
3004  */
3005 int
3006 zonecfg_dev_manifest(zone_dochandle_t hdl)
3007 {
3008         char path[MAXPATHLEN];
3009         int ret;
3010 
3011         if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK)
3012                 return (ret);
3013 
3014         if (strlcat(path, "/dev", sizeof (path)) >= sizeof (path))
3015                 return (Z_TOO_BIG);
3016 
3017         /*
3018          * We have to serialize all devwalks in the same process
3019          * (which should be fine), since nftw() is so badly designed.
3020          */
3021         (void) pthread_mutex_lock(&zonecfg_devwalk_lock);
3022 
3023         g_devwalk_skip_prefix = strlen(path) + 1;
3024         g_devwalk_data = (g_devwalk_data_t)hdl;
3025         g_devwalk_cb = get_detach_dev_entry;
3026         (void) nftw(path, zonecfg_devwalk_cb, 0, FTW_PHYS);
3027 
3028         (void) pthread_mutex_unlock(&zonecfg_devwalk_lock);
3029         return (Z_OK);
3030 }
3031 
3032 /*
3033  * Update the owner, group, mode and acl on the specified dev (inpath) for
3034  * the zone (hdl).  This function can be used to fix up the dev tree after
3035  * attaching a migrated zone.
3036  */
3037 int
3038 zonecfg_devperms_apply(zone_dochandle_t hdl, const char *inpath, uid_t owner,
3039     gid_t group, mode_t mode, const char *acltxt)
3040 {
3041         int ret;
3042         char path[MAXPATHLEN];
3043         struct stat st;
3044         acl_t *aclp;
3045 
3046         if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK)
3047                 return (ret);
3048 
3049         if (strlcat(path, "/dev/", sizeof (path)) >= sizeof (path))
3050                 return (Z_TOO_BIG);
3051         if (strlcat(path, inpath, sizeof (path)) >= sizeof (path))
3052                 return (Z_TOO_BIG);
3053 
3054         if (stat(path, &st) == -1)
3055                 return (Z_INVAL);
3056 
3057         /* make sure we're only touching device nodes */
3058         if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode))
3059                 return (Z_INVAL);
3060 
3061         if (chown(path, owner, group) == -1)
3062                 return (Z_SYSTEM);
3063 
3064         if (chmod(path, mode) == -1)
3065                 return (Z_SYSTEM);
3066 
3067         if ((acltxt == NULL) || (strcmp(acltxt, "") == 0))
3068                 return (Z_OK);
3069 
3070         if (acl_fromtext(acltxt, &aclp) != 0) {
3071                 errno = EINVAL;
3072                 return (Z_SYSTEM);
3073         }
3074 
3075         errno = 0;
3076         if (acl_set(path, aclp) == -1) {
3077                 free(aclp);
3078                 return (Z_SYSTEM);
3079         }
3080 
3081         free(aclp);
3082         return (Z_OK);
3083 }
3084 
3085 /*
3086  * This function finds everything mounted under a zone's rootpath.
3087  * This returns the number of mounts under rootpath, or -1 on error.
3088  * callback is called once per mount found with the first argument
3089  * pointing to a mnttab structure containing the mount's information.
3090  *
3091  * If the callback function returns non-zero zonecfg_find_mounts
3092  * aborts with an error.
3093  */
3094 int
3095 zonecfg_find_mounts(char *rootpath, int (*callback)(const struct mnttab *,
3096     void *), void *priv)
3097 {
3098         FILE *mnttab;
3099         struct mnttab m;
3100         size_t l;
3101         int zfsl;
3102         int rv = 0;
3103         char zfs_path[MAXPATHLEN];
3104 
3105         assert(rootpath != NULL);
3106 
3107         if ((zfsl = snprintf(zfs_path, sizeof (zfs_path), "%s/.zfs/", rootpath))
3108             >= sizeof (zfs_path))
3109                 return (-1);
3110 
3111         l = strlen(rootpath);
3112 
3113         mnttab = fopen("/etc/mnttab", "r");
3114 
3115         if (mnttab == NULL)
3116                 return (-1);
3117 
3118         if (ioctl(fileno(mnttab), MNTIOC_SHOWHIDDEN, NULL) < 0)  {
3119                 rv = -1;
3120                 goto out;
3121         }
3122 
3123         while (!getmntent(mnttab, &m)) {
3124                 if ((strncmp(rootpath, m.mnt_mountp, l) == 0) &&
3125                     (m.mnt_mountp[l] == '/') &&
3126                     (strncmp(zfs_path, m.mnt_mountp, zfsl) != 0)) {
3127                         rv++;
3128                         if (callback == NULL)
3129                                 continue;
3130                         if (callback(&m, priv)) {
3131                                 rv = -1;
3132                                 goto out;
3133 
3134                         }
3135                 }
3136         }
3137 
3138 out:
3139         (void) fclose(mnttab);
3140         return (rv);
3141 }
3142 
3143 int
3144 zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3145 {
3146         xmlNodePtr cur, firstmatch;
3147         int err;
3148         char name[MAXNAMELEN], type[MAXNAMELEN], value[MAXNAMELEN];
3149 
3150         if (tabptr == NULL)
3151                 return (Z_INVAL);
3152 
3153         if ((err = operation_prep(handle)) != Z_OK)
3154                 return (err);
3155 
3156         cur = handle->zone_dh_cur;
3157         firstmatch = NULL;
3158         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
3159                 if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
3160                         continue;
3161                 if (strlen(tabptr->zone_attr_name) > 0) {
3162                         if ((fetchprop(cur, DTD_ATTR_NAME, name,
3163                             sizeof (name)) == Z_OK) &&
3164                             (strcmp(tabptr->zone_attr_name, name) == 0)) {
3165                                 if (firstmatch == NULL)
3166                                         firstmatch = cur;
3167                                 else
3168                                         return (Z_INSUFFICIENT_SPEC);
3169                         }
3170                 }
3171                 if (strlen(tabptr->zone_attr_type) > 0) {
3172                         if ((fetchprop(cur, DTD_ATTR_TYPE, type,
3173                             sizeof (type)) == Z_OK)) {
3174                                 if (strcmp(tabptr->zone_attr_type, type) == 0) {
3175                                         if (firstmatch == NULL)
3176                                                 firstmatch = cur;
3177                                         else if (firstmatch != cur)
3178                                                 return (Z_INSUFFICIENT_SPEC);
3179                                 } else {
3180                                         /*
3181                                          * If another property matched but this
3182                                          * one doesn't then reset firstmatch.
3183                                          */
3184                                         if (firstmatch == cur)
3185                                                 firstmatch = NULL;
3186                                 }
3187                         }
3188                 }
3189                 if (strlen(tabptr->zone_attr_value) > 0) {
3190                         if ((fetchprop(cur, DTD_ATTR_VALUE, value,
3191                             sizeof (value)) == Z_OK)) {
3192                                 if (strcmp(tabptr->zone_attr_value, value) ==
3193                                     0) {
3194                                         if (firstmatch == NULL)
3195                                                 firstmatch = cur;
3196                                         else if (firstmatch != cur)
3197                                                 return (Z_INSUFFICIENT_SPEC);
3198                                 } else {
3199                                         /*
3200                                          * If another property matched but this
3201                                          * one doesn't then reset firstmatch.
3202                                          */
3203                                         if (firstmatch == cur)
3204                                                 firstmatch = NULL;
3205                                 }
3206                         }
3207                 }
3208         }
3209         if (firstmatch == NULL)
3210                 return (Z_NO_RESOURCE_ID);
3211 
3212         cur = firstmatch;
3213 
3214         if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
3215             sizeof (tabptr->zone_attr_name))) != Z_OK)
3216                 return (err);
3217 
3218         if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
3219             sizeof (tabptr->zone_attr_type))) != Z_OK)
3220                 return (err);
3221 
3222         if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
3223             sizeof (tabptr->zone_attr_value))) != Z_OK)
3224                 return (err);
3225 
3226         return (Z_OK);
3227 }
3228 
3229 static int
3230 zonecfg_add_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3231 {
3232         xmlNodePtr newnode, cur = handle->zone_dh_cur;
3233         int err;
3234 
3235         newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ATTR, NULL);
3236         err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_attr_name);
3237         if (err != Z_OK)
3238                 return (err);
3239         err = newprop(newnode, DTD_ATTR_TYPE, tabptr->zone_attr_type);
3240         if (err != Z_OK)
3241                 return (err);
3242         err = newprop(newnode, DTD_ATTR_VALUE, tabptr->zone_attr_value);
3243         if (err != Z_OK)
3244                 return (err);
3245         return (Z_OK);
3246 }
3247 
3248 int
3249 zonecfg_add_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3250 {
3251         int err;
3252 
3253         if (tabptr == NULL)
3254                 return (Z_INVAL);
3255 
3256         if ((err = operation_prep(handle)) != Z_OK)
3257                 return (err);
3258 
3259         if ((err = zonecfg_add_attr_core(handle, tabptr)) != Z_OK)
3260                 return (err);
3261 
3262         return (Z_OK);
3263 }
3264 
3265 static int
3266 zonecfg_delete_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3267 {
3268         xmlNodePtr cur = handle->zone_dh_cur;
3269         int name_match, type_match, value_match;
3270 
3271         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
3272                 if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
3273                         continue;
3274 
3275                 name_match = match_prop(cur, DTD_ATTR_NAME,
3276                     tabptr->zone_attr_name);
3277                 type_match = match_prop(cur, DTD_ATTR_TYPE,
3278                     tabptr->zone_attr_type);
3279                 value_match = match_prop(cur, DTD_ATTR_VALUE,
3280                     tabptr->zone_attr_value);
3281 
3282                 if (name_match && type_match && value_match) {
3283                         xmlUnlinkNode(cur);
3284                         xmlFreeNode(cur);
3285                         return (Z_OK);
3286                 }
3287         }
3288         return (Z_NO_RESOURCE_ID);
3289 }
3290 
3291 int
3292 zonecfg_delete_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3293 {
3294         int err;
3295 
3296         if (tabptr == NULL)
3297                 return (Z_INVAL);
3298 
3299         if ((err = operation_prep(handle)) != Z_OK)
3300                 return (err);
3301 
3302         if ((err = zonecfg_delete_attr_core(handle, tabptr)) != Z_OK)
3303                 return (err);
3304 
3305         return (Z_OK);
3306 }
3307 
3308 int
3309 zonecfg_modify_attr(
3310         zone_dochandle_t handle,
3311         struct zone_attrtab *oldtabptr,
3312         struct zone_attrtab *newtabptr)
3313 {
3314         int err;
3315 
3316         if (oldtabptr == NULL || newtabptr == NULL)
3317                 return (Z_INVAL);
3318 
3319         if ((err = operation_prep(handle)) != Z_OK)
3320                 return (err);
3321 
3322         if ((err = zonecfg_delete_attr_core(handle, oldtabptr)) != Z_OK)
3323                 return (err);
3324 
3325         if ((err = zonecfg_add_attr_core(handle, newtabptr)) != Z_OK)
3326                 return (err);
3327 
3328         return (Z_OK);
3329 }
3330 
3331 int
3332 zonecfg_get_attr_boolean(const struct zone_attrtab *attr, boolean_t *value)
3333 {
3334         if (attr == NULL)
3335                 return (Z_INVAL);
3336 
3337         if (strcmp(attr->zone_attr_type, DTD_ENTITY_BOOLEAN) != 0)
3338                 return (Z_INVAL);
3339 
3340         if (strcmp(attr->zone_attr_value, DTD_ENTITY_TRUE) == 0) {
3341                 *value = B_TRUE;
3342                 return (Z_OK);
3343         }
3344         if (strcmp(attr->zone_attr_value, DTD_ENTITY_FALSE) == 0) {
3345                 *value = B_FALSE;
3346                 return (Z_OK);
3347         }
3348         return (Z_INVAL);
3349 }
3350 
3351 int
3352 zonecfg_get_attr_int(const struct zone_attrtab *attr, int64_t *value)
3353 {
3354         long long result;
3355         char *endptr;
3356 
3357         if (attr == NULL)
3358                 return (Z_INVAL);
3359 
3360         if (strcmp(attr->zone_attr_type, DTD_ENTITY_INT) != 0)
3361                 return (Z_INVAL);
3362 
3363         errno = 0;
3364         result = strtoll(attr->zone_attr_value, &endptr, 10);
3365         if (errno != 0 || *endptr != '\0')
3366                 return (Z_INVAL);
3367         *value = result;
3368         return (Z_OK);
3369 }
3370 
3371 int
3372 zonecfg_get_attr_string(const struct zone_attrtab *attr, char *value,
3373     size_t val_sz)
3374 {
3375         if (attr == NULL)
3376                 return (Z_INVAL);
3377 
3378         if (strcmp(attr->zone_attr_type, DTD_ENTITY_STRING) != 0)
3379                 return (Z_INVAL);
3380 
3381         if (strlcpy(value, attr->zone_attr_value, val_sz) >= val_sz)
3382                 return (Z_TOO_BIG);
3383         return (Z_OK);
3384 }
3385 
3386 int
3387 zonecfg_get_attr_uint(const struct zone_attrtab *attr, uint64_t *value)
3388 {
3389         unsigned long long result;
3390         long long neg_result;
3391         char *endptr;
3392 
3393         if (attr == NULL)
3394                 return (Z_INVAL);
3395 
3396         if (strcmp(attr->zone_attr_type, DTD_ENTITY_UINT) != 0)
3397                 return (Z_INVAL);
3398 
3399         errno = 0;
3400         result = strtoull(attr->zone_attr_value, &endptr, 10);
3401         if (errno != 0 || *endptr != '\0')
3402                 return (Z_INVAL);
3403         errno = 0;
3404         neg_result = strtoll(attr->zone_attr_value, &endptr, 10);
3405         /*
3406          * Incredibly, strtoull("<negative number>", ...) will not fail but
3407          * return whatever (negative) number cast as a u_longlong_t, so we
3408          * need to look for this here.
3409          */
3410         if (errno == 0 && neg_result < 0)
3411                 return (Z_INVAL);
3412         *value = result;
3413         return (Z_OK);
3414 }
3415 
3416 int
3417 zonecfg_lookup_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3418 {
3419         xmlNodePtr cur, val;
3420         char savedname[MAXNAMELEN];
3421         struct zone_rctlvaltab *valptr;
3422         int err;
3423 
3424         if (strlen(tabptr->zone_rctl_name) == 0)
3425                 return (Z_INVAL);
3426 
3427         if ((err = operation_prep(handle)) != Z_OK)
3428                 return (err);
3429 
3430         cur = handle->zone_dh_cur;
3431         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
3432                 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL))
3433                         continue;
3434                 if ((fetchprop(cur, DTD_ATTR_NAME, savedname,
3435                     sizeof (savedname)) == Z_OK) &&
3436                     (strcmp(savedname, tabptr->zone_rctl_name) == 0)) {
3437                         tabptr->zone_rctl_valptr = NULL;
3438                         for (val = cur->xmlChildrenNode; val != NULL;
3439                             val = val->next) {
3440                                 valptr = (struct zone_rctlvaltab *)malloc(
3441                                     sizeof (struct zone_rctlvaltab));
3442                                 if (valptr == NULL)
3443                                         return (Z_NOMEM);
3444                                 if ((fetchprop(val, DTD_ATTR_PRIV,
3445                                     valptr->zone_rctlval_priv,
3446                                     sizeof (valptr->zone_rctlval_priv)) !=
3447                                     Z_OK))
3448                                         break;
3449                                 if ((fetchprop(val, DTD_ATTR_LIMIT,
3450                                     valptr->zone_rctlval_limit,
3451                                     sizeof (valptr->zone_rctlval_limit)) !=
3452                                     Z_OK))
3453                                         break;
3454                                 if ((fetchprop(val, DTD_ATTR_ACTION,
3455                                     valptr->zone_rctlval_action,
3456                                     sizeof (valptr->zone_rctlval_action)) !=
3457                                     Z_OK))
3458                                         break;
3459                                 if (zonecfg_add_rctl_value(tabptr, valptr) !=
3460                                     Z_OK)
3461                                         break;
3462                         }
3463                         return (Z_OK);
3464                 }
3465         }
3466         return (Z_NO_RESOURCE_ID);
3467 }
3468 
3469 static int
3470 zonecfg_add_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3471 {
3472         xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode;
3473         struct zone_rctlvaltab *valptr;
3474         int err;
3475 
3476         newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_RCTL, NULL);
3477         err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_rctl_name);
3478         if (err != Z_OK)
3479                 return (err);
3480         for (valptr = tabptr->zone_rctl_valptr; valptr != NULL;
3481             valptr = valptr->zone_rctlval_next) {
3482                 valnode = xmlNewTextChild(newnode, NULL,
3483                     DTD_ELEM_RCTLVALUE, NULL);
3484                 err = newprop(valnode, DTD_ATTR_PRIV,
3485                     valptr->zone_rctlval_priv);
3486                 if (err != Z_OK)
3487                         return (err);
3488                 err = newprop(valnode, DTD_ATTR_LIMIT,
3489                     valptr->zone_rctlval_limit);
3490                 if (err != Z_OK)
3491                         return (err);
3492                 err = newprop(valnode, DTD_ATTR_ACTION,
3493                     valptr->zone_rctlval_action);
3494                 if (err != Z_OK)
3495                         return (err);
3496         }
3497         return (Z_OK);
3498 }
3499 
3500 int
3501 zonecfg_add_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3502 {
3503         int err;
3504 
3505         if (tabptr == NULL)
3506                 return (Z_INVAL);
3507 
3508         if ((err = operation_prep(handle)) != Z_OK)
3509                 return (err);
3510 
3511         if ((err = zonecfg_add_rctl_core(handle, tabptr)) != Z_OK)
3512                 return (err);
3513 
3514         return (Z_OK);
3515 }
3516 
3517 static int
3518 zonecfg_delete_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3519 {
3520         xmlNodePtr cur = handle->zone_dh_cur;
3521         xmlChar *savedname;
3522         int name_result;
3523 
3524         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
3525                 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL))
3526                         continue;
3527 
3528                 savedname = xmlGetProp(cur, DTD_ATTR_NAME);
3529                 if (savedname == NULL)  /* shouldn't happen */
3530                         continue;
3531                 name_result = xmlStrcmp(savedname,
3532                     (const xmlChar *) tabptr->zone_rctl_name);
3533                 xmlFree(savedname);
3534 
3535                 if (name_result == 0) {
3536                         xmlUnlinkNode(cur);
3537                         xmlFreeNode(cur);
3538                         return (Z_OK);
3539                 }
3540         }
3541         return (Z_NO_RESOURCE_ID);
3542 }
3543 
3544 int
3545 zonecfg_delete_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
3546 {
3547         int err;
3548 
3549         if (tabptr == NULL)
3550                 return (Z_INVAL);
3551 
3552         if ((err = operation_prep(handle)) != Z_OK)
3553                 return (err);
3554 
3555         if ((err = zonecfg_delete_rctl_core(handle, tabptr)) != Z_OK)
3556                 return (err);
3557 
3558         return (Z_OK);
3559 }
3560 
3561 int
3562 zonecfg_modify_rctl(
3563         zone_dochandle_t handle,
3564         struct zone_rctltab *oldtabptr,
3565         struct zone_rctltab *newtabptr)
3566 {
3567         int err;
3568 
3569         if (oldtabptr == NULL || newtabptr == NULL)
3570                 return (Z_INVAL);
3571 
3572         if ((err = operation_prep(handle)) != Z_OK)
3573                 return (err);
3574 
3575         if ((err = zonecfg_delete_rctl_core(handle, oldtabptr)) != Z_OK)
3576                 return (err);
3577 
3578         if ((err = zonecfg_add_rctl_core(handle, newtabptr)) != Z_OK)
3579                 return (err);
3580 
3581         return (Z_OK);
3582 }
3583 
3584 int
3585 zonecfg_add_rctl_value(
3586         struct zone_rctltab *tabptr,
3587         struct zone_rctlvaltab *valtabptr)
3588 {
3589         struct zone_rctlvaltab *last, *old, *new;
3590         rctlblk_t *rctlblk = alloca(rctlblk_size());
3591 
3592         last = tabptr->zone_rctl_valptr;
3593         for (old = last; old != NULL; old = old->zone_rctlval_next)
3594                 last = old;     /* walk to the end of the list */
3595         new = valtabptr;        /* alloc'd by caller */
3596         new->zone_rctlval_next = NULL;
3597         if (zonecfg_construct_rctlblk(valtabptr, rctlblk) != Z_OK)
3598                 return (Z_INVAL);
3599         if (!zonecfg_valid_rctlblk(rctlblk))
3600                 return (Z_INVAL);
3601         if (last == NULL)
3602                 tabptr->zone_rctl_valptr = new;
3603         else
3604                 last->zone_rctlval_next = new;
3605         return (Z_OK);
3606 }
3607 
3608 int
3609 zonecfg_remove_rctl_value(
3610         struct zone_rctltab *tabptr,
3611         struct zone_rctlvaltab *valtabptr)
3612 {
3613         struct zone_rctlvaltab *last, *this, *next;
3614 
3615         last = tabptr->zone_rctl_valptr;
3616         for (this = last; this != NULL; this = this->zone_rctlval_next) {
3617                 if (strcmp(this->zone_rctlval_priv,
3618                     valtabptr->zone_rctlval_priv) == 0 &&
3619                     strcmp(this->zone_rctlval_limit,
3620                     valtabptr->zone_rctlval_limit) == 0 &&
3621                     strcmp(this->zone_rctlval_action,
3622                     valtabptr->zone_rctlval_action) == 0) {
3623                         next = this->zone_rctlval_next;
3624                         if (this == tabptr->zone_rctl_valptr)
3625                                 tabptr->zone_rctl_valptr = next;
3626                         else
3627                                 last->zone_rctlval_next = next;
3628                         free(this);
3629                         return (Z_OK);
3630                 } else
3631                         last = this;
3632         }
3633         return (Z_NO_PROPERTY_ID);
3634 }
3635 
3636 void
3637 zonecfg_set_swinv(zone_dochandle_t handle)
3638 {
3639         handle->zone_dh_sw_inv = B_TRUE;
3640 }
3641 
3642 /*
3643  * Add the pkg to the sw inventory on the handle.
3644  */
3645 int
3646 zonecfg_add_pkg(zone_dochandle_t handle, char *name, char *version)
3647 {
3648         xmlNodePtr newnode;
3649         xmlNodePtr cur;
3650         int err;
3651 
3652         if ((err = operation_prep(handle)) != Z_OK)
3653                 return (err);
3654 
3655         cur = handle->zone_dh_cur;
3656         newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL);
3657         if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK)
3658                 return (err);
3659         if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK)
3660                 return (err);
3661         return (Z_OK);
3662 }
3663 
3664 char *
3665 zonecfg_strerror(int errnum)
3666 {
3667         switch (errnum) {
3668         case Z_OK:
3669                 return (dgettext(TEXT_DOMAIN, "OK"));
3670         case Z_EMPTY_DOCUMENT:
3671                 return (dgettext(TEXT_DOMAIN, "Empty document"));
3672         case Z_WRONG_DOC_TYPE:
3673                 return (dgettext(TEXT_DOMAIN, "Wrong document type"));
3674         case Z_BAD_PROPERTY:
3675                 return (dgettext(TEXT_DOMAIN, "Bad document property"));
3676         case Z_TEMP_FILE:
3677                 return (dgettext(TEXT_DOMAIN,
3678                     "Problem creating temporary file"));
3679         case Z_SAVING_FILE:
3680                 return (dgettext(TEXT_DOMAIN, "Problem saving file"));
3681         case Z_NO_ENTRY:
3682                 return (dgettext(TEXT_DOMAIN, "No such entry"));
3683         case Z_BOGUS_ZONE_NAME:
3684                 return (dgettext(TEXT_DOMAIN, "Bogus zone name"));
3685         case Z_REQD_RESOURCE_MISSING:
3686                 return (dgettext(TEXT_DOMAIN, "Required resource missing"));
3687         case Z_REQD_PROPERTY_MISSING:
3688                 return (dgettext(TEXT_DOMAIN, "Required property missing"));
3689         case Z_BAD_HANDLE:
3690                 return (dgettext(TEXT_DOMAIN, "Bad handle"));
3691         case Z_NOMEM:
3692                 return (dgettext(TEXT_DOMAIN, "Out of memory"));
3693         case Z_INVAL:
3694                 return (dgettext(TEXT_DOMAIN, "Invalid argument"));
3695         case Z_ACCES:
3696                 return (dgettext(TEXT_DOMAIN, "Permission denied"));
3697         case Z_TOO_BIG:
3698                 return (dgettext(TEXT_DOMAIN, "Argument list too long"));
3699         case Z_MISC_FS:
3700                 return (dgettext(TEXT_DOMAIN,
3701                     "Miscellaneous file system error"));
3702         case Z_NO_ZONE:
3703                 return (dgettext(TEXT_DOMAIN, "No such zone configured"));
3704         case Z_NO_RESOURCE_TYPE:
3705                 return (dgettext(TEXT_DOMAIN, "No such resource type"));
3706         case Z_NO_RESOURCE_ID:
3707                 return (dgettext(TEXT_DOMAIN, "No such resource with that id"));
3708         case Z_NO_PROPERTY_TYPE:
3709                 return (dgettext(TEXT_DOMAIN, "No such property type"));
3710         case Z_NO_PROPERTY_ID:
3711                 return (dgettext(TEXT_DOMAIN, "No such property with that id"));
3712         case Z_BAD_ZONE_STATE:
3713                 return (dgettext(TEXT_DOMAIN,
3714                     "Zone state is invalid for the requested operation"));
3715         case Z_INVALID_DOCUMENT:
3716                 return (dgettext(TEXT_DOMAIN, "Invalid document"));
3717         case Z_NAME_IN_USE:
3718                 return (dgettext(TEXT_DOMAIN, "Zone name already in use"));
3719         case Z_NO_SUCH_ID:
3720                 return (dgettext(TEXT_DOMAIN, "No such zone ID"));
3721         case Z_UPDATING_INDEX:
3722                 return (dgettext(TEXT_DOMAIN, "Problem updating index file"));
3723         case Z_LOCKING_FILE:
3724                 return (dgettext(TEXT_DOMAIN, "Locking index file"));
3725         case Z_UNLOCKING_FILE:
3726                 return (dgettext(TEXT_DOMAIN, "Unlocking index file"));
3727         case Z_INSUFFICIENT_SPEC:
3728                 return (dgettext(TEXT_DOMAIN, "Insufficient specification"));
3729         case Z_RESOLVED_PATH:
3730                 return (dgettext(TEXT_DOMAIN, "Resolved path mismatch"));
3731         case Z_IPV6_ADDR_PREFIX_LEN:
3732                 return (dgettext(TEXT_DOMAIN,
3733                     "IPv6 address missing required prefix length"));
3734         case Z_BOGUS_ADDRESS:
3735                 return (dgettext(TEXT_DOMAIN,
3736                     "Neither an IPv4 nor an IPv6 address nor a host name"));
3737         case Z_PRIV_PROHIBITED:
3738                 return (dgettext(TEXT_DOMAIN,
3739                     "Specified privilege is prohibited"));
3740         case Z_PRIV_REQUIRED:
3741                 return (dgettext(TEXT_DOMAIN,
3742                     "Required privilege is missing"));
3743         case Z_PRIV_UNKNOWN:
3744                 return (dgettext(TEXT_DOMAIN,
3745                     "Specified privilege is unknown"));
3746         case Z_BRAND_ERROR:
3747                 return (dgettext(TEXT_DOMAIN,
3748                     "Brand-specific error"));
3749         case Z_INCOMPATIBLE:
3750                 return (dgettext(TEXT_DOMAIN, "Incompatible settings"));
3751         case Z_ALIAS_DISALLOW:
3752                 return (dgettext(TEXT_DOMAIN,
3753                     "An incompatible rctl already exists for this property"));
3754         case Z_CLEAR_DISALLOW:
3755                 return (dgettext(TEXT_DOMAIN,
3756                     "Clearing this property is not allowed"));
3757         case Z_POOL:
3758                 return (dgettext(TEXT_DOMAIN, "libpool(3LIB) error"));
3759         case Z_POOLS_NOT_ACTIVE:
3760                 return (dgettext(TEXT_DOMAIN, "Pools facility not active; "
3761                     "zone will not be bound to pool"));
3762         case Z_POOL_ENABLE:
3763                 return (dgettext(TEXT_DOMAIN,
3764                     "Could not enable pools facility"));
3765         case Z_NO_POOL:
3766                 return (dgettext(TEXT_DOMAIN,
3767                     "Pool not found; using default pool"));
3768         case Z_POOL_CREATE:
3769                 return (dgettext(TEXT_DOMAIN,
3770                     "Could not create a temporary pool"));
3771         case Z_POOL_BIND:
3772                 return (dgettext(TEXT_DOMAIN, "Could not bind zone to pool"));
3773         case Z_INVALID_PROPERTY:
3774                 return (dgettext(TEXT_DOMAIN, "Specified property is invalid"));
3775         case Z_SYSTEM:
3776                 return (strerror(errno));
3777         default:
3778                 return (dgettext(TEXT_DOMAIN, "Unknown error"));
3779         }
3780 }
3781 
3782 /*
3783  * Note that the zonecfg_setXent() and zonecfg_endXent() calls are all the
3784  * same, as they just turn around and call zonecfg_setent() / zonecfg_endent().
3785  */
3786 
3787 static int
3788 zonecfg_setent(zone_dochandle_t handle)
3789 {
3790         xmlNodePtr cur;
3791         int err;
3792 
3793         if (handle == NULL)
3794                 return (Z_INVAL);
3795 
3796         if ((err = operation_prep(handle)) != Z_OK) {
3797                 handle->zone_dh_cur = NULL;
3798                 return (err);
3799         }
3800         cur = handle->zone_dh_cur;
3801         cur = cur->xmlChildrenNode;
3802         handle->zone_dh_cur = cur;
3803         return (Z_OK);
3804 }
3805 
3806 static int
3807 zonecfg_endent(zone_dochandle_t handle)
3808 {
3809         if (handle == NULL)
3810                 return (Z_INVAL);
3811 
3812         handle->zone_dh_cur = handle->zone_dh_top;
3813         return (Z_OK);
3814 }
3815 
3816 /*
3817  * Do the work required to manipulate a process through libproc.
3818  * If grab_process() returns no errors (0), then release_process()
3819  * must eventually be called.
3820  *
3821  * Return values:
3822  *      0 Successful creation of agent thread
3823  *      1 Error grabbing
3824  *      2 Error creating agent
3825  */
3826 static int
3827 grab_process(pr_info_handle_t *p)
3828 {
3829         int ret;
3830 
3831         if ((p->pr = Pgrab(p->pid, 0, &ret)) != NULL) {
3832 
3833                 if (Psetflags(p->pr, PR_RLC) != 0) {
3834                         Prelease(p->pr, 0);
3835                         return (1);
3836                 }
3837                 if (Pcreate_agent(p->pr) == 0) {
3838                         return (0);
3839 
3840                 } else {
3841                         Prelease(p->pr, 0);
3842                         return (2);
3843                 }
3844         } else {
3845                 return (1);
3846         }
3847 }
3848 
3849 /*
3850  * Release the specified process. This destroys the agent
3851  * and releases the process. If the process is NULL, nothing
3852  * is done. This function should only be called if grab_process()
3853  * has previously been called and returned success.
3854  *
3855  * This function is Pgrab-safe.
3856  */
3857 static void
3858 release_process(struct ps_prochandle *Pr)
3859 {
3860         if (Pr == NULL)
3861                 return;
3862 
3863         Pdestroy_agent(Pr);
3864         Prelease(Pr, 0);
3865 }
3866 
3867 static boolean_t
3868 grab_zone_proc(char *zonename, pr_info_handle_t *p)
3869 {
3870         DIR *dirp;
3871         struct dirent *dentp;
3872         zoneid_t zoneid;
3873         int pid_self;
3874         psinfo_t psinfo;
3875 
3876         if (zone_get_id(zonename, &zoneid) != 0)
3877                 return (B_FALSE);
3878 
3879         pid_self = getpid();
3880 
3881         if ((dirp = opendir("/proc")) == NULL)
3882                 return (B_FALSE);
3883 
3884         while (dentp = readdir(dirp)) {
3885                 p->pid = atoi(dentp->d_name);
3886 
3887                 /* Skip self */
3888                 if (p->pid == pid_self)
3889                         continue;
3890 
3891                 if (proc_get_psinfo(p->pid, &psinfo) != 0)
3892                         continue;
3893 
3894                 if (psinfo.pr_zoneid != zoneid)
3895                         continue;
3896 
3897                 /* attempt to grab process */
3898                 if (grab_process(p) != 0)
3899                         continue;
3900 
3901                 if (pr_getzoneid(p->pr) != zoneid) {
3902                         release_process(p->pr);
3903                         continue;
3904                 }
3905 
3906                 (void) closedir(dirp);
3907                 return (B_TRUE);
3908         }
3909 
3910         (void) closedir(dirp);
3911         return (B_FALSE);
3912 }
3913 
3914 static boolean_t
3915 get_priv_rctl(struct ps_prochandle *pr, char *name, rctlblk_t *rblk)
3916 {
3917         if (pr_getrctl(pr, name, NULL, rblk, RCTL_FIRST))
3918                 return (B_FALSE);
3919 
3920         if (rctlblk_get_privilege(rblk) == RCPRIV_PRIVILEGED)
3921                 return (B_TRUE);
3922 
3923         while (pr_getrctl(pr, name, rblk, rblk, RCTL_NEXT) == 0) {
3924                 if (rctlblk_get_privilege(rblk) == RCPRIV_PRIVILEGED)
3925                         return (B_TRUE);
3926         }
3927 
3928         return (B_FALSE);
3929 }
3930 
3931 /*
3932  * Apply the current rctl settings to the specified, running zone.
3933  */
3934 int
3935 zonecfg_apply_rctls(char *zone_name, zone_dochandle_t handle)
3936 {
3937         int err;
3938         int res = Z_OK;
3939         rctlblk_t *rblk;
3940         pr_info_handle_t p;
3941         struct zone_rctltab rctl;
3942 
3943         if ((err = zonecfg_setrctlent(handle)) != Z_OK)
3944                 return (err);
3945 
3946         if ((rblk = (rctlblk_t *)malloc(rctlblk_size())) == NULL) {
3947                 (void) zonecfg_endrctlent(handle);
3948                 return (Z_NOMEM);
3949         }
3950 
3951         if (!grab_zone_proc(zone_name, &p)) {
3952                 (void) zonecfg_endrctlent(handle);
3953                 free(rblk);
3954                 return (Z_SYSTEM);
3955         }
3956 
3957         while (zonecfg_getrctlent(handle, &rctl) == Z_OK) {
3958                 char *rname;
3959                 struct zone_rctlvaltab *valptr;
3960 
3961                 rname = rctl.zone_rctl_name;
3962 
3963                 /* first delete all current privileged settings for this rctl */
3964                 while (get_priv_rctl(p.pr, rname, rblk)) {
3965                         if (pr_setrctl(p.pr, rname, NULL, rblk, RCTL_DELETE) !=
3966                             0) {
3967                                 res = Z_SYSTEM;
3968                                 goto done;
3969                         }
3970                 }
3971 
3972                 /* now set each new value for the rctl */
3973                 for (valptr = rctl.zone_rctl_valptr; valptr != NULL;
3974                     valptr = valptr->zone_rctlval_next) {
3975                         if ((err = zonecfg_construct_rctlblk(valptr, rblk))
3976                             != Z_OK) {
3977                                 res = errno = err;
3978                                 goto done;
3979                         }
3980 
3981                         if (pr_setrctl(p.pr, rname, NULL, rblk, RCTL_INSERT)) {
3982                                 res = Z_SYSTEM;
3983                                 goto done;
3984                         }
3985                 }
3986         }
3987 
3988 done:
3989         release_process(p.pr);
3990         free(rblk);
3991         (void) zonecfg_endrctlent(handle);
3992 
3993         return (res);
3994 }
3995 
3996 static const xmlChar *
3997 nm_to_dtd(char *nm)
3998 {
3999         if (strcmp(nm, "device") == 0)
4000                 return (DTD_ELEM_DEVICE);
4001         if (strcmp(nm, "fs") == 0)
4002                 return (DTD_ELEM_FS);
4003         if (strcmp(nm, "net") == 0)
4004                 return (DTD_ELEM_NET);
4005         if (strcmp(nm, "attr") == 0)
4006                 return (DTD_ELEM_ATTR);
4007         if (strcmp(nm, "rctl") == 0)
4008                 return (DTD_ELEM_RCTL);
4009         if (strcmp(nm, "dataset") == 0)
4010                 return (DTD_ELEM_DATASET);
4011         if (strcmp(nm, "admin") == 0)
4012                 return (DTD_ELEM_ADMIN);
4013 
4014         return (NULL);
4015 }
4016 
4017 int
4018 zonecfg_num_resources(zone_dochandle_t handle, char *rsrc)
4019 {
4020         int num = 0;
4021         const xmlChar *dtd;
4022         xmlNodePtr cur;
4023 
4024         if ((dtd = nm_to_dtd(rsrc)) == NULL)
4025                 return (num);
4026 
4027         if (zonecfg_setent(handle) != Z_OK)
4028                 return (num);
4029 
4030         for (cur = handle->zone_dh_cur; cur != NULL; cur = cur->next)
4031                 if (xmlStrcmp(cur->name, dtd) == 0)
4032                         num++;
4033 
4034         (void) zonecfg_endent(handle);
4035 
4036         return (num);
4037 }
4038 
4039 int
4040 zonecfg_del_all_resources(zone_dochandle_t handle, char *rsrc)
4041 {
4042         int err;
4043         const xmlChar *dtd;
4044         xmlNodePtr cur;
4045 
4046         if ((dtd = nm_to_dtd(rsrc)) == NULL)
4047                 return (Z_NO_RESOURCE_TYPE);
4048 
4049         if ((err = zonecfg_setent(handle)) != Z_OK)
4050                 return (err);
4051 
4052         cur = handle->zone_dh_cur;
4053         while (cur != NULL) {
4054                 xmlNodePtr tmp;
4055 
4056                 if (xmlStrcmp(cur->name, dtd)) {
4057                         cur = cur->next;
4058                         continue;
4059                 }
4060 
4061                 tmp = cur->next;
4062                 xmlUnlinkNode(cur);
4063                 xmlFreeNode(cur);
4064                 cur = tmp;
4065         }
4066 
4067         (void) zonecfg_endent(handle);
4068         return (Z_OK);
4069 }
4070 
4071 static boolean_t
4072 valid_uint(char *s, uint64_t *n)
4073 {
4074         char *endp;
4075 
4076         /* strtoull accepts '-'?! so we want to flag that as an error */
4077         if (strchr(s, '-') != NULL)
4078                 return (B_FALSE);
4079 
4080         errno = 0;
4081         *n = strtoull(s, &endp, 10);
4082 
4083         if (errno != 0 || *endp != '\0')
4084                 return (B_FALSE);
4085         return (B_TRUE);
4086 }
4087 
4088 /*
4089  * Convert a string representing a number (possibly a fraction) into an integer.
4090  * The string can have a modifier (K, M, G or T).   The modifiers are treated
4091  * as powers of two (not 10).
4092  */
4093 int
4094 zonecfg_str_to_bytes(char *str, uint64_t *bytes)
4095 {
4096         long double val;
4097         char *unitp;
4098         uint64_t scale;
4099 
4100         if ((val = strtold(str, &unitp)) < 0)
4101                 return (-1);
4102 
4103         /* remove any leading white space from units string */
4104         while (isspace(*unitp) != 0)
4105                 ++unitp;
4106 
4107         /* if no units explicitly set, error */
4108         if (unitp == NULL || *unitp == '\0') {
4109                 scale = 1;
4110         } else {
4111                 int i;
4112                 char *units[] = {"K", "M", "G", "T", NULL};
4113 
4114                 scale = 1024;
4115 
4116                 /* update scale based on units */
4117                 for (i = 0; units[i] != NULL; i++) {
4118                         if (strcasecmp(unitp, units[i]) == 0)
4119                                 break;
4120                         scale <<= 10;
4121                 }
4122 
4123                 if (units[i] == NULL)
4124                         return (-1);
4125         }
4126 
4127         *bytes = (uint64_t)(val * scale);
4128         return (0);
4129 }
4130 
4131 boolean_t
4132 zonecfg_valid_ncpus(char *lowstr, char *highstr)
4133 {
4134         uint64_t low, high;
4135 
4136         if (!valid_uint(lowstr, &low) || !valid_uint(highstr, &high) ||
4137             low < 1 || low > high)
4138                 return (B_FALSE);
4139 
4140         return (B_TRUE);
4141 }
4142 
4143 boolean_t
4144 zonecfg_valid_importance(char *impstr)
4145 {
4146         uint64_t num;
4147 
4148         if (!valid_uint(impstr, &num))
4149                 return (B_FALSE);
4150 
4151         return (B_TRUE);
4152 }
4153 
4154 boolean_t
4155 zonecfg_valid_alias_limit(char *name, char *limitstr, uint64_t *limit)
4156 {
4157         int i;
4158 
4159         for (i = 0; aliases[i].shortname != NULL; i++)
4160                 if (strcmp(name, aliases[i].shortname) == 0)
4161                         break;
4162 
4163         if (aliases[i].shortname == NULL)
4164                 return (B_FALSE);
4165 
4166         if (!valid_uint(limitstr, limit) || *limit < aliases[i].low_limit)
4167                 return (B_FALSE);
4168 
4169         return (B_TRUE);
4170 }
4171 
4172 boolean_t
4173 zonecfg_valid_memlimit(char *memstr, uint64_t *mem_val)
4174 {
4175         if (zonecfg_str_to_bytes(memstr, mem_val) != 0)
4176                 return (B_FALSE);
4177 
4178         return (B_TRUE);
4179 }
4180 
4181 static int
4182 zerr_pool(char *pool_err, int err_size, int res)
4183 {
4184         (void) strlcpy(pool_err, pool_strerror(pool_error()), err_size);
4185         return (res);
4186 }
4187 
4188 static int
4189 create_tmp_pset(char *pool_err, int err_size, pool_conf_t *pconf, pool_t *pool,
4190     char *name, int min, int max)
4191 {
4192         pool_resource_t *res;
4193         pool_elem_t *elem;
4194         pool_value_t *val;
4195 
4196         if ((res = pool_resource_create(pconf, "pset", name)) == NULL)
4197                 return (zerr_pool(pool_err, err_size, Z_POOL));
4198 
4199         if (pool_associate(pconf, pool, res) != PO_SUCCESS)
4200                 return (zerr_pool(pool_err, err_size, Z_POOL));
4201 
4202         if ((elem = pool_resource_to_elem(pconf, res)) == NULL)
4203                 return (zerr_pool(pool_err, err_size, Z_POOL));
4204 
4205         if ((val = pool_value_alloc()) == NULL)
4206                 return (zerr_pool(pool_err, err_size, Z_POOL));
4207 
4208         /* set the maximum number of cpus for the pset */
4209         pool_value_set_uint64(val, (uint64_t)max);
4210 
4211         if (pool_put_property(pconf, elem, "pset.max", val) != PO_SUCCESS) {
4212                 pool_value_free(val);
4213                 return (zerr_pool(pool_err, err_size, Z_POOL));
4214         }
4215 
4216         /* set the minimum number of cpus for the pset */
4217         pool_value_set_uint64(val, (uint64_t)min);
4218 
4219         if (pool_put_property(pconf, elem, "pset.min", val) != PO_SUCCESS) {
4220                 pool_value_free(val);
4221                 return (zerr_pool(pool_err, err_size, Z_POOL));
4222         }
4223 
4224         pool_value_free(val);
4225 
4226         return (Z_OK);
4227 }
4228 
4229 static int
4230 create_tmp_pool(char *pool_err, int err_size, pool_conf_t *pconf, char *name,
4231     struct zone_psettab *pset_tab)
4232 {
4233         pool_t *pool;
4234         int res = Z_OK;
4235 
4236         /* create a temporary pool configuration */
4237         if (pool_conf_open(pconf, NULL, PO_TEMP) != PO_SUCCESS) {
4238                 res = zerr_pool(pool_err, err_size, Z_POOL);
4239                 return (res);
4240         }
4241 
4242         if ((pool = pool_create(pconf, name)) == NULL) {
4243                 res = zerr_pool(pool_err, err_size, Z_POOL_CREATE);
4244                 goto done;
4245         }
4246 
4247         /* set pool importance */
4248         if (pset_tab->zone_importance[0] != '\0') {
4249                 pool_elem_t *elem;
4250                 pool_value_t *val;
4251 
4252                 if ((elem = pool_to_elem(pconf, pool)) == NULL) {
4253                         res = zerr_pool(pool_err, err_size, Z_POOL);
4254                         goto done;
4255                 }
4256 
4257                 if ((val = pool_value_alloc()) == NULL) {
4258                         res = zerr_pool(pool_err, err_size, Z_POOL);
4259                         goto done;
4260                 }
4261 
4262                 pool_value_set_int64(val,
4263                     (int64_t)atoi(pset_tab->zone_importance));
4264 
4265                 if (pool_put_property(pconf, elem, "pool.importance", val)
4266                     != PO_SUCCESS) {
4267                         res = zerr_pool(pool_err, err_size, Z_POOL);
4268                         pool_value_free(val);
4269                         goto done;
4270                 }
4271 
4272                 pool_value_free(val);
4273         }
4274 
4275         if ((res = create_tmp_pset(pool_err, err_size, pconf, pool, name,
4276             atoi(pset_tab->zone_ncpu_min),
4277             atoi(pset_tab->zone_ncpu_max))) != Z_OK)
4278                 goto done;
4279 
4280         /* validation */
4281         if (pool_conf_status(pconf) == POF_INVALID) {
4282                 res = zerr_pool(pool_err, err_size, Z_POOL);
4283                 goto done;
4284         }
4285 
4286         /*
4287          * This validation is the one we expect to fail if the user specified
4288          * an invalid configuration (too many cpus) for this system.
4289          */
4290         if (pool_conf_validate(pconf, POV_RUNTIME) != PO_SUCCESS) {
4291                 res = zerr_pool(pool_err, err_size, Z_POOL_CREATE);
4292                 goto done;
4293         }
4294 
4295         /*
4296          * Commit the dynamic configuration but not the pool configuration
4297          * file.
4298          */
4299         if (pool_conf_commit(pconf, 1) != PO_SUCCESS)
4300                 res = zerr_pool(pool_err, err_size, Z_POOL);
4301 
4302 done:
4303         (void) pool_conf_close(pconf);
4304         return (res);
4305 }
4306 
4307 static int
4308 get_running_tmp_pset(pool_conf_t *pconf, pool_t *pool, pool_resource_t *pset,
4309     struct zone_psettab *pset_tab)
4310 {
4311         int nfound = 0;
4312         pool_elem_t *pe;
4313         pool_value_t *pv = pool_value_alloc();
4314         uint64_t val_uint;
4315 
4316         if (pool != NULL) {
4317                 pe = pool_to_elem(pconf, pool);
4318                 if (pool_get_property(pconf, pe, "pool.importance", pv)
4319                     != POC_INVAL) {
4320                         int64_t val_int;
4321 
4322                         (void) pool_value_get_int64(pv, &val_int);
4323                         (void) snprintf(pset_tab->zone_importance,
4324                             sizeof (pset_tab->zone_importance), "%d", val_int);
4325                         nfound++;
4326                 }
4327         }
4328 
4329         if (pset != NULL) {
4330                 pe = pool_resource_to_elem(pconf, pset);
4331                 if (pool_get_property(pconf, pe, "pset.min", pv) != POC_INVAL) {
4332                         (void) pool_value_get_uint64(pv, &val_uint);
4333                         (void) snprintf(pset_tab->zone_ncpu_min,
4334                             sizeof (pset_tab->zone_ncpu_min), "%u", val_uint);
4335                         nfound++;
4336                 }
4337 
4338                 if (pool_get_property(pconf, pe, "pset.max", pv) != POC_INVAL) {
4339                         (void) pool_value_get_uint64(pv, &val_uint);
4340                         (void) snprintf(pset_tab->zone_ncpu_max,
4341                             sizeof (pset_tab->zone_ncpu_max), "%u", val_uint);
4342                         nfound++;
4343                 }
4344         }
4345 
4346         pool_value_free(pv);
4347 
4348         if (nfound == 3)
4349                 return (PO_SUCCESS);
4350 
4351         return (PO_FAIL);
4352 }
4353 
4354 /*
4355  * Determine if a tmp pool is configured and if so, if the configuration is
4356  * still valid or if it has been changed since the tmp pool was created.
4357  * If the tmp pool configuration is no longer valid, delete the tmp pool.
4358  *
4359  * Set *valid=B_TRUE if there is an existing, valid tmp pool configuration.
4360  */
4361 static int
4362 verify_del_tmp_pool(pool_conf_t *pconf, char *tmp_name, char *pool_err,
4363     int err_size, struct zone_psettab *pset_tab, boolean_t *exists)
4364 {
4365         int res = Z_OK;
4366         pool_t *pool;
4367         pool_resource_t *pset;
4368         struct zone_psettab pset_current;
4369 
4370         *exists = B_FALSE;
4371 
4372         if (pool_conf_open(pconf, pool_dynamic_location(), PO_RDWR)
4373             != PO_SUCCESS) {
4374                 res = zerr_pool(pool_err, err_size, Z_POOL);
4375                 return (res);
4376         }
4377 
4378         pool = pool_get_pool(pconf, tmp_name);
4379         pset = pool_get_resource(pconf, "pset", tmp_name);
4380 
4381         if (pool == NULL && pset == NULL) {
4382                 /* no tmp pool configured */
4383                 goto done;
4384         }
4385 
4386         /*
4387          * If an existing tmp pool for this zone is configured with the proper
4388          * settings, then the tmp pool is valid.
4389          */
4390         if (get_running_tmp_pset(pconf, pool, pset, &pset_current)
4391             == PO_SUCCESS &&
4392             strcmp(pset_tab->zone_ncpu_min,
4393             pset_current.zone_ncpu_min) == 0 &&
4394             strcmp(pset_tab->zone_ncpu_max,
4395             pset_current.zone_ncpu_max) == 0 &&
4396             strcmp(pset_tab->zone_importance,
4397             pset_current.zone_importance) == 0) {
4398                 *exists = B_TRUE;
4399 
4400         } else {
4401                 /*
4402                  * An out-of-date tmp pool configuration exists.  Delete it
4403                  * so that we can create the correct tmp pool config.
4404                  */
4405                 if (pset != NULL &&
4406                     pool_resource_destroy(pconf, pset) != PO_SUCCESS) {
4407                         res = zerr_pool(pool_err, err_size, Z_POOL);
4408                         goto done;
4409                 }
4410 
4411                 if (pool != NULL &&
4412                     pool_destroy(pconf, pool) != PO_SUCCESS) {
4413                         res = zerr_pool(pool_err, err_size, Z_POOL);
4414                         goto done;
4415                 }
4416 
4417                 /* commit dynamic config */
4418                 if (pool_conf_commit(pconf, 0) != PO_SUCCESS)
4419                         res = zerr_pool(pool_err, err_size, Z_POOL);
4420         }
4421 
4422 done:
4423         (void) pool_conf_close(pconf);
4424 
4425         return (res);
4426 }
4427 
4428 /*
4429  * Destroy any existing tmp pool.
4430  */
4431 int
4432 zonecfg_destroy_tmp_pool(char *zone_name, char *pool_err, int err_size)
4433 {
4434         int status;
4435         int res = Z_OK;
4436         pool_conf_t *pconf;
4437         pool_t *pool;
4438         pool_resource_t *pset;
4439         char tmp_name[MAX_TMP_POOL_NAME];
4440 
4441         /* if pools not enabled then nothing to do */
4442         if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
4443                 return (Z_OK);
4444 
4445         if ((pconf = pool_conf_alloc()) == NULL)
4446                 return (zerr_pool(pool_err, err_size, Z_POOL));
4447 
4448         (void) snprintf(tmp_name, sizeof (tmp_name), TMP_POOL_NAME, zone_name);
4449 
4450         if (pool_conf_open(pconf, pool_dynamic_location(), PO_RDWR)
4451             != PO_SUCCESS) {
4452                 res = zerr_pool(pool_err, err_size, Z_POOL);
4453                 pool_conf_free(pconf);
4454                 return (res);
4455         }
4456 
4457         pool = pool_get_pool(pconf, tmp_name);
4458         pset = pool_get_resource(pconf, "pset", tmp_name);
4459 
4460         if (pool == NULL && pset == NULL) {
4461                 /* nothing to destroy, we're done */
4462                 goto done;
4463         }
4464 
4465         if (pset != NULL && pool_resource_destroy(pconf, pset) != PO_SUCCESS) {
4466                 res = zerr_pool(pool_err, err_size, Z_POOL);
4467                 goto done;
4468         }
4469 
4470         if (pool != NULL && pool_destroy(pconf, pool) != PO_SUCCESS) {
4471                 res = zerr_pool(pool_err, err_size, Z_POOL);
4472                 goto done;
4473         }
4474 
4475         /* commit dynamic config */
4476         if (pool_conf_commit(pconf, 0) != PO_SUCCESS)
4477                 res = zerr_pool(pool_err, err_size, Z_POOL);
4478 
4479 done:
4480         (void) pool_conf_close(pconf);
4481         pool_conf_free(pconf);
4482 
4483         return (res);
4484 }
4485 
4486 /*
4487  * Attempt to bind to a tmp pool for this zone.  If there is no tmp pool
4488  * configured, we just return Z_OK.
4489  *
4490  * We either attempt to create the tmp pool for this zone or rebind to an
4491  * existing tmp pool for this zone.
4492  *
4493  * Rebinding is used when a zone with a tmp pool reboots so that we don't have
4494  * to recreate the tmp pool.  To do this we need to be sure we work correctly
4495  * for the following cases:
4496  *
4497  *      - there is an existing, properly configured tmp pool.
4498  *      - zonecfg added tmp pool after zone was booted, must now create.
4499  *      - zonecfg updated tmp pool config after zone was booted, in this case
4500  *        we destroy the old tmp pool and create a new one.
4501  */
4502 int
4503 zonecfg_bind_tmp_pool(zone_dochandle_t handle, zoneid_t zoneid, char *pool_err,
4504     int err_size)
4505 {
4506         struct zone_psettab pset_tab;
4507         int err;
4508         int status;
4509         pool_conf_t *pconf;
4510         boolean_t exists;
4511         char zone_name[ZONENAME_MAX];
4512         char tmp_name[MAX_TMP_POOL_NAME];
4513 
4514         (void) getzonenamebyid(zoneid, zone_name, sizeof (zone_name));
4515 
4516         err = zonecfg_lookup_pset(handle, &pset_tab);
4517 
4518         /* if no temporary pool configured, we're done */
4519         if (err == Z_NO_ENTRY)
4520                 return (Z_OK);
4521 
4522         /*
4523          * importance might not have a value but we need to validate it here,
4524          * so set the default.
4525          */
4526         if (pset_tab.zone_importance[0] == '\0')
4527                 (void) strlcpy(pset_tab.zone_importance, "1",
4528                     sizeof (pset_tab.zone_importance));
4529 
4530         /* if pools not enabled, enable them now */
4531         if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) {
4532                 if (pool_set_status(POOL_ENABLED) != PO_SUCCESS)
4533                         return (Z_POOL_ENABLE);
4534         }
4535 
4536         if ((pconf = pool_conf_alloc()) == NULL)
4537                 return (zerr_pool(pool_err, err_size, Z_POOL));
4538 
4539         (void) snprintf(tmp_name, sizeof (tmp_name), TMP_POOL_NAME, zone_name);
4540 
4541         /*
4542          * Check if a valid tmp pool/pset already exists.  If so, we just
4543          * reuse it.
4544          */
4545         if ((err = verify_del_tmp_pool(pconf, tmp_name, pool_err, err_size,
4546             &pset_tab, &exists)) != Z_OK) {
4547                 pool_conf_free(pconf);
4548                 return (err);
4549         }
4550 
4551         if (!exists)
4552                 err = create_tmp_pool(pool_err, err_size, pconf, tmp_name,
4553                     &pset_tab);
4554 
4555         pool_conf_free(pconf);
4556 
4557         if (err != Z_OK)
4558                 return (err);
4559 
4560         /* Bind the zone to the pool. */
4561         if (pool_set_binding(tmp_name, P_ZONEID, zoneid) != PO_SUCCESS)
4562                 return (zerr_pool(pool_err, err_size, Z_POOL_BIND));
4563 
4564         return (Z_OK);
4565 }
4566 
4567 /*
4568  * Attempt to bind to a permanent pool for this zone.  If there is no
4569  * permanent pool configured, we just return Z_OK.
4570  */
4571 int
4572 zonecfg_bind_pool(zone_dochandle_t handle, zoneid_t zoneid, char *pool_err,
4573     int err_size)
4574 {
4575         pool_conf_t *poolconf;
4576         pool_t *pool;
4577         char poolname[MAXPATHLEN];
4578         int status;
4579         int error;
4580 
4581         /*
4582          * Find the pool mentioned in the zone configuration, and bind to it.
4583          */
4584         error = zonecfg_get_pool(handle, poolname, sizeof (poolname));
4585         if (error == Z_NO_ENTRY || (error == Z_OK && strlen(poolname) == 0)) {
4586                 /*
4587                  * The property is not set on the zone, so the pool
4588                  * should be bound to the default pool.  But that's
4589                  * already done by the kernel, so we can just return.
4590                  */
4591                 return (Z_OK);
4592         }
4593         if (error != Z_OK) {
4594                 /*
4595                  * Not an error, even though it shouldn't be happening.
4596                  */
4597                 return (Z_OK);
4598         }
4599         /*
4600          * Don't do anything if pools aren't enabled.
4601          */
4602         if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
4603                 return (Z_POOLS_NOT_ACTIVE);
4604 
4605         /*
4606          * Try to provide a sane error message if the requested pool doesn't
4607          * exist.
4608          */
4609         if ((poolconf = pool_conf_alloc()) == NULL)
4610                 return (zerr_pool(pool_err, err_size, Z_POOL));
4611 
4612         if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) !=
4613             PO_SUCCESS) {
4614                 pool_conf_free(poolconf);
4615                 return (zerr_pool(pool_err, err_size, Z_POOL));
4616         }
4617         pool = pool_get_pool(poolconf, poolname);
4618         (void) pool_conf_close(poolconf);
4619         pool_conf_free(poolconf);
4620         if (pool == NULL)
4621                 return (Z_NO_POOL);
4622 
4623         /*
4624          * Bind the zone to the pool.
4625          */
4626         if (pool_set_binding(poolname, P_ZONEID, zoneid) != PO_SUCCESS) {
4627                 /* if bind fails, return poolname for the error msg */
4628                 (void) strlcpy(pool_err, poolname, err_size);
4629                 return (Z_POOL_BIND);
4630         }
4631 
4632         return (Z_OK);
4633 }
4634 
4635 int
4636 zonecfg_get_poolname(zone_dochandle_t handle, char *zone, char *pool,
4637     size_t poolsize)
4638 {
4639         int err;
4640         struct zone_psettab pset_tab;
4641 
4642         err = zonecfg_lookup_pset(handle, &pset_tab);
4643         if ((err != Z_NO_ENTRY) && (err != Z_OK))
4644                 return (err);
4645 
4646         /* pset was found so a temporary pool was created */
4647         if (err == Z_OK) {
4648                 (void) snprintf(pool, poolsize, TMP_POOL_NAME, zone);
4649                 return (Z_OK);
4650         }
4651 
4652         /* lookup the poolname in zonecfg */
4653         return (zonecfg_get_pool(handle, pool, poolsize));
4654 }
4655 
4656 static boolean_t
4657 svc_enabled(char *svc_name)
4658 {
4659         scf_simple_prop_t       *prop;
4660         boolean_t               found = B_FALSE;
4661 
4662         prop = scf_simple_prop_get(NULL, svc_name, SCF_PG_GENERAL,
4663             SCF_PROPERTY_ENABLED);
4664 
4665         if (scf_simple_prop_numvalues(prop) == 1 &&
4666             *scf_simple_prop_next_boolean(prop) != 0)
4667                 found = B_TRUE;
4668 
4669         scf_simple_prop_free(prop);
4670 
4671         return (found);
4672 }
4673 
4674 /*
4675  * If the zone has capped-memory, make sure the rcap service is enabled.
4676  */
4677 int
4678 zonecfg_enable_rcapd(char *err, int size)
4679 {
4680         if (!svc_enabled(RCAP_SERVICE) &&
4681             smf_enable_instance(RCAP_SERVICE, 0) == -1) {
4682                 (void) strlcpy(err, scf_strerror(scf_error()), size);
4683                 return (Z_SYSTEM);
4684         }
4685 
4686         return (Z_OK);
4687 }
4688 
4689 /*
4690  * Return true if pset has cpu range specified and poold is not enabled.
4691  */
4692 boolean_t
4693 zonecfg_warn_poold(zone_dochandle_t handle)
4694 {
4695         struct zone_psettab pset_tab;
4696         int min, max;
4697         int err;
4698 
4699         err = zonecfg_lookup_pset(handle, &pset_tab);
4700 
4701         /* if no temporary pool configured, we're done */
4702         if (err == Z_NO_ENTRY)
4703                 return (B_FALSE);
4704 
4705         min = atoi(pset_tab.zone_ncpu_min);
4706         max = atoi(pset_tab.zone_ncpu_max);
4707 
4708         /* range not specified, no need for poold */
4709         if (min == max)
4710                 return (B_FALSE);
4711 
4712         /* we have a range, check if poold service is enabled */
4713         if (svc_enabled(POOLD_SERVICE))
4714                 return (B_FALSE);
4715 
4716         return (B_TRUE);
4717 }
4718 
4719 /*
4720  * Retrieve the specified pool's thread scheduling class.  'poolname' must
4721  * refer to the name of a configured resource pool.  The thread scheduling
4722  * class specified by the pool will be stored in the buffer to which 'class'
4723  * points.  'clsize' is the byte size of the buffer to which 'class' points.
4724  *
4725  * This function returns Z_OK if it successfully stored the specified pool's
4726  * thread scheduling class into the buffer to which 'class' points.  It returns
4727  * Z_NO_POOL if resource pools are not enabled, the function is unable to
4728  * access the system's resource pools configuration, or the specified pool
4729  * does not exist.  The function returns Z_TOO_BIG if the buffer to which
4730  * 'class' points is not large enough to contain the thread scheduling class'
4731  * name.  The function returns Z_NO_ENTRY if the pool does not specify a thread
4732  * scheduling class.
4733  */
4734 static int
4735 get_pool_sched_class(char *poolname, char *class, int clsize)
4736 {
4737         int status;
4738         pool_conf_t *poolconf;
4739         pool_t *pool;
4740         pool_elem_t *pe;
4741         pool_value_t *pv = pool_value_alloc();
4742         const char *sched_str;
4743 
4744         if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
4745                 return (Z_NO_POOL);
4746 
4747         if ((poolconf = pool_conf_alloc()) == NULL)
4748                 return (Z_NO_POOL);
4749 
4750         if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) !=
4751             PO_SUCCESS) {
4752                 pool_conf_free(poolconf);
4753                 return (Z_NO_POOL);
4754         }
4755 
4756         if ((pool = pool_get_pool(poolconf, poolname)) == NULL) {
4757                 (void) pool_conf_close(poolconf);
4758                 pool_conf_free(poolconf);
4759                 return (Z_NO_POOL);
4760         }
4761 
4762         pe = pool_to_elem(poolconf, pool);
4763         if (pool_get_property(poolconf, pe, "pool.scheduler", pv) !=
4764             POC_STRING) {
4765                 (void) pool_conf_close(poolconf);
4766                 pool_conf_free(poolconf);
4767                 return (Z_NO_ENTRY);
4768         }
4769         (void) pool_value_get_string(pv, &sched_str);
4770         (void) pool_conf_close(poolconf);
4771         pool_conf_free(poolconf);
4772         if (strlcpy(class, sched_str, clsize) >= clsize)
4773                 return (Z_TOO_BIG);
4774         return (Z_OK);
4775 }
4776 
4777 /*
4778  * Get the default scheduling class for the zone.  This will either be the
4779  * class set on the zone's pool or the system default scheduling class.
4780  */
4781 int
4782 zonecfg_get_dflt_sched_class(zone_dochandle_t handle, char *class, int clsize)
4783 {
4784         char poolname[MAXPATHLEN];
4785 
4786         if (zonecfg_get_pool(handle, poolname, sizeof (poolname)) == Z_OK) {
4787                 /* check if the zone's pool specified a sched class */
4788                 if (get_pool_sched_class(poolname, class, clsize) == Z_OK)
4789                         return (Z_OK);
4790         }
4791 
4792         if (priocntl(0, 0, PC_GETDFLCL, class, (uint64_t)clsize) == -1)
4793                 return (Z_TOO_BIG);
4794 
4795         return (Z_OK);
4796 }
4797 
4798 int
4799 zonecfg_setfsent(zone_dochandle_t handle)
4800 {
4801         return (zonecfg_setent(handle));
4802 }
4803 
4804 int
4805 zonecfg_getfsent(zone_dochandle_t handle, struct zone_fstab *tabptr)
4806 {
4807         xmlNodePtr cur, options;
4808         char options_str[MAX_MNTOPT_STR];
4809         int err;
4810 
4811         if (handle == NULL)
4812                 return (Z_INVAL);
4813 
4814         if ((cur = handle->zone_dh_cur) == NULL)
4815                 return (Z_NO_ENTRY);
4816 
4817         for (; cur != NULL; cur = cur->next)
4818                 if (!xmlStrcmp(cur->name, DTD_ELEM_FS))
4819                         break;
4820         if (cur == NULL) {
4821                 handle->zone_dh_cur = handle->zone_dh_top;
4822                 return (Z_NO_ENTRY);
4823         }
4824 
4825         if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
4826             sizeof (tabptr->zone_fs_special))) != Z_OK) {
4827                 handle->zone_dh_cur = handle->zone_dh_top;
4828                 return (err);
4829         }
4830 
4831         if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
4832             sizeof (tabptr->zone_fs_raw))) != Z_OK) {
4833                 handle->zone_dh_cur = handle->zone_dh_top;
4834                 return (err);
4835         }
4836 
4837         if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
4838             sizeof (tabptr->zone_fs_dir))) != Z_OK) {
4839                 handle->zone_dh_cur = handle->zone_dh_top;
4840                 return (err);
4841         }
4842 
4843         if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
4844             sizeof (tabptr->zone_fs_type))) != Z_OK) {
4845                 handle->zone_dh_cur = handle->zone_dh_top;
4846                 return (err);
4847         }
4848 
4849         /* OK for options to be NULL */
4850         tabptr->zone_fs_options = NULL;
4851         for (options = cur->xmlChildrenNode; options != NULL;
4852             options = options->next) {
4853                 if (fetchprop(options, DTD_ATTR_NAME, options_str,
4854                     sizeof (options_str)) != Z_OK)
4855                         break;
4856                 if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
4857                         break;
4858         }
4859 
4860         handle->zone_dh_cur = cur->next;
4861         return (Z_OK);
4862 }
4863 
4864 int
4865 zonecfg_endfsent(zone_dochandle_t handle)
4866 {
4867         return (zonecfg_endent(handle));
4868 }
4869 
4870 int
4871 zonecfg_setnwifent(zone_dochandle_t handle)
4872 {
4873         return (zonecfg_setent(handle));
4874 }
4875 
4876 int
4877 zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
4878 {
4879         xmlNodePtr cur;
4880         int err;
4881 
4882         if (handle == NULL)
4883                 return (Z_INVAL);
4884 
4885         if ((cur = handle->zone_dh_cur) == NULL)
4886                 return (Z_NO_ENTRY);
4887 
4888         for (; cur != NULL; cur = cur->next)
4889                 if (!xmlStrcmp(cur->name, DTD_ELEM_NET))
4890                         break;
4891         if (cur == NULL) {
4892                 handle->zone_dh_cur = handle->zone_dh_top;
4893                 return (Z_NO_ENTRY);
4894         }
4895 
4896         if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
4897             sizeof (tabptr->zone_nwif_address))) != Z_OK) {
4898                 handle->zone_dh_cur = handle->zone_dh_top;
4899                 return (err);
4900         }
4901 
4902         if ((err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
4903             tabptr->zone_nwif_allowed_address,
4904             sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK) {
4905                 handle->zone_dh_cur = handle->zone_dh_top;
4906                 return (err);
4907         }
4908 
4909         if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
4910             sizeof (tabptr->zone_nwif_physical))) != Z_OK) {
4911                 handle->zone_dh_cur = handle->zone_dh_top;
4912                 return (err);
4913         }
4914 
4915         if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
4916             tabptr->zone_nwif_defrouter,
4917             sizeof (tabptr->zone_nwif_defrouter))) != Z_OK) {
4918                 handle->zone_dh_cur = handle->zone_dh_top;
4919                 return (err);
4920         }
4921 
4922         handle->zone_dh_cur = cur->next;
4923         return (Z_OK);
4924 }
4925 
4926 int
4927 zonecfg_endnwifent(zone_dochandle_t handle)
4928 {
4929         return (zonecfg_endent(handle));
4930 }
4931 
4932 int
4933 zonecfg_setdevent(zone_dochandle_t handle)
4934 {
4935         return (zonecfg_setent(handle));
4936 }
4937 
4938 int
4939 zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr)
4940 {
4941         xmlNodePtr cur;
4942         int err;
4943 
4944         if (handle == NULL)
4945                 return (Z_INVAL);
4946 
4947         if ((cur = handle->zone_dh_cur) == NULL)
4948                 return (Z_NO_ENTRY);
4949 
4950         for (; cur != NULL; cur = cur->next)
4951                 if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
4952                         break;
4953         if (cur == NULL) {
4954                 handle->zone_dh_cur = handle->zone_dh_top;
4955                 return (Z_NO_ENTRY);
4956         }
4957 
4958         if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
4959             sizeof (tabptr->zone_dev_match))) != Z_OK) {
4960                 handle->zone_dh_cur = handle->zone_dh_top;
4961                 return (err);
4962         }
4963 
4964         handle->zone_dh_cur = cur->next;
4965         return (Z_OK);
4966 }
4967 
4968 int
4969 zonecfg_enddevent(zone_dochandle_t handle)
4970 {
4971         return (zonecfg_endent(handle));
4972 }
4973 
4974 int
4975 zonecfg_setrctlent(zone_dochandle_t handle)
4976 {
4977         return (zonecfg_setent(handle));
4978 }
4979 
4980 int
4981 zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr)
4982 {
4983         xmlNodePtr cur, val;
4984         struct zone_rctlvaltab *valptr;
4985         int err;
4986 
4987         if (handle == NULL)
4988                 return (Z_INVAL);
4989 
4990         if ((cur = handle->zone_dh_cur) == NULL)
4991                 return (Z_NO_ENTRY);
4992 
4993         for (; cur != NULL; cur = cur->next)
4994                 if (!xmlStrcmp(cur->name, DTD_ELEM_RCTL))
4995                         break;
4996         if (cur == NULL) {
4997                 handle->zone_dh_cur = handle->zone_dh_top;
4998                 return (Z_NO_ENTRY);
4999         }
5000 
5001         if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_rctl_name,
5002             sizeof (tabptr->zone_rctl_name))) != Z_OK) {
5003                 handle->zone_dh_cur = handle->zone_dh_top;
5004                 return (err);
5005         }
5006 
5007         tabptr->zone_rctl_valptr = NULL;
5008         for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
5009                 valptr = (struct zone_rctlvaltab *)malloc(
5010                     sizeof (struct zone_rctlvaltab));
5011                 if (valptr == NULL)
5012                         return (Z_NOMEM);
5013                 if (fetchprop(val, DTD_ATTR_PRIV, valptr->zone_rctlval_priv,
5014                     sizeof (valptr->zone_rctlval_priv)) != Z_OK)
5015                         break;
5016                 if (fetchprop(val, DTD_ATTR_LIMIT, valptr->zone_rctlval_limit,
5017                     sizeof (valptr->zone_rctlval_limit)) != Z_OK)
5018                         break;
5019                 if (fetchprop(val, DTD_ATTR_ACTION, valptr->zone_rctlval_action,
5020                     sizeof (valptr->zone_rctlval_action)) != Z_OK)
5021                         break;
5022                 if (zonecfg_add_rctl_value(tabptr, valptr) != Z_OK)
5023                         break;
5024         }
5025 
5026         handle->zone_dh_cur = cur->next;
5027         return (Z_OK);
5028 }
5029 
5030 int
5031 zonecfg_endrctlent(zone_dochandle_t handle)
5032 {
5033         return (zonecfg_endent(handle));
5034 }
5035 
5036 int
5037 zonecfg_setattrent(zone_dochandle_t handle)
5038 {
5039         return (zonecfg_setent(handle));
5040 }
5041 
5042 int
5043 zonecfg_getattrent(zone_dochandle_t handle, struct zone_attrtab *tabptr)
5044 {
5045         xmlNodePtr cur;
5046         int err;
5047 
5048         if (handle == NULL)
5049                 return (Z_INVAL);
5050 
5051         if ((cur = handle->zone_dh_cur) == NULL)
5052                 return (Z_NO_ENTRY);
5053 
5054         for (; cur != NULL; cur = cur->next)
5055                 if (!xmlStrcmp(cur->name, DTD_ELEM_ATTR))
5056                         break;
5057         if (cur == NULL) {
5058                 handle->zone_dh_cur = handle->zone_dh_top;
5059                 return (Z_NO_ENTRY);
5060         }
5061 
5062         if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
5063             sizeof (tabptr->zone_attr_name))) != Z_OK) {
5064                 handle->zone_dh_cur = handle->zone_dh_top;
5065                 return (err);
5066         }
5067 
5068         if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
5069             sizeof (tabptr->zone_attr_type))) != Z_OK) {
5070                 handle->zone_dh_cur = handle->zone_dh_top;
5071                 return (err);
5072         }
5073 
5074         if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
5075             sizeof (tabptr->zone_attr_value))) != Z_OK) {
5076                 handle->zone_dh_cur = handle->zone_dh_top;
5077                 return (err);
5078         }
5079 
5080         handle->zone_dh_cur = cur->next;
5081         return (Z_OK);
5082 }
5083 
5084 int
5085 zonecfg_endattrent(zone_dochandle_t handle)
5086 {
5087         return (zonecfg_endent(handle));
5088 }
5089 
5090 int
5091 zonecfg_setadminent(zone_dochandle_t handle)
5092 {
5093         return (zonecfg_setent(handle));
5094 }
5095 
5096 int
5097 zonecfg_getadminent(zone_dochandle_t handle, struct zone_admintab *tabptr)
5098 {
5099         xmlNodePtr cur;
5100         int err;
5101 
5102         if (handle == NULL)
5103                 return (Z_INVAL);
5104 
5105         if ((cur = handle->zone_dh_cur) == NULL)
5106                 return (Z_NO_ENTRY);
5107 
5108         for (; cur != NULL; cur = cur->next)
5109                 if (!xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
5110                         break;
5111         if (cur == NULL) {
5112                 handle->zone_dh_cur = handle->zone_dh_top;
5113                 return (Z_NO_ENTRY);
5114         }
5115 
5116         if ((err = fetchprop(cur, DTD_ATTR_USER, tabptr->zone_admin_user,
5117             sizeof (tabptr->zone_admin_user))) != Z_OK) {
5118                 handle->zone_dh_cur = handle->zone_dh_top;
5119                 return (err);
5120         }
5121 
5122 
5123         if ((err = fetchprop(cur, DTD_ATTR_AUTHS, tabptr->zone_admin_auths,
5124             sizeof (tabptr->zone_admin_auths))) != Z_OK) {
5125                 handle->zone_dh_cur = handle->zone_dh_top;
5126                 return (err);
5127         }
5128 
5129         handle->zone_dh_cur = cur->next;
5130         return (Z_OK);
5131 }
5132 
5133 int
5134 zonecfg_endadminent(zone_dochandle_t handle)
5135 {
5136         return (zonecfg_endent(handle));
5137 }
5138 
5139 /*
5140  * The privileges available on the system and described in privileges(5)
5141  * fall into four categories with respect to non-global zones:
5142  *
5143  *      Default set of privileges considered safe for all non-global
5144  *      zones.  These privileges are "safe" in the sense that a
5145  *      privileged process in the zone cannot affect processes in any
5146  *      other zone on the system.
5147  *
5148  *      Set of privileges not currently permitted within a non-global
5149  *      zone.  These privileges are considered by default, "unsafe,"
5150  *      and include ones which affect global resources (such as the
5151  *      system clock or physical memory) or are overly broad and cover
5152  *      more than one mechanism in the system.  In other cases, there
5153  *      has not been sufficient virtualization in the parts of the
5154  *      system the privilege covers to allow its use within a
5155  *      non-global zone.
5156  *
5157  *      Set of privileges required in order to get a zone booted and
5158  *      init(1M) started.  These cannot be removed from the zone's
5159  *      privilege set.
5160  *
5161  * All other privileges are optional and are potentially useful for
5162  * processes executing inside a non-global zone.
5163  *
5164  * When privileges are added to the system, a determination needs to be
5165  * made as to which category the privilege belongs to.  Ideally,
5166  * privileges should be fine-grained enough and the mechanisms they cover
5167  * virtualized enough so that they can be made available to non-global
5168  * zones.
5169  */
5170 
5171 /*
5172  * Define some of the tokens that priv_str_to_set(3C) recognizes.  Since
5173  * the privilege string separator can be any character, although it is
5174  * usually a comma character, define these here as well in the event that
5175  * they change or are augmented in the future.
5176  */
5177 #define BASIC_TOKEN             "basic"
5178 #define DEFAULT_TOKEN           "default"
5179 #define ZONE_TOKEN              "zone"
5180 #define TOKEN_PRIV_CHAR         ','
5181 #define TOKEN_PRIV_STR          ","
5182 
5183 typedef struct priv_node {
5184         struct priv_node        *pn_next;       /* Next privilege */
5185         char                    *pn_priv;       /* Privileges name */
5186 } priv_node_t;
5187 
5188 /* Privileges lists can differ across brands */
5189 typedef struct priv_lists {
5190         /* Privileges considered safe for all non-global zones of a brand */
5191         struct priv_node        *pl_default;
5192 
5193         /* Privileges not permitted for all non-global zones of a brand */
5194         struct priv_node        *pl_prohibited;
5195 
5196         /* Privileges required for all non-global zones of a brand */
5197         struct priv_node        *pl_required;
5198 
5199         /*
5200          * ip-type of the zone these privileges lists apply to.
5201          * It is used to pass ip-type to the callback function,
5202          * priv_lists_cb, which has no way of getting the ip-type.
5203          */
5204         const char              *pl_iptype;
5205 } priv_lists_t;
5206 
5207 static int
5208 priv_lists_cb(void *data, priv_iter_t *priv_iter)
5209 {
5210         priv_lists_t *plp = (priv_lists_t *)data;
5211         priv_node_t *pnp;
5212 
5213         /* Skip this privilege if ip-type does not match */
5214         if ((strcmp(priv_iter->pi_iptype, "all") != 0) &&
5215             (strcmp(priv_iter->pi_iptype, plp->pl_iptype) != 0))
5216                 return (0);
5217 
5218         /* Allocate a new priv list node. */
5219         if ((pnp = malloc(sizeof (*pnp))) == NULL)
5220                 return (-1);
5221         if ((pnp->pn_priv = strdup(priv_iter->pi_name)) == NULL) {
5222                 free(pnp);
5223                 return (-1);
5224         }
5225 
5226         /* Insert the new priv list node into the right list */
5227         if (strcmp(priv_iter->pi_set, "default") == 0) {
5228                 pnp->pn_next = plp->pl_default;
5229                 plp->pl_default = pnp;
5230         } else if (strcmp(priv_iter->pi_set, "prohibited") == 0) {
5231                 pnp->pn_next = plp->pl_prohibited;
5232                 plp->pl_prohibited = pnp;
5233         } else if (strcmp(priv_iter->pi_set, "required") == 0) {
5234                 pnp->pn_next = plp->pl_required;
5235                 plp->pl_required = pnp;
5236         } else {
5237                 free(pnp->pn_priv);
5238                 free(pnp);
5239                 return (-1);
5240         }
5241         return (0);
5242 }
5243 
5244 static void
5245 priv_lists_destroy(priv_lists_t *plp)
5246 {
5247         priv_node_t *pnp;
5248 
5249         assert(plp != NULL);
5250 
5251         while ((pnp = plp->pl_default) != NULL) {
5252                 plp->pl_default = pnp->pn_next;
5253                 free(pnp->pn_priv);
5254                 free(pnp);
5255         }
5256         while ((pnp = plp->pl_prohibited) != NULL) {
5257                 plp->pl_prohibited = pnp->pn_next;
5258                 free(pnp->pn_priv);
5259                 free(pnp);
5260         }
5261         while ((pnp = plp->pl_required) != NULL) {
5262                 plp->pl_required = pnp->pn_next;
5263                 free(pnp->pn_priv);
5264                 free(pnp);
5265         }
5266         free(plp);
5267 }
5268 
5269 static int
5270 priv_lists_create(zone_dochandle_t handle, char *brand, priv_lists_t **plpp,
5271     const char *curr_iptype)
5272 {
5273         priv_lists_t *plp;
5274         brand_handle_t bh;
5275         char brand_str[MAXNAMELEN];
5276 
5277         /* handle or brand must be set, but never both */
5278         assert((handle != NULL) || (brand != NULL));
5279         assert((handle == NULL) || (brand == NULL));
5280 
5281         if (handle != NULL) {
5282                 brand = brand_str;
5283                 if (zonecfg_get_brand(handle, brand, sizeof (brand_str)) != 0)
5284                         return (Z_BRAND_ERROR);
5285         }
5286 
5287         if ((bh = brand_open(brand)) == NULL)
5288                 return (Z_BRAND_ERROR);
5289 
5290         if ((plp = calloc(1, sizeof (priv_lists_t))) == NULL) {
5291                 brand_close(bh);
5292                 return (Z_NOMEM);
5293         }
5294 
5295         plp->pl_iptype = curr_iptype;
5296 
5297         /* construct the privilege lists */
5298         if (brand_config_iter_privilege(bh, priv_lists_cb, plp) != 0) {
5299                 priv_lists_destroy(plp);
5300                 brand_close(bh);
5301                 return (Z_BRAND_ERROR);
5302         }
5303 
5304         brand_close(bh);
5305         *plpp = plp;
5306         return (Z_OK);
5307 }
5308 
5309 static int
5310 get_default_privset(priv_set_t *privs, priv_lists_t *plp)
5311 {
5312         priv_node_t *pnp;
5313         priv_set_t *basic;
5314 
5315         basic = priv_str_to_set(BASIC_TOKEN, TOKEN_PRIV_STR, NULL);
5316         if (basic == NULL)
5317                 return (errno == ENOMEM ? Z_NOMEM : Z_INVAL);
5318 
5319         priv_union(basic, privs);
5320         priv_freeset(basic);
5321 
5322         for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) {
5323                 if (priv_addset(privs, pnp->pn_priv) != 0)
5324                         return (Z_INVAL);
5325         }
5326 
5327         return (Z_OK);
5328 }
5329 
5330 int
5331 zonecfg_default_brand(char *brand, size_t brandsize)
5332 {
5333         zone_dochandle_t handle;
5334         int myzoneid = getzoneid();
5335         int ret;
5336 
5337         /*
5338          * If we're running within a zone, then the default brand is the
5339          * current zone's brand.
5340          */
5341         if (myzoneid != GLOBAL_ZONEID) {
5342                 ret = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brand, brandsize);
5343                 if (ret < 0)
5344                         return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL);
5345                 return (Z_OK);
5346         }
5347 
5348         if ((handle = zonecfg_init_handle()) == NULL)
5349                 return (Z_NOMEM);
5350         if ((ret = zonecfg_get_handle("SUNWdefault", handle)) == Z_OK) {
5351                 ret = i_zonecfg_get_brand(handle, brand, brandsize, B_TRUE);
5352                 zonecfg_fini_handle(handle);
5353                 return (ret);
5354         }
5355         return (ret);
5356 }
5357 
5358 int
5359 zonecfg_default_privset(priv_set_t *privs, const char *curr_iptype)
5360 {
5361         priv_lists_t *plp;
5362         char buf[MAXNAMELEN];
5363         int ret;
5364 
5365         if ((ret = zonecfg_default_brand(buf, sizeof (buf))) != Z_OK)
5366                 return (ret);
5367         if ((ret = priv_lists_create(NULL, buf, &plp, curr_iptype)) != Z_OK)
5368                 return (ret);
5369         ret = get_default_privset(privs, plp);
5370         priv_lists_destroy(plp);
5371         return (ret);
5372 }
5373 
5374 void
5375 append_priv_token(char *priv, char *str, size_t strlen)
5376 {
5377         if (*str != '\0')
5378                 (void) strlcat(str, TOKEN_PRIV_STR, strlen);
5379         (void) strlcat(str, priv, strlen);
5380 }
5381 
5382 /*
5383  * Verify that the supplied string is a valid privilege limit set for a
5384  * non-global zone.  This string must not only be acceptable to
5385  * priv_str_to_set(3C) which parses it, but it also must resolve to a
5386  * privilege set that includes certain required privileges and lacks
5387  * certain prohibited privileges.
5388  */
5389 static int
5390 verify_privset(char *privbuf, priv_set_t *privs, char **privname,
5391     boolean_t add_default, priv_lists_t *plp)
5392 {
5393         priv_node_t *pnp;
5394         char *tmp, *cp, *lasts;
5395         size_t len;
5396         priv_set_t *mergeset;
5397         const char *token;
5398 
5399         /*
5400          * The verification of the privilege string occurs in several
5401          * phases.  In the first phase, the supplied string is scanned for
5402          * the ZONE_TOKEN token which is not support as part of the
5403          * "limitpriv" property.
5404          *
5405          * Duplicate the supplied privilege string since strtok_r(3C)
5406          * tokenizes its input by null-terminating the tokens.
5407          */
5408         if ((tmp = strdup(privbuf)) == NULL)
5409                 return (Z_NOMEM);
5410         for (cp = strtok_r(tmp, TOKEN_PRIV_STR, &lasts); cp != NULL;
5411             cp = strtok_r(NULL, TOKEN_PRIV_STR, &lasts)) {
5412                 if (strcmp(cp, ZONE_TOKEN) == 0) {
5413                         free(tmp);
5414                         if ((*privname = strdup(ZONE_TOKEN)) == NULL)
5415                                 return (Z_NOMEM);
5416                         else
5417                                 return (Z_PRIV_UNKNOWN);
5418                 }
5419         }
5420         free(tmp);
5421 
5422         if (add_default) {
5423                 /*
5424                  * If DEFAULT_TOKEN was specified, a string needs to be
5425                  * built containing the privileges from the default, safe
5426                  * set along with those of the "limitpriv" property.
5427                  */
5428                 len = strlen(privbuf) + sizeof (BASIC_TOKEN) + 2;
5429 
5430                 for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next)
5431                         len += strlen(pnp->pn_priv) + 1;
5432                 tmp = alloca(len);
5433                 *tmp = '\0';
5434 
5435                 append_priv_token(BASIC_TOKEN, tmp, len);
5436                 for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next)
5437                         append_priv_token(pnp->pn_priv, tmp, len);
5438                 (void) strlcat(tmp, TOKEN_PRIV_STR, len);
5439                 (void) strlcat(tmp, privbuf, len);
5440         } else {
5441                 tmp = privbuf;
5442         }
5443 
5444 
5445         /*
5446          * In the next phase, attempt to convert the merged privilege
5447          * string into a privilege set.  In the case of an error, either
5448          * there was a memory allocation failure or there was an invalid
5449          * privilege token in the string.  In either case, return an
5450          * appropriate error code but in the event of an invalid token,
5451          * allocate a string containing its name and return that back to
5452          * the caller.
5453          */
5454         mergeset = priv_str_to_set(tmp, TOKEN_PRIV_STR, &token);
5455         if (mergeset == NULL) {
5456                 if (token == NULL)
5457                         return (Z_NOMEM);
5458                 if ((cp = strchr(token, TOKEN_PRIV_CHAR)) != NULL)
5459                         *cp = '\0';
5460                 if ((*privname = strdup(token)) == NULL)
5461                         return (Z_NOMEM);
5462                 else
5463                         return (Z_PRIV_UNKNOWN);
5464         }
5465 
5466         /*
5467          * Next, verify that none of the prohibited zone privileges are
5468          * present in the merged privilege set.
5469          */
5470         for (pnp = plp->pl_prohibited; pnp != NULL; pnp = pnp->pn_next) {
5471                 if (priv_ismember(mergeset, pnp->pn_priv)) {
5472                         priv_freeset(mergeset);
5473                         if ((*privname = strdup(pnp->pn_priv)) == NULL)
5474                                 return (Z_NOMEM);
5475                         else
5476                                 return (Z_PRIV_PROHIBITED);
5477                 }
5478         }
5479 
5480         /*
5481          * Finally, verify that all of the required zone privileges are
5482          * present in the merged privilege set.
5483          */
5484         for (pnp = plp->pl_required; pnp != NULL; pnp = pnp->pn_next) {
5485                 if (!priv_ismember(mergeset, pnp->pn_priv)) {
5486                         priv_freeset(mergeset);
5487                         if ((*privname = strdup(pnp->pn_priv)) == NULL)
5488                                 return (Z_NOMEM);
5489                         else
5490                                 return (Z_PRIV_REQUIRED);
5491                 }
5492         }
5493 
5494         priv_copyset(mergeset, privs);
5495         priv_freeset(mergeset);
5496         return (Z_OK);
5497 }
5498 
5499 /*
5500  * Fill in the supplied privilege set with either the default, safe set of
5501  * privileges suitable for a non-global zone, or one based on the
5502  * "limitpriv" property in the zone's configuration.
5503  *
5504  * In the event of an invalid privilege specification in the
5505  * configuration, a string is allocated and returned containing the
5506  * "privilege" causing the issue.  It is the caller's responsibility to
5507  * free this memory when it is done with it.
5508  */
5509 int
5510 zonecfg_get_privset(zone_dochandle_t handle, priv_set_t *privs,
5511     char **privname)
5512 {
5513         priv_lists_t *plp;
5514         char *cp, *limitpriv = NULL;
5515         int err, limitlen;
5516         zone_iptype_t iptype;
5517         const char *curr_iptype;
5518 
5519         /*
5520          * Attempt to lookup the "limitpriv" property.  If it does not
5521          * exist or matches the string DEFAULT_TOKEN exactly, then the
5522          * default, safe privilege set is returned.
5523          */
5524         if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) != Z_OK)
5525                 return (err);
5526 
5527         if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK)
5528                 return (err);
5529 
5530         switch (iptype) {
5531         case ZS_SHARED:
5532                 curr_iptype = "shared";
5533                 break;
5534         case ZS_EXCLUSIVE:
5535                 curr_iptype = "exclusive";
5536                 break;
5537         }
5538 
5539         if ((err = priv_lists_create(handle, NULL, &plp, curr_iptype)) != Z_OK)
5540                 return (err);
5541 
5542         limitlen = strlen(limitpriv);
5543         if (limitlen == 0 || strcmp(limitpriv, DEFAULT_TOKEN) == 0) {
5544                 free(limitpriv);
5545                 err = get_default_privset(privs, plp);
5546                 priv_lists_destroy(plp);
5547                 return (err);
5548         }
5549 
5550         /*
5551          * Check if the string DEFAULT_TOKEN is the first token in a list
5552          * of privileges.
5553          */
5554         cp = strchr(limitpriv, TOKEN_PRIV_CHAR);
5555         if (cp != NULL &&
5556             strncmp(limitpriv, DEFAULT_TOKEN, cp - limitpriv) == 0)
5557                 err = verify_privset(cp + 1, privs, privname, B_TRUE, plp);
5558         else
5559                 err = verify_privset(limitpriv, privs, privname, B_FALSE, plp);
5560 
5561         free(limitpriv);
5562         priv_lists_destroy(plp);
5563         return (err);
5564 }
5565 
5566 int
5567 zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz)
5568 {
5569         zone_dochandle_t handle;
5570         boolean_t found = B_FALSE;
5571         struct zoneent *ze;
5572         FILE *cookie;
5573         int err;
5574         char *cp;
5575 
5576         if (zone_name == NULL)
5577                 return (Z_INVAL);
5578 
5579         (void) strlcpy(zonepath, zonecfg_root, rp_sz);
5580         cp = zonepath + strlen(zonepath);
5581         while (cp > zonepath && cp[-1] == '/')
5582                 *--cp = '\0';
5583 
5584         if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) {
5585                 if (zonepath[0] == '\0')
5586                         (void) strlcpy(zonepath, "/", rp_sz);
5587                 return (Z_OK);
5588         }
5589 
5590         /*
5591          * First check the index file.  Because older versions did not have
5592          * a copy of the zone path, allow for it to be zero length, in which
5593          * case we ignore this result and fall back to the XML files.
5594          */
5595         cookie = setzoneent();
5596         while ((ze = getzoneent_private(cookie)) != NULL) {
5597                 if (strcmp(ze->zone_name, zone_name) == 0) {
5598                         found = B_TRUE;
5599                         if (ze->zone_path[0] != '\0')
5600                                 (void) strlcpy(cp, ze->zone_path,
5601                                     rp_sz - (cp - zonepath));
5602                 }
5603                 free(ze);
5604                 if (found)
5605                         break;
5606         }
5607         endzoneent(cookie);
5608         if (found && *cp != '\0')
5609                 return (Z_OK);
5610 
5611         /* Fall back to the XML files. */
5612         if ((handle = zonecfg_init_handle()) == NULL)
5613                 return (Z_NOMEM);
5614 
5615         /*
5616          * Check the snapshot first: if a zone is running, its zonepath
5617          * may have changed.
5618          */
5619         if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
5620                 if ((err = zonecfg_get_handle(zone_name, handle)) != Z_OK) {
5621                         zonecfg_fini_handle(handle);
5622                         return (err);
5623                 }
5624         }
5625         err = zonecfg_get_zonepath(handle, zonepath, rp_sz);
5626         zonecfg_fini_handle(handle);
5627         return (err);
5628 }
5629 
5630 int
5631 zone_get_rootpath(char *zone_name, char *rootpath, size_t rp_sz)
5632 {
5633         int err;
5634 
5635         /* This function makes sense for non-global zones only. */
5636         if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
5637                 return (Z_BOGUS_ZONE_NAME);
5638         if ((err = zone_get_zonepath(zone_name, rootpath, rp_sz)) != Z_OK)
5639                 return (err);
5640         if (strlcat(rootpath, "/root", rp_sz) >= rp_sz)
5641                 return (Z_TOO_BIG);
5642         return (Z_OK);
5643 }
5644 
5645 int
5646 zone_get_brand(char *zone_name, char *brandname, size_t rp_sz)
5647 {
5648         int err;
5649         zone_dochandle_t handle;
5650         char myzone[MAXNAMELEN];
5651         int myzoneid = getzoneid();
5652 
5653         /*
5654          * If we are not in the global zone, then we don't have the zone
5655          * .xml files with the brand name available.  Thus, we are going to
5656          * have to ask the kernel for the information.
5657          */
5658         if (myzoneid != GLOBAL_ZONEID) {
5659                 if (is_system_labeled()) {
5660                         (void) strlcpy(brandname, NATIVE_BRAND_NAME, rp_sz);
5661                         return (Z_OK);
5662                 }
5663                 if (zone_getattr(myzoneid, ZONE_ATTR_NAME, myzone,
5664                     sizeof (myzone)) < 0)
5665                         return (Z_NO_ZONE);
5666                 if (!zonecfg_is_scratch(myzone)) {
5667                         if (strncmp(zone_name, myzone, MAXNAMELEN) != 0)
5668                                 return (Z_NO_ZONE);
5669                 }
5670                 err = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brandname, rp_sz);
5671                 if (err < 0)
5672                         return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL);
5673 
5674                 return (Z_OK);
5675         }
5676 
5677         if (strcmp(zone_name, "global") == 0)
5678                 return (zonecfg_default_brand(brandname, rp_sz));
5679 
5680         if ((handle = zonecfg_init_handle()) == NULL)
5681                 return (Z_NOMEM);
5682 
5683         err = zonecfg_get_handle((char *)zone_name, handle);
5684         if (err == Z_OK)
5685                 err = zonecfg_get_brand(handle, brandname, rp_sz);
5686 
5687         zonecfg_fini_handle(handle);
5688         return (err);
5689 }
5690 
5691 /*
5692  * Atomically get a new zone_did value.  The currently allocated value
5693  * is stored in /etc/zones/did.txt.  Lock the file, read the current value,
5694  * increment, save the new value and unlock the file.  Return the new value
5695  * or -1 if there was an error.  The ID namespace is large enough that we
5696  * don't worry about recycling an ID when a zone is deleted.
5697  */
5698 static zoneid_t
5699 new_zone_did()
5700 {
5701         int fd;
5702         int len;
5703         int val;
5704         struct flock lck;
5705         char pathbuf[PATH_MAX];
5706         char buf[80];
5707 
5708         if (snprintf(pathbuf, sizeof (pathbuf), "%s%s", zonecfg_get_root(),
5709             DEBUGID_FILE) >= sizeof (pathbuf)) {
5710                 printf(gettext("alternate root path is too long"));
5711                 return (-1);
5712         }
5713 
5714         if ((fd = open(pathbuf, O_RDWR | O_CREAT,
5715             S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
5716                 perror("new_zone_did open failed");
5717                 return (-1);
5718         }
5719 
5720         /* Initialize the lock. */
5721         lck.l_whence = SEEK_SET;
5722         lck.l_start = 0;
5723         lck.l_len = 0;
5724 
5725         /* Wait until we acquire an exclusive lock on the file. */
5726         lck.l_type = F_WRLCK;
5727         if (fcntl(fd, F_SETLKW, &lck) == -1) {
5728                 perror("new_zone_did lock failed");
5729                 (void) close(fd);
5730                 return (-1);
5731         }
5732 
5733         /* Get currently allocated value */
5734         len = read(fd, buf, sizeof (buf));
5735         if (len == -1) {
5736                 perror("new_zone_did read failed");
5737                 val = -1;
5738         } else {
5739                 if (lseek(fd, 0L, SEEK_SET) == -1) {
5740                         perror("new_zone_did seek failed");
5741                         val = -1;
5742                 } else {
5743                         if (len == 0) {
5744                                 /* Just created the file, initialize at 1 */
5745                                 val = 1;
5746                         } else {
5747                                 val = atoi(buf);
5748                                 val++;
5749                         }
5750 
5751                         (void) snprintf(buf, sizeof (buf), "%d\n", val);
5752                         len = strlen(buf);
5753 
5754                         /* Save newly allocated value */
5755                         if (write(fd, buf, len) == -1) {
5756                                 perror("new_zone_did write failed");
5757                                 val = -1;
5758                         }
5759                 }
5760         }
5761 
5762         /* Release the file lock. */
5763         lck.l_type = F_UNLCK;
5764         if (fcntl(fd, F_SETLK, &lck) == -1) {
5765                 perror("new_zone_did unlock failed");
5766                 val = -1;
5767         }
5768 
5769         if (close(fd) != 0)
5770                 perror("new_zone_did close failed");
5771 
5772         return (val);
5773 }
5774 
5775 /*
5776  * Called by zoneadmd to get the zone's debug ID.
5777  * If the zone doesn't already have an ID, a new one is generated and
5778  * persistently saved onto the zone.  Normally either zoneadm or zonecfg
5779  * will assign a new ID for the zone, so zoneadmd should never have to
5780  * generate one, but we also handle that here just to be paranoid.
5781  */
5782 zoneid_t
5783 zone_get_did(char *zone_name)
5784 {
5785         int res;
5786         zoneid_t new_did;
5787         zone_dochandle_t handle;
5788         char did_str[80];
5789 
5790         if ((handle = zonecfg_init_handle()) == NULL)
5791                 return (getpid());
5792 
5793         if (zonecfg_get_handle((char *)zone_name, handle) != Z_OK)
5794                 return (getpid());
5795 
5796         res = getrootattr(handle, DTD_ATTR_DID, did_str, sizeof (did_str));
5797 
5798         /* If the zone already has an assigned debug ID, return it. */
5799         if (res == Z_OK && did_str[0] != '\0') {
5800                 zonecfg_fini_handle(handle);
5801                 return (atoi(did_str));
5802         }
5803 
5804         /*
5805          * The zone doesn't have an assigned debug ID yet, generate one and
5806          * save it as part of the zone definition.
5807          */
5808         if ((new_did = new_zone_did()) == -1) {
5809                 /*
5810                  * We should really never hit this block of code.
5811                  * Generating a new ID failed for some reason.  Use the current
5812                  * pid as a temporary ID so that the zone can continue to boot
5813                  * but we don't persistently save this temporary ID on the zone.
5814                  */
5815                 zonecfg_fini_handle(handle);
5816                 return (getpid());
5817         }
5818 
5819         /* Now persistently save this new ID onto the zone. */
5820         (void) snprintf(did_str, sizeof (did_str), "%d", new_did);
5821         (void) setrootattr(handle, DTD_ATTR_DID, did_str);
5822         (void) zonecfg_save(handle);
5823 
5824         zonecfg_fini_handle(handle);
5825         return (new_did);
5826 }
5827 
5828 zoneid_t
5829 zonecfg_get_did(zone_dochandle_t handle)
5830 {
5831         char did_str[80];
5832         int err;
5833         zoneid_t did;
5834 
5835         err = getrootattr(handle, DTD_ATTR_DID, did_str, sizeof (did_str));
5836         if (err == Z_OK && did_str[0] != '\0')
5837                 did = atoi(did_str);
5838         else
5839                 did = -1;
5840 
5841         return (did);
5842 }
5843 
5844 void
5845 zonecfg_set_did(zone_dochandle_t handle)
5846 {
5847         zoneid_t new_did;
5848         char did_str[80];
5849 
5850         if ((new_did = new_zone_did()) == -1)
5851                 return;
5852         (void) snprintf(did_str, sizeof (did_str), "%d", new_did);
5853         (void) setrootattr(handle, DTD_ATTR_DID, did_str);
5854 }
5855 
5856 /*
5857  * Return the appropriate root for the active /dev.
5858  * For normal zone, the path is $ZONEPATH/root;
5859  * for scratch zone, the dev path is $ZONEPATH/lu.
5860  */
5861 int
5862 zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz)
5863 {
5864         int err;
5865         char *suffix;
5866         zone_state_t state;
5867 
5868         /* This function makes sense for non-global zones only. */
5869         if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
5870                 return (Z_BOGUS_ZONE_NAME);
5871         if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK)
5872                 return (err);
5873 
5874         if (zone_get_state(zone_name, &state) == Z_OK &&
5875             state == ZONE_STATE_MOUNTED)
5876                 suffix = "/lu";
5877         else
5878                 suffix = "/root";
5879         if (strlcat(devroot, suffix, rp_sz) >= rp_sz)
5880                 return (Z_TOO_BIG);
5881         return (Z_OK);
5882 }
5883 
5884 static zone_state_t
5885 kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state)
5886 {
5887         char zoneroot[MAXPATHLEN];
5888         size_t zlen;
5889 
5890         assert(kernel_state <= ZONE_MAX_STATE);
5891         switch (kernel_state) {
5892                 case ZONE_IS_UNINITIALIZED:
5893                 case ZONE_IS_INITIALIZED:
5894                         /* The kernel will not return these two states */
5895                         return (ZONE_STATE_READY);
5896                 case ZONE_IS_READY:
5897                         /*
5898                          * If the zone's root is mounted on $ZONEPATH/lu, then
5899                          * it's a mounted scratch zone.
5900                          */
5901                         if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot,
5902                             sizeof (zoneroot)) >= 0) {
5903                                 zlen = strlen(zoneroot);
5904                                 if (zlen > 3 &&
5905                                     strcmp(zoneroot + zlen - 3, "/lu") == 0)
5906                                         return (ZONE_STATE_MOUNTED);
5907                         }
5908                         return (ZONE_STATE_READY);
5909                 case ZONE_IS_BOOTING:
5910                 case ZONE_IS_RUNNING:
5911                         return (ZONE_STATE_RUNNING);
5912                 case ZONE_IS_SHUTTING_DOWN:
5913                 case ZONE_IS_EMPTY:
5914                         return (ZONE_STATE_SHUTTING_DOWN);
5915                 case ZONE_IS_DOWN:
5916                 case ZONE_IS_DYING:
5917                 case ZONE_IS_DEAD:
5918                 default:
5919                         return (ZONE_STATE_DOWN);
5920         }
5921         /* NOTREACHED */
5922 }
5923 
5924 int
5925 zone_get_state(char *zone_name, zone_state_t *state_num)
5926 {
5927         zone_status_t status;
5928         zoneid_t zone_id;
5929         struct zoneent *ze;
5930         boolean_t found = B_FALSE;
5931         FILE *cookie;
5932         char kernzone[ZONENAME_MAX];
5933         FILE *fp;
5934 
5935         if (zone_name == NULL)
5936                 return (Z_INVAL);
5937 
5938         /*
5939          * If we're looking at an alternate root, then we need to query the
5940          * kernel using the scratch zone name.
5941          */
5942         zone_id = -1;
5943         if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) {
5944                 if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) {
5945                         if (zonecfg_find_scratch(fp, zone_name, zonecfg_root,
5946                             kernzone, sizeof (kernzone)) == 0)
5947                                 zone_id = getzoneidbyname(kernzone);
5948                         zonecfg_close_scratch(fp);
5949                 }
5950         } else {
5951                 zone_id = getzoneidbyname(zone_name);
5952         }
5953 
5954         /* check to see if zone is running */
5955         if (zone_id != -1 &&
5956             zone_getattr(zone_id, ZONE_ATTR_STATUS, &status,
5957             sizeof (status)) >= 0) {
5958                 *state_num = kernel_state_to_user_state(zone_id, status);
5959                 return (Z_OK);
5960         }
5961 
5962         cookie = setzoneent();
5963         while ((ze = getzoneent_private(cookie)) != NULL) {
5964                 if (strcmp(ze->zone_name, zone_name) == 0) {
5965                         found = B_TRUE;
5966                         *state_num = ze->zone_state;
5967                 }
5968                 free(ze);
5969                 if (found)
5970                         break;
5971         }
5972         endzoneent(cookie);
5973         return ((found) ? Z_OK : Z_NO_ZONE);
5974 }
5975 
5976 int
5977 zone_set_state(char *zone, zone_state_t state)
5978 {
5979         struct zoneent ze;
5980 
5981         if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED &&
5982             state != ZONE_STATE_INCOMPLETE)
5983                 return (Z_INVAL);
5984 
5985         bzero(&ze, sizeof (ze));
5986         (void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name));
5987         ze.zone_state = state;
5988         (void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path));
5989         return (putzoneent(&ze, PZE_MODIFY));
5990 }
5991 
5992 /*
5993  * Get id (if any) for specified zone.  There are four possible outcomes:
5994  * - If the string corresponds to the numeric id of an active (booted)
5995  *   zone, sets *zip to the zone id and returns 0.
5996  * - If the string corresponds to the name of an active (booted) zone,
5997  *   sets *zip to the zone id and returns 0.
5998  * - If the string is a name in the configuration but is not booted,
5999  *   sets *zip to ZONE_ID_UNDEFINED and returns 0.
6000  * - Otherwise, leaves *zip unchanged and returns -1.
6001  *
6002  * This function acts as an auxiliary filter on the function of the same
6003  * name in libc; the linker binds to this version if libzonecfg exists,
6004  * and the libc version if it doesn't.  Any changes to this version of
6005  * the function should probably be reflected in the libc version as well.
6006  */
6007 int
6008 zone_get_id(const char *str, zoneid_t *zip)
6009 {
6010         zone_dochandle_t hdl;
6011         zoneid_t zoneid;
6012         char *cp;
6013         int err;
6014 
6015         /* first try looking for active zone by id */
6016         errno = 0;
6017         zoneid = (zoneid_t)strtol(str, &cp, 0);
6018         if (errno == 0 && cp != str && *cp == '\0' &&
6019             getzonenamebyid(zoneid, NULL, 0) != -1) {
6020                 *zip = zoneid;
6021                 return (0);
6022         }
6023 
6024         /* then look for active zone by name */
6025         if ((zoneid = getzoneidbyname(str)) != -1) {
6026                 *zip = zoneid;
6027                 return (0);
6028         }
6029 
6030         /* if in global zone, try looking up name in configuration database */
6031         if (getzoneid() != GLOBAL_ZONEID ||
6032             (hdl = zonecfg_init_handle()) == NULL)
6033                 return (-1);
6034 
6035         if (zonecfg_get_handle(str, hdl) == Z_OK) {
6036                 /* zone exists but isn't active */
6037                 *zip = ZONE_ID_UNDEFINED;
6038                 err = 0;
6039         } else {
6040                 err = -1;
6041         }
6042 
6043         zonecfg_fini_handle(hdl);
6044         return (err);
6045 }
6046 
6047 char *
6048 zone_state_str(zone_state_t state_num)
6049 {
6050         switch (state_num) {
6051         case ZONE_STATE_CONFIGURED:
6052                 return (ZONE_STATE_STR_CONFIGURED);
6053         case ZONE_STATE_INCOMPLETE:
6054                 return (ZONE_STATE_STR_INCOMPLETE);
6055         case ZONE_STATE_INSTALLED:
6056                 return (ZONE_STATE_STR_INSTALLED);
6057         case ZONE_STATE_READY:
6058                 return (ZONE_STATE_STR_READY);
6059         case ZONE_STATE_MOUNTED:
6060                 return (ZONE_STATE_STR_MOUNTED);
6061         case ZONE_STATE_RUNNING:
6062                 return (ZONE_STATE_STR_RUNNING);
6063         case ZONE_STATE_SHUTTING_DOWN:
6064                 return (ZONE_STATE_STR_SHUTTING_DOWN);
6065         case ZONE_STATE_DOWN:
6066                 return (ZONE_STATE_STR_DOWN);
6067         default:
6068                 return ("unknown");
6069         }
6070 }
6071 
6072 /*
6073  * Given a UUID value, find an associated zone name.  This is intended to be
6074  * used by callers who set up some 'default' name (corresponding to the
6075  * expected name for the zone) in the zonename buffer, and thus the function
6076  * doesn't touch this buffer on failure.
6077  */
6078 int
6079 zonecfg_get_name_by_uuid(const uuid_t uuidin, char *zonename, size_t namelen)
6080 {
6081         FILE *fp;
6082         struct zoneent *ze;
6083         uchar_t *uuid;
6084 
6085         /*
6086          * A small amount of subterfuge via casts is necessary here because
6087          * libuuid doesn't use const correctly, but we don't want to export
6088          * this brokenness to our clients.
6089          */
6090         uuid = (uchar_t *)uuidin;
6091         if (uuid_is_null(uuid))
6092                 return (Z_NO_ZONE);
6093         if ((fp = setzoneent()) == NULL)
6094                 return (Z_NO_ZONE);
6095         while ((ze = getzoneent_private(fp)) != NULL) {
6096                 if (uuid_compare(uuid, ze->zone_uuid) == 0)
6097                         break;
6098                 free(ze);
6099         }
6100         endzoneent(fp);
6101         if (ze != NULL) {
6102                 (void) strlcpy(zonename, ze->zone_name, namelen);
6103                 free(ze);
6104                 return (Z_OK);
6105         } else {
6106                 return (Z_NO_ZONE);
6107         }
6108 }
6109 
6110 /*
6111  * Given a zone name, get its UUID.  Returns a "NULL" UUID value if the zone
6112  * exists but the file doesn't have a value set yet.  Returns an error if the
6113  * zone cannot be located.
6114  */
6115 int
6116 zonecfg_get_uuid(const char *zonename, uuid_t uuid)
6117 {
6118         FILE *fp;
6119         struct zoneent *ze;
6120 
6121         if ((fp = setzoneent()) == NULL)
6122                 return (Z_NO_ZONE);
6123         while ((ze = getzoneent_private(fp)) != NULL) {
6124                 if (strcmp(ze->zone_name, zonename) == 0)
6125                         break;
6126                 free(ze);
6127         }
6128         endzoneent(fp);
6129         if (ze != NULL) {
6130                 uuid_copy(uuid, ze->zone_uuid);
6131                 free(ze);
6132                 return (Z_OK);
6133         } else {
6134                 return (Z_NO_ZONE);
6135         }
6136 }
6137 
6138 /*
6139  * File-system convenience functions.
6140  */
6141 boolean_t
6142 zonecfg_valid_fs_type(const char *type)
6143 {
6144         /*
6145          * We already know which FS types don't work.
6146          */
6147         if (strcmp(type, "proc") == 0 ||
6148             strcmp(type, "mntfs") == 0 ||
6149             strcmp(type, "autofs") == 0 ||
6150             strncmp(type, "nfs", sizeof ("nfs") - 1) == 0)
6151                 return (B_FALSE);
6152         /*
6153          * The caller may do more detailed verification to make sure other
6154          * aspects of this filesystem type make sense.
6155          */
6156         return (B_TRUE);
6157 }
6158 
6159 /*
6160  * Generally uninteresting rctl convenience functions.
6161  */
6162 
6163 int
6164 zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval,
6165     rctlblk_t *rctlblk)
6166 {
6167         unsigned long long ull;
6168         char *endp;
6169         rctl_priv_t priv;
6170         rctl_qty_t limit;
6171         uint_t action;
6172 
6173         /* Get the privilege */
6174         if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) {
6175                 priv = RCPRIV_BASIC;
6176         } else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) {
6177                 priv = RCPRIV_PRIVILEGED;
6178         } else {
6179                 /* Invalid privilege */
6180                 return (Z_INVAL);
6181         }
6182 
6183         /* deal with negative input; strtoull(3c) doesn't do what we want */
6184         if (rctlval->zone_rctlval_limit[0] == '-')
6185                 return (Z_INVAL);
6186         /* Get the limit */
6187         errno = 0;
6188         ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0);
6189         if (errno != 0 || *endp != '\0') {
6190                 /* parse failed */
6191                 return (Z_INVAL);
6192         }
6193         limit = (rctl_qty_t)ull;
6194 
6195         /* Get the action */
6196         if (strcmp(rctlval->zone_rctlval_action, "none") == 0) {
6197                 action = RCTL_LOCAL_NOACTION;
6198         } else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) {
6199                 action = RCTL_LOCAL_SIGNAL;
6200         } else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) {
6201                 action = RCTL_LOCAL_DENY;
6202         } else {
6203                 /* Invalid Action */
6204                 return (Z_INVAL);
6205         }
6206         rctlblk_set_local_action(rctlblk, action, 0);
6207         rctlblk_set_privilege(rctlblk, priv);
6208         rctlblk_set_value(rctlblk, limit);
6209         return (Z_OK);
6210 }
6211 
6212 static int
6213 rctl_check(const char *rctlname, void *arg)
6214 {
6215         const char *attrname = arg;
6216 
6217         /*
6218          * Returning 1 here is our signal to zonecfg_is_rctl() that it is
6219          * indeed an rctl name recognized by the system.
6220          */
6221         return (strcmp(rctlname, attrname) == 0 ? 1 : 0);
6222 }
6223 
6224 boolean_t
6225 zonecfg_is_rctl(const char *name)
6226 {
6227         return (rctl_walk(rctl_check, (void *)name) == 1);
6228 }
6229 
6230 boolean_t
6231 zonecfg_valid_rctlname(const char *name)
6232 {
6233         const char *c;
6234 
6235         if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0)
6236                 return (B_FALSE);
6237         if (strlen(name) == sizeof ("zone.") - 1)
6238                 return (B_FALSE);
6239         for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) {
6240                 if (!isalpha(*c) && *c != '-')
6241                         return (B_FALSE);
6242         }
6243         return (B_TRUE);
6244 }
6245 
6246 boolean_t
6247 zonecfg_valid_rctlblk(const rctlblk_t *rctlblk)
6248 {
6249         rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk);
6250         uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
6251 
6252         if (priv != RCPRIV_PRIVILEGED)
6253                 return (B_FALSE);
6254         if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY)
6255                 return (B_FALSE);
6256         return (B_TRUE);
6257 }
6258 
6259 boolean_t
6260 zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk)
6261 {
6262         rctlblk_t *current, *next;
6263         rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk);
6264         uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
6265         uint_t global_flags;
6266 
6267         if (!zonecfg_valid_rctlblk(rctlblk))
6268                 return (B_FALSE);
6269         if (!zonecfg_valid_rctlname(name))
6270                 return (B_FALSE);
6271 
6272         current = alloca(rctlblk_size());
6273         if (getrctl(name, NULL, current, RCTL_FIRST) != 0)
6274                 return (B_TRUE);        /* not an rctl on this system */
6275         /*
6276          * Make sure the proposed value isn't greater than the current system
6277          * value.
6278          */
6279         next = alloca(rctlblk_size());
6280         while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) {
6281                 rctlblk_t *tmp;
6282 
6283                 if (getrctl(name, current, next, RCTL_NEXT) != 0)
6284                         return (B_FALSE);       /* shouldn't happen */
6285                 tmp = current;
6286                 current = next;
6287                 next = tmp;
6288         }
6289         if (limit > rctlblk_get_value(current))
6290                 return (B_FALSE);
6291 
6292         /*
6293          * Make sure the proposed action is allowed.
6294          */
6295         global_flags = rctlblk_get_global_flags(current);
6296         if ((global_flags & RCTL_GLOBAL_DENY_NEVER) &&
6297             action == RCTL_LOCAL_DENY)
6298                 return (B_FALSE);
6299         if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) &&
6300             action == RCTL_LOCAL_NOACTION)
6301                 return (B_FALSE);
6302 
6303         return (B_TRUE);
6304 }
6305 
6306 /*
6307  * There is always a race condition between reading the initial copy of
6308  * a zones state and its state changing.  We address this by providing
6309  * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions.
6310  * When zonecfg_critical_enter is called, sets the state field to LOCKED
6311  * and aquires biglock. Biglock protects against other threads executing
6312  * critical_enter and the state field protects against state changes during
6313  * the critical period.
6314  *
6315  * If any state changes occur, zn_cb will set the failed field of the znotify
6316  * structure.  This will cause the critical_exit function to re-lock the
6317  * channel and return an error. Since evsnts may be delayed, the critical_exit
6318  * function "flushes" the queue by putting an event on the queue and waiting for
6319  * zn_cb to notify critical_exit that it received the ping event.
6320  */
6321 static const char *
6322 string_get_tok(const char *in, char delim, int num)
6323 {
6324         int i = 0;
6325 
6326         for (; i < num; in++) {
6327                 if (*in == delim)
6328                         i++;
6329                 if (*in == 0)
6330                         return (NULL);
6331         }
6332         return (in);
6333 }
6334 
6335 static boolean_t
6336 is_ping(sysevent_t *ev)
6337 {
6338         if (strcmp(sysevent_get_subclass_name(ev),
6339             ZONE_EVENT_PING_SUBCLASS) == 0) {
6340                 return (B_TRUE);
6341         } else {
6342                 return (B_FALSE);
6343         }
6344 }
6345 
6346 static boolean_t
6347 is_my_ping(sysevent_t *ev)
6348 {
6349         const char *sender;
6350         char mypid[sizeof (pid_t) * 3 + 1];
6351 
6352         (void) snprintf(mypid, sizeof (mypid), "%i", getpid());
6353         sender = string_get_tok(sysevent_get_pub(ev), ':', 3);
6354         if (sender == NULL)
6355                 return (B_FALSE);
6356         if (strcmp(sender, mypid) != 0)
6357                 return (B_FALSE);
6358         return (B_TRUE);
6359 }
6360 
6361 static int
6362 do_callback(struct znotify *zevtchan, sysevent_t *ev)
6363 {
6364         nvlist_t *l;
6365         int zid;
6366         char *zonename;
6367         char *newstate;
6368         char *oldstate;
6369         int ret;
6370         hrtime_t when;
6371 
6372         if (strcmp(sysevent_get_subclass_name(ev),
6373             ZONE_EVENT_STATUS_SUBCLASS) == 0) {
6374 
6375                 if (sysevent_get_attr_list(ev, &l) != 0) {
6376                         if (errno == ENOMEM) {
6377                                 zevtchan->zn_failure_count++;
6378                                 return (EAGAIN);
6379                         }
6380                         return (0);
6381                 }
6382                 ret = 0;
6383 
6384                 if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) &&
6385                     (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate)
6386                     == 0) &&
6387                     (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate)
6388                     == 0) &&
6389                     (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP,
6390                     (uint64_t *)&when) == 0) &&
6391                     (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) {
6392                         ret = zevtchan->zn_callback(zonename, zid, newstate,
6393                             oldstate, when, zevtchan->zn_private);
6394                 }
6395 
6396                 zevtchan->zn_failure_count = 0;
6397                 nvlist_free(l);
6398                 return (ret);
6399         } else {
6400                 /*
6401                  * We have received an event in an unknown subclass. Ignore.
6402                  */
6403                 zevtchan->zn_failure_count = 0;
6404                 return (0);
6405         }
6406 }
6407 
6408 static int
6409 zn_cb(sysevent_t *ev, void *p)
6410 {
6411         struct znotify *zevtchan = p;
6412         int error;
6413 
6414         (void) pthread_mutex_lock(&(zevtchan->zn_mutex));
6415 
6416         if (is_ping(ev) && !is_my_ping(ev)) {
6417                 (void) pthread_mutex_unlock((&zevtchan->zn_mutex));
6418                 return (0);
6419         }
6420 
6421         if (zevtchan->zn_state == ZN_LOCKED) {
6422                 assert(!is_ping(ev));
6423                 zevtchan->zn_failed = B_TRUE;
6424                 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
6425                 return (0);
6426         }
6427 
6428         if (zevtchan->zn_state == ZN_PING_INFLIGHT) {
6429                 if (is_ping(ev)) {
6430                         zevtchan->zn_state = ZN_PING_RECEIVED;
6431                         (void) pthread_cond_signal(&(zevtchan->zn_cond));
6432                         (void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
6433                         return (0);
6434                 } else {
6435                         zevtchan->zn_failed = B_TRUE;
6436                         (void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
6437                         return (0);
6438                 }
6439         }
6440 
6441         if (zevtchan->zn_state == ZN_UNLOCKED) {
6442 
6443                 error = do_callback(zevtchan, ev);
6444                 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
6445                 /*
6446                  * Every ENOMEM failure causes do_callback to increment
6447                  * zn_failure_count and every success causes it to
6448                  * set zn_failure_count to zero.  If we got EAGAIN,
6449                  * we will sleep for zn_failure_count seconds and return
6450                  * EAGAIN to gpec to try again.
6451                  *
6452                  * After 55 seconds, or 10 try's we give up and drop the
6453                  * event.
6454                  */
6455                 if (error == EAGAIN) {
6456                         if (zevtchan->zn_failure_count > ZONE_CB_RETRY_COUNT) {
6457                                 return (0);
6458                         }
6459                         (void) sleep(zevtchan->zn_failure_count);
6460                 }
6461                 return (error);
6462         }
6463 
6464         if (zevtchan->zn_state == ZN_PING_RECEIVED) {
6465                 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
6466                 return (0);
6467         }
6468 
6469         abort();
6470         return (0);
6471 }
6472 
6473 void
6474 zonecfg_notify_critical_enter(void *h)
6475 {
6476         struct znotify *zevtchan = h;
6477 
6478         (void) pthread_mutex_lock(&(zevtchan->zn_bigmutex));
6479         zevtchan->zn_state = ZN_LOCKED;
6480 }
6481 
6482 int
6483 zonecfg_notify_critical_exit(void * h)
6484 {
6485 
6486         struct znotify *zevtchan = h;
6487 
6488         if (zevtchan->zn_state == ZN_UNLOCKED)
6489                 return (0);
6490 
6491         (void) pthread_mutex_lock(&(zevtchan->zn_mutex));
6492         zevtchan->zn_state = ZN_PING_INFLIGHT;
6493 
6494         (void) sysevent_evc_publish(zevtchan->zn_eventchan,
6495             ZONE_EVENT_STATUS_CLASS,
6496             ZONE_EVENT_PING_SUBCLASS, ZONE_EVENT_PING_PUBLISHER,
6497             zevtchan->zn_subscriber_id, NULL, EVCH_SLEEP);
6498 
6499         while (zevtchan->zn_state != ZN_PING_RECEIVED) {
6500                 (void) pthread_cond_wait(&(zevtchan->zn_cond),
6501                     &(zevtchan->zn_mutex));
6502         }
6503 
6504         if (zevtchan->zn_failed == B_TRUE) {
6505                 zevtchan->zn_state = ZN_LOCKED;
6506                 zevtchan->zn_failed = B_FALSE;
6507                 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
6508                 return (1);
6509         }
6510 
6511         zevtchan->zn_state = ZN_UNLOCKED;
6512         (void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
6513         (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex));
6514         return (0);
6515 }
6516 
6517 void
6518 zonecfg_notify_critical_abort(void *h)
6519 {
6520         struct znotify *zevtchan = h;
6521 
6522         zevtchan->zn_state = ZN_UNLOCKED;
6523         zevtchan->zn_failed = B_FALSE;
6524         /*
6525          * Don't do anything about zn_lock. If it is held, it could only be
6526          * held by zn_cb and it will be unlocked soon.
6527          */
6528         (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex));
6529 }
6530 
6531 void *
6532 zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid,
6533     const char *newstate, const char *oldstate, hrtime_t when, void *p),
6534     void *p)
6535 {
6536         struct znotify *zevtchan;
6537         int i = 1;
6538         int r;
6539 
6540         zevtchan = malloc(sizeof (struct znotify));
6541 
6542         if (zevtchan == NULL)
6543                 return (NULL);
6544 
6545         zevtchan->zn_private = p;
6546         zevtchan->zn_callback = func;
6547         zevtchan->zn_state = ZN_UNLOCKED;
6548         zevtchan->zn_failed = B_FALSE;
6549 
6550         if (pthread_mutex_init(&(zevtchan->zn_mutex), NULL))
6551                 goto out3;
6552         if (pthread_cond_init(&(zevtchan->zn_cond), NULL)) {
6553                 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex));
6554                 goto out3;
6555         }
6556         if (pthread_mutex_init(&(zevtchan->zn_bigmutex), NULL)) {
6557                 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex));
6558                 (void) pthread_cond_destroy(&(zevtchan->zn_cond));
6559                 goto out3;
6560         }
6561 
6562         if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &(zevtchan->zn_eventchan),
6563             0) != 0)
6564                 goto out2;
6565 
6566         do {
6567                 /*
6568                  * At 4 digits the subscriber ID gets too long and we have
6569                  * no chance of successfully registering.
6570                  */
6571                 if (i > 999)
6572                         goto out1;
6573 
6574                 (void) sprintf(zevtchan->zn_subscriber_id, "zone_%li_%i",
6575                     getpid() % 999999l, i);
6576 
6577                 r = sysevent_evc_subscribe(zevtchan->zn_eventchan,
6578                     zevtchan->zn_subscriber_id, ZONE_EVENT_STATUS_CLASS, zn_cb,
6579                     zevtchan, 0);
6580 
6581                 i++;
6582 
6583         } while (r);
6584 
6585         return (zevtchan);
6586 out1:
6587         (void) sysevent_evc_unbind(zevtchan->zn_eventchan);
6588 out2:
6589         (void) pthread_mutex_destroy(&zevtchan->zn_mutex);
6590         (void) pthread_cond_destroy(&zevtchan->zn_cond);
6591         (void) pthread_mutex_destroy(&(zevtchan->zn_bigmutex));
6592 out3:
6593         free(zevtchan);
6594 
6595         return (NULL);
6596 }
6597 
6598 void
6599 zonecfg_notify_unbind(void *handle)
6600 {
6601 
6602         int ret;
6603 
6604         (void) sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan);
6605         /*
6606          * Check that all evc threads have gone away. This should be
6607          * enforced by sysevent_evc_unbind.
6608          */
6609         ret = pthread_mutex_trylock(&((struct znotify *)handle)->zn_mutex);
6610 
6611         if (ret)
6612                 abort();
6613 
6614         (void) pthread_mutex_unlock(&((struct znotify *)handle)->zn_mutex);
6615         (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_mutex);
6616         (void) pthread_cond_destroy(&((struct znotify *)handle)->zn_cond);
6617         (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_bigmutex);
6618 
6619         free(handle);
6620 }
6621 
6622 static int
6623 zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
6624 {
6625         xmlNodePtr newnode, cur = handle->zone_dh_cur;
6626         int err;
6627 
6628         newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DATASET, NULL);
6629         if ((err = newprop(newnode, DTD_ATTR_NAME,
6630             tabptr->zone_dataset_name)) != Z_OK)
6631                 return (err);
6632         return (Z_OK);
6633 }
6634 
6635 int
6636 zonecfg_add_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
6637 {
6638         int err;
6639 
6640         if (tabptr == NULL)
6641                 return (Z_INVAL);
6642 
6643         if ((err = operation_prep(handle)) != Z_OK)
6644                 return (err);
6645 
6646         if ((err = zonecfg_add_ds_core(handle, tabptr)) != Z_OK)
6647                 return (err);
6648 
6649         return (Z_OK);
6650 }
6651 
6652 static int
6653 zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
6654 {
6655         xmlNodePtr cur = handle->zone_dh_cur;
6656 
6657         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6658                 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET))
6659                         continue;
6660 
6661                 if (match_prop(cur, DTD_ATTR_NAME,
6662                     tabptr->zone_dataset_name)) {
6663                         xmlUnlinkNode(cur);
6664                         xmlFreeNode(cur);
6665                         return (Z_OK);
6666                 }
6667         }
6668         return (Z_NO_RESOURCE_ID);
6669 }
6670 
6671 int
6672 zonecfg_delete_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
6673 {
6674         int err;
6675 
6676         if (tabptr == NULL)
6677                 return (Z_INVAL);
6678 
6679         if ((err = operation_prep(handle)) != Z_OK)
6680                 return (err);
6681 
6682         if ((err = zonecfg_delete_ds_core(handle, tabptr)) != Z_OK)
6683                 return (err);
6684 
6685         return (Z_OK);
6686 }
6687 
6688 int
6689 zonecfg_modify_ds(
6690         zone_dochandle_t handle,
6691         struct zone_dstab *oldtabptr,
6692         struct zone_dstab *newtabptr)
6693 {
6694         int err;
6695 
6696         if (oldtabptr == NULL || newtabptr == NULL)
6697                 return (Z_INVAL);
6698 
6699         if ((err = operation_prep(handle)) != Z_OK)
6700                 return (err);
6701 
6702         if ((err = zonecfg_delete_ds_core(handle, oldtabptr)) != Z_OK)
6703                 return (err);
6704 
6705         if ((err = zonecfg_add_ds_core(handle, newtabptr)) != Z_OK)
6706                 return (err);
6707 
6708         return (Z_OK);
6709 }
6710 
6711 int
6712 zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
6713 {
6714         xmlNodePtr cur, firstmatch;
6715         int err;
6716         char dataset[MAXNAMELEN];
6717 
6718         if (tabptr == NULL)
6719                 return (Z_INVAL);
6720 
6721         if ((err = operation_prep(handle)) != Z_OK)
6722                 return (err);
6723 
6724         cur = handle->zone_dh_cur;
6725         firstmatch = NULL;
6726         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6727                 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET))
6728                         continue;
6729                 if (strlen(tabptr->zone_dataset_name) > 0) {
6730                         if ((fetchprop(cur, DTD_ATTR_NAME, dataset,
6731                             sizeof (dataset)) == Z_OK) &&
6732                             (strcmp(tabptr->zone_dataset_name,
6733                             dataset) == 0)) {
6734                                 if (firstmatch == NULL)
6735                                         firstmatch = cur;
6736                                 else
6737                                         return (Z_INSUFFICIENT_SPEC);
6738                         }
6739                 }
6740         }
6741         if (firstmatch == NULL)
6742                 return (Z_NO_RESOURCE_ID);
6743 
6744         cur = firstmatch;
6745 
6746         if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
6747             sizeof (tabptr->zone_dataset_name))) != Z_OK)
6748                 return (err);
6749 
6750         return (Z_OK);
6751 }
6752 
6753 int
6754 zonecfg_setdsent(zone_dochandle_t handle)
6755 {
6756         return (zonecfg_setent(handle));
6757 }
6758 
6759 int
6760 zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr)
6761 {
6762         xmlNodePtr cur;
6763         int err;
6764 
6765         if (handle == NULL)
6766                 return (Z_INVAL);
6767 
6768         if ((cur = handle->zone_dh_cur) == NULL)
6769                 return (Z_NO_ENTRY);
6770 
6771         for (; cur != NULL; cur = cur->next)
6772                 if (!xmlStrcmp(cur->name, DTD_ELEM_DATASET))
6773                         break;
6774         if (cur == NULL) {
6775                 handle->zone_dh_cur = handle->zone_dh_top;
6776                 return (Z_NO_ENTRY);
6777         }
6778 
6779         if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
6780             sizeof (tabptr->zone_dataset_name))) != Z_OK) {
6781                 handle->zone_dh_cur = handle->zone_dh_top;
6782                 return (err);
6783         }
6784 
6785         handle->zone_dh_cur = cur->next;
6786         return (Z_OK);
6787 }
6788 
6789 int
6790 zonecfg_enddsent(zone_dochandle_t handle)
6791 {
6792         return (zonecfg_endent(handle));
6793 }
6794 
6795 /*
6796  * Support for aliased rctls; that is, rctls that have simplified names in
6797  * zonecfg.  For example, max-lwps is an alias for a well defined zone.max-lwps
6798  * rctl.  If there are multiple existing values for one of these rctls or if
6799  * there is a single value that does not match the well defined template (i.e.
6800  * it has a different action) then we cannot treat the rctl as having an alias
6801  * so we return Z_ALIAS_DISALLOW.  That means that the rctl cannot be
6802  * managed in zonecfg via an alias and that the standard rctl syntax must be
6803  * used.
6804  *
6805  * The possible return values are:
6806  *      Z_NO_PROPERTY_ID - invalid alias name
6807  *      Z_ALIAS_DISALLOW - pre-existing, incompatible rctl definition
6808  *      Z_NO_ENTRY - no rctl is configured for this alias
6809  *      Z_OK - we got a valid rctl for the specified alias
6810  */
6811 int
6812 zonecfg_get_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t *rval)
6813 {
6814         boolean_t found = B_FALSE;
6815         boolean_t found_val = B_FALSE;
6816         xmlNodePtr cur, val;
6817         char savedname[MAXNAMELEN];
6818         struct zone_rctlvaltab rctl;
6819         int i;
6820         int err;
6821 
6822         for (i = 0; aliases[i].shortname != NULL; i++)
6823                 if (strcmp(name, aliases[i].shortname) == 0)
6824                         break;
6825 
6826         if (aliases[i].shortname == NULL)
6827                 return (Z_NO_PROPERTY_ID);
6828 
6829         if ((err = operation_prep(handle)) != Z_OK)
6830                 return (err);
6831 
6832         cur = handle->zone_dh_cur;
6833         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6834                 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL) != 0)
6835                         continue;
6836                 if ((fetchprop(cur, DTD_ATTR_NAME, savedname,
6837                     sizeof (savedname)) == Z_OK) &&
6838                     (strcmp(savedname, aliases[i].realname) == 0)) {
6839 
6840                         /*
6841                          * If we already saw one of these, we can't have an
6842                          * alias since we just found another.
6843                          */
6844                         if (found)
6845                                 return (Z_ALIAS_DISALLOW);
6846                         found = B_TRUE;
6847 
6848                         for (val = cur->xmlChildrenNode; val != NULL;
6849                             val = val->next) {
6850                                 /*
6851                                  * If we already have one value, we can't have
6852                                  * an alias since we just found another.
6853                                  */
6854                                 if (found_val)
6855                                         return (Z_ALIAS_DISALLOW);
6856                                 found_val = B_TRUE;
6857 
6858                                 if ((fetchprop(val, DTD_ATTR_PRIV,
6859                                     rctl.zone_rctlval_priv,
6860                                     sizeof (rctl.zone_rctlval_priv)) != Z_OK))
6861                                         break;
6862                                 if ((fetchprop(val, DTD_ATTR_LIMIT,
6863                                     rctl.zone_rctlval_limit,
6864                                     sizeof (rctl.zone_rctlval_limit)) != Z_OK))
6865                                         break;
6866                                 if ((fetchprop(val, DTD_ATTR_ACTION,
6867                                     rctl.zone_rctlval_action,
6868                                     sizeof (rctl.zone_rctlval_action)) != Z_OK))
6869                                         break;
6870                         }
6871 
6872                         /* check priv and action match the expected vals */
6873                         if (strcmp(rctl.zone_rctlval_priv,
6874                             aliases[i].priv) != 0 ||
6875                             strcmp(rctl.zone_rctlval_action,
6876                             aliases[i].action) != 0)
6877                                 return (Z_ALIAS_DISALLOW);
6878                 }
6879         }
6880 
6881         if (found) {
6882                 *rval = strtoull(rctl.zone_rctlval_limit, NULL, 10);
6883                 return (Z_OK);
6884         }
6885 
6886         return (Z_NO_ENTRY);
6887 }
6888 
6889 int
6890 zonecfg_rm_aliased_rctl(zone_dochandle_t handle, char *name)
6891 {
6892         int i;
6893         uint64_t val;
6894         struct zone_rctltab rctltab;
6895 
6896         /*
6897          * First check that we have a valid aliased rctl to remove.
6898          * This will catch an rctl entry with non-standard values or
6899          * multiple rctl values for this name.  We need to ignore those
6900          * rctl entries.
6901          */
6902         if (zonecfg_get_aliased_rctl(handle, name, &val) != Z_OK)
6903                 return (Z_OK);
6904 
6905         for (i = 0; aliases[i].shortname != NULL; i++)
6906                 if (strcmp(name, aliases[i].shortname) == 0)
6907                         break;
6908 
6909         if (aliases[i].shortname == NULL)
6910                 return (Z_NO_RESOURCE_ID);
6911 
6912         (void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname,
6913             sizeof (rctltab.zone_rctl_name));
6914 
6915         return (zonecfg_delete_rctl(handle, &rctltab));
6916 }
6917 
6918 boolean_t
6919 zonecfg_aliased_rctl_ok(zone_dochandle_t handle, char *name)
6920 {
6921         uint64_t tmp_val;
6922 
6923         switch (zonecfg_get_aliased_rctl(handle, name, &tmp_val)) {
6924         case Z_OK:
6925                 /*FALLTHRU*/
6926         case Z_NO_ENTRY:
6927                 return (B_TRUE);
6928         default:
6929                 return (B_FALSE);
6930         }
6931 }
6932 
6933 int
6934 zonecfg_set_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t val)
6935 {
6936         int i;
6937         int err;
6938         struct zone_rctltab rctltab;
6939         struct zone_rctlvaltab *rctlvaltab;
6940         char buf[128];
6941 
6942         if (!zonecfg_aliased_rctl_ok(handle, name))
6943                 return (Z_ALIAS_DISALLOW);
6944 
6945         for (i = 0; aliases[i].shortname != NULL; i++)
6946                 if (strcmp(name, aliases[i].shortname) == 0)
6947                         break;
6948 
6949         if (aliases[i].shortname == NULL)
6950                 return (Z_NO_RESOURCE_ID);
6951 
6952         /* remove any pre-existing definition for this rctl */
6953         (void) zonecfg_rm_aliased_rctl(handle, name);
6954 
6955         (void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname,
6956             sizeof (rctltab.zone_rctl_name));
6957 
6958         rctltab.zone_rctl_valptr = NULL;
6959 
6960         if ((rctlvaltab = calloc(1, sizeof (struct zone_rctlvaltab))) == NULL)
6961                 return (Z_NOMEM);
6962 
6963         (void) snprintf(buf, sizeof (buf), "%llu", (long long)val);
6964 
6965         (void) strlcpy(rctlvaltab->zone_rctlval_priv, aliases[i].priv,
6966             sizeof (rctlvaltab->zone_rctlval_priv));
6967         (void) strlcpy(rctlvaltab->zone_rctlval_limit, buf,
6968             sizeof (rctlvaltab->zone_rctlval_limit));
6969         (void) strlcpy(rctlvaltab->zone_rctlval_action, aliases[i].action,
6970             sizeof (rctlvaltab->zone_rctlval_action));
6971 
6972         rctlvaltab->zone_rctlval_next = NULL;
6973 
6974         if ((err = zonecfg_add_rctl_value(&rctltab, rctlvaltab)) != Z_OK)
6975                 return (err);
6976 
6977         return (zonecfg_add_rctl(handle, &rctltab));
6978 }
6979 
6980 static int
6981 delete_tmp_pool(zone_dochandle_t handle)
6982 {
6983         int err;
6984         xmlNodePtr cur = handle->zone_dh_cur;
6985 
6986         if ((err = operation_prep(handle)) != Z_OK)
6987                 return (err);
6988 
6989         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6990                 if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) {
6991                         xmlUnlinkNode(cur);
6992                         xmlFreeNode(cur);
6993                         return (Z_OK);
6994                 }
6995         }
6996 
6997         return (Z_NO_RESOURCE_ID);
6998 }
6999 
7000 static int
7001 modify_tmp_pool(zone_dochandle_t handle, char *pool_importance)
7002 {
7003         int err;
7004         xmlNodePtr cur = handle->zone_dh_cur;
7005         xmlNodePtr newnode;
7006 
7007         err = delete_tmp_pool(handle);
7008         if (err != Z_OK && err != Z_NO_RESOURCE_ID)
7009                 return (err);
7010 
7011         if (*pool_importance != '\0') {
7012                 if ((err = operation_prep(handle)) != Z_OK)
7013                         return (err);
7014 
7015                 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_TMPPOOL, NULL);
7016                 if ((err = newprop(newnode, DTD_ATTR_IMPORTANCE,
7017                     pool_importance)) != Z_OK)
7018                         return (err);
7019         }
7020 
7021         return (Z_OK);
7022 }
7023 
7024 static int
7025 add_pset_core(zone_dochandle_t handle, struct zone_psettab *tabptr)
7026 {
7027         xmlNodePtr newnode, cur = handle->zone_dh_cur;
7028         int err;
7029 
7030         newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PSET, NULL);
7031         if ((err = newprop(newnode, DTD_ATTR_NCPU_MIN,
7032             tabptr->zone_ncpu_min)) != Z_OK)
7033                 return (err);
7034         if ((err = newprop(newnode, DTD_ATTR_NCPU_MAX,
7035             tabptr->zone_ncpu_max)) != Z_OK)
7036                 return (err);
7037 
7038         if ((err = modify_tmp_pool(handle, tabptr->zone_importance)) != Z_OK)
7039                 return (err);
7040 
7041         return (Z_OK);
7042 }
7043 
7044 int
7045 zonecfg_add_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
7046 {
7047         int err;
7048 
7049         if (tabptr == NULL)
7050                 return (Z_INVAL);
7051 
7052         if ((err = operation_prep(handle)) != Z_OK)
7053                 return (err);
7054 
7055         if ((err = add_pset_core(handle, tabptr)) != Z_OK)
7056                 return (err);
7057 
7058         return (Z_OK);
7059 }
7060 
7061 int
7062 zonecfg_delete_pset(zone_dochandle_t handle)
7063 {
7064         int err;
7065         int res = Z_NO_RESOURCE_ID;
7066         xmlNodePtr cur = handle->zone_dh_cur;
7067 
7068         if ((err = operation_prep(handle)) != Z_OK)
7069                 return (err);
7070 
7071         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
7072                 if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) {
7073                         xmlUnlinkNode(cur);
7074                         xmlFreeNode(cur);
7075                         res = Z_OK;
7076                         break;
7077                 }
7078         }
7079 
7080         /*
7081          * Once we have msets, we should check that a mset
7082          * do not exist before we delete the tmp_pool data.
7083          */
7084         err = delete_tmp_pool(handle);
7085         if (err != Z_OK && err != Z_NO_RESOURCE_ID)
7086                 return (err);
7087 
7088         return (res);
7089 }
7090 
7091 int
7092 zonecfg_modify_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
7093 {
7094         int err;
7095 
7096         if (tabptr == NULL)
7097                 return (Z_INVAL);
7098 
7099         if ((err = zonecfg_delete_pset(handle)) != Z_OK)
7100                 return (err);
7101 
7102         if ((err = add_pset_core(handle, tabptr)) != Z_OK)
7103                 return (err);
7104 
7105         return (Z_OK);
7106 }
7107 
7108 int
7109 zonecfg_lookup_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
7110 {
7111         xmlNodePtr cur;
7112         int err;
7113         int res = Z_NO_ENTRY;
7114 
7115         if (tabptr == NULL)
7116                 return (Z_INVAL);
7117 
7118         if ((err = operation_prep(handle)) != Z_OK)
7119                 return (err);
7120 
7121         /* this is an optional component */
7122         tabptr->zone_importance[0] = '\0';
7123 
7124         cur = handle->zone_dh_cur;
7125         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
7126                 if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) {
7127                         if ((err = fetchprop(cur, DTD_ATTR_NCPU_MIN,
7128                             tabptr->zone_ncpu_min,
7129                             sizeof (tabptr->zone_ncpu_min))) != Z_OK) {
7130                                 handle->zone_dh_cur = handle->zone_dh_top;
7131                                 return (err);
7132                         }
7133 
7134                         if ((err = fetchprop(cur, DTD_ATTR_NCPU_MAX,
7135                             tabptr->zone_ncpu_max,
7136                             sizeof (tabptr->zone_ncpu_max))) != Z_OK) {
7137                                 handle->zone_dh_cur = handle->zone_dh_top;
7138                                 return (err);
7139                         }
7140 
7141                         res = Z_OK;
7142 
7143                 } else if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) {
7144                         if ((err = fetchprop(cur, DTD_ATTR_IMPORTANCE,
7145                             tabptr->zone_importance,
7146                             sizeof (tabptr->zone_importance))) != Z_OK) {
7147                                 handle->zone_dh_cur = handle->zone_dh_top;
7148                                 return (err);
7149                         }
7150                 }
7151         }
7152 
7153         return (res);
7154 }
7155 
7156 int
7157 zonecfg_getpsetent(zone_dochandle_t handle, struct zone_psettab *tabptr)
7158 {
7159         int err;
7160 
7161         if ((err = zonecfg_setent(handle)) != Z_OK)
7162                 return (err);
7163 
7164         err = zonecfg_lookup_pset(handle, tabptr);
7165 
7166         (void) zonecfg_endent(handle);
7167 
7168         return (err);
7169 }
7170 
7171 static int
7172 add_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
7173 {
7174         xmlNodePtr newnode, cur = handle->zone_dh_cur;
7175         int err;
7176 
7177         newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_MCAP, NULL);
7178         if ((err = newprop(newnode, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap))
7179             != Z_OK)
7180                 return (err);
7181 
7182         return (Z_OK);
7183 }
7184 
7185 int
7186 zonecfg_delete_mcap(zone_dochandle_t handle)
7187 {
7188         int err;
7189         xmlNodePtr cur = handle->zone_dh_cur;
7190 
7191         if ((err = operation_prep(handle)) != Z_OK)
7192                 return (err);
7193 
7194         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
7195                 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
7196                         continue;
7197 
7198                 xmlUnlinkNode(cur);
7199                 xmlFreeNode(cur);
7200                 return (Z_OK);
7201         }
7202         return (Z_NO_RESOURCE_ID);
7203 }
7204 
7205 int
7206 zonecfg_modify_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
7207 {
7208         int err;
7209 
7210         if (tabptr == NULL)
7211                 return (Z_INVAL);
7212 
7213         err = zonecfg_delete_mcap(handle);
7214         /* it is ok if there is no mcap entry */
7215         if (err != Z_OK && err != Z_NO_RESOURCE_ID)
7216                 return (err);
7217 
7218         if ((err = add_mcap(handle, tabptr)) != Z_OK)
7219                 return (err);
7220 
7221         return (Z_OK);
7222 }
7223 
7224 int
7225 zonecfg_lookup_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
7226 {
7227         xmlNodePtr cur;
7228         int err;
7229 
7230         if (tabptr == NULL)
7231                 return (Z_INVAL);
7232 
7233         if ((err = operation_prep(handle)) != Z_OK)
7234                 return (err);
7235 
7236         cur = handle->zone_dh_cur;
7237         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
7238                 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
7239                         continue;
7240                 if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP,
7241                     tabptr->zone_physmem_cap,
7242                     sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
7243                         handle->zone_dh_cur = handle->zone_dh_top;
7244                         return (err);
7245                 }
7246 
7247                 return (Z_OK);
7248         }
7249 
7250         return (Z_NO_ENTRY);
7251 }
7252 
7253 int
7254 zonecfg_getsecflagsent(zone_dochandle_t handle,
7255     struct zone_secflagstab *tabptr)
7256 {
7257         int err;
7258         xmlNodePtr cur;
7259 
7260         if (handle == NULL)
7261                 return (Z_INVAL);
7262 
7263         if ((err = zonecfg_setent(handle)) != Z_OK)
7264                 return (err);
7265 
7266 
7267         if ((cur = handle->zone_dh_cur) == NULL)
7268                 return (Z_NO_ENTRY);
7269 
7270         for (; cur != NULL; cur = cur->next) {
7271                 if (xmlStrcmp(cur->name, DTD_ELEM_SECFLAGS) == 0)
7272                         break;
7273         }
7274 
7275         if (cur == NULL) {
7276                 handle->zone_dh_cur = handle->zone_dh_top;
7277                 return (Z_NO_ENTRY);
7278         }
7279 
7280         if ((err = fetchprop(cur, DTD_ATTR_DEFAULT,
7281             tabptr->zone_secflags_default,
7282             sizeof (tabptr->zone_secflags_default))) != Z_OK) {
7283                 handle->zone_dh_cur = handle->zone_dh_top;
7284                 return (err);
7285         }
7286 
7287         if ((err = fetchprop(cur, DTD_ATTR_LOWER,
7288             tabptr->zone_secflags_lower,
7289             sizeof (tabptr->zone_secflags_lower))) != Z_OK) {
7290                 handle->zone_dh_cur = handle->zone_dh_top;
7291                 return (err);
7292         }
7293 
7294         if ((err = fetchprop(cur, DTD_ATTR_UPPER,
7295             tabptr->zone_secflags_upper,
7296             sizeof (tabptr->zone_secflags_upper))) != Z_OK) {
7297                 handle->zone_dh_cur = handle->zone_dh_top;
7298                 return (err);
7299         }
7300 
7301         handle->zone_dh_cur = cur->next;
7302 
7303         (void) zonecfg_endent(handle);
7304 
7305         return (err);
7306 }
7307 
7308 static int
7309 getmcapent_core(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
7310 {
7311         xmlNodePtr cur;
7312         int err;
7313 
7314         if (handle == NULL)
7315                 return (Z_INVAL);
7316 
7317         if ((cur = handle->zone_dh_cur) == NULL)
7318                 return (Z_NO_ENTRY);
7319 
7320         for (; cur != NULL; cur = cur->next)
7321                 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) == 0)
7322                         break;
7323         if (cur == NULL) {
7324                 handle->zone_dh_cur = handle->zone_dh_top;
7325                 return (Z_NO_ENTRY);
7326         }
7327 
7328         if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap,
7329             sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
7330                 handle->zone_dh_cur = handle->zone_dh_top;
7331                 return (err);
7332         }
7333 
7334         handle->zone_dh_cur = cur->next;
7335         return (Z_OK);
7336 }
7337 
7338 int
7339 zonecfg_getmcapent(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
7340 {
7341         int err;
7342 
7343         if ((err = zonecfg_setent(handle)) != Z_OK)
7344                 return (err);
7345 
7346         err = getmcapent_core(handle, tabptr);
7347 
7348         (void) zonecfg_endent(handle);
7349 
7350         return (err);
7351 }
7352 
7353 /*
7354  * Get the full tree of pkg metadata in a set of nested AVL trees.
7355  * pkgs_avl is an AVL tree of pkgs.
7356  *
7357  * The zone xml data contains DTD_ELEM_PACKAGE elements.
7358  */
7359 int
7360 zonecfg_getpkgdata(zone_dochandle_t handle, uu_avl_pool_t *pkg_pool,
7361     uu_avl_t *pkgs_avl)
7362 {
7363         xmlNodePtr cur;
7364         int res;
7365         zone_pkg_entry_t *pkg;
7366         char name[MAXNAMELEN];
7367         char version[ZONE_PKG_VERSMAX];
7368 
7369         if (handle == NULL)
7370                 return (Z_INVAL);
7371 
7372         if ((res = zonecfg_setent(handle)) != Z_OK)
7373                 return (res);
7374 
7375         if ((cur = handle->zone_dh_cur) == NULL) {
7376                 res = Z_NO_ENTRY;
7377                 goto done;
7378         }
7379 
7380         for (; cur != NULL; cur = cur->next) {
7381                 if (xmlStrcmp(cur->name, DTD_ELEM_PACKAGE) == 0) {
7382                         uu_avl_index_t where;
7383 
7384                         if ((res = fetchprop(cur, DTD_ATTR_NAME, name,
7385                             sizeof (name))) != Z_OK)
7386                                 goto done;
7387 
7388                         if ((res = fetchprop(cur, DTD_ATTR_VERSION, version,
7389                             sizeof (version))) != Z_OK)
7390                                 goto done;
7391 
7392                         if ((pkg = (zone_pkg_entry_t *)
7393                             malloc(sizeof (zone_pkg_entry_t))) == NULL) {
7394                                 res = Z_NOMEM;
7395                                 goto done;
7396                         }
7397 
7398                         if ((pkg->zpe_name = strdup(name)) == NULL) {
7399                                 free(pkg);
7400                                 res = Z_NOMEM;
7401                                 goto done;
7402                         }
7403 
7404                         if ((pkg->zpe_vers = strdup(version)) == NULL) {
7405                                 free(pkg->zpe_name);
7406                                 free(pkg);
7407                                 res = Z_NOMEM;
7408                                 goto done;
7409                         }
7410 
7411                         uu_avl_node_init(pkg, &pkg->zpe_entry, pkg_pool);
7412                         if (uu_avl_find(pkgs_avl, pkg, NULL, &where) != NULL) {
7413                                 free(pkg->zpe_name);
7414                                 free(pkg->zpe_vers);
7415                                 free(pkg);
7416                         } else {
7417                                 uu_avl_insert(pkgs_avl, pkg, where);
7418                         }
7419                 }
7420         }
7421 
7422 done:
7423         (void) zonecfg_endent(handle);
7424         return (res);
7425 }
7426 
7427 int
7428 zonecfg_setdevperment(zone_dochandle_t handle)
7429 {
7430         return (zonecfg_setent(handle));
7431 }
7432 
7433 int
7434 zonecfg_getdevperment(zone_dochandle_t handle, struct zone_devpermtab *tabptr)
7435 {
7436         xmlNodePtr cur;
7437         int err;
7438         char buf[128];
7439 
7440         tabptr->zone_devperm_acl = NULL;
7441 
7442         if (handle == NULL)
7443                 return (Z_INVAL);
7444 
7445         if ((cur = handle->zone_dh_cur) == NULL)
7446                 return (Z_NO_ENTRY);
7447 
7448         for (; cur != NULL; cur = cur->next)
7449                 if (!xmlStrcmp(cur->name, DTD_ELEM_DEV_PERM))
7450                         break;
7451         if (cur == NULL) {
7452                 handle->zone_dh_cur = handle->zone_dh_top;
7453                 return (Z_NO_ENTRY);
7454         }
7455 
7456         if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_devperm_name,
7457             sizeof (tabptr->zone_devperm_name))) != Z_OK) {
7458                 handle->zone_dh_cur = handle->zone_dh_top;
7459                 return (err);
7460         }
7461 
7462         if ((err = fetchprop(cur, DTD_ATTR_UID, buf, sizeof (buf))) != Z_OK) {
7463                 handle->zone_dh_cur = handle->zone_dh_top;
7464                 return (err);
7465         }
7466         tabptr->zone_devperm_uid = (uid_t)atol(buf);
7467 
7468         if ((err = fetchprop(cur, DTD_ATTR_GID, buf, sizeof (buf))) != Z_OK) {
7469                 handle->zone_dh_cur = handle->zone_dh_top;
7470                 return (err);
7471         }
7472         tabptr->zone_devperm_gid = (gid_t)atol(buf);
7473 
7474         if ((err = fetchprop(cur, DTD_ATTR_MODE, buf, sizeof (buf))) != Z_OK) {
7475                 handle->zone_dh_cur = handle->zone_dh_top;
7476                 return (err);
7477         }
7478         tabptr->zone_devperm_mode = (mode_t)strtol(buf, (char **)NULL, 8);
7479 
7480         if ((err = fetch_alloc_prop(cur, DTD_ATTR_ACL,
7481             &(tabptr->zone_devperm_acl))) != Z_OK) {
7482                 handle->zone_dh_cur = handle->zone_dh_top;
7483                 return (err);
7484         }
7485 
7486         handle->zone_dh_cur = cur->next;
7487         return (Z_OK);
7488 }
7489 
7490 int
7491 zonecfg_enddevperment(zone_dochandle_t handle)
7492 {
7493         return (zonecfg_endent(handle));
7494 }
7495 
7496 /* PRINTFLIKE1 */
7497 static void
7498 zerror(const char *zone_name, const char *fmt, ...)
7499 {
7500         va_list alist;
7501 
7502         va_start(alist, fmt);
7503         (void) fprintf(stderr, "zone '%s': ", zone_name);
7504         (void) vfprintf(stderr, fmt, alist);
7505         (void) fprintf(stderr, "\n");
7506         va_end(alist);
7507 }
7508 
7509 static void
7510 zperror(const char *str)
7511 {
7512         (void) fprintf(stderr, "%s: %s\n", str, strerror(errno));
7513 }
7514 
7515 /*
7516  * The following three routines implement a simple locking mechanism to
7517  * ensure that only one instance of zoneadm at a time is able to manipulate
7518  * a given zone.  The lock is built on top of an fcntl(2) lock of
7519  * [<altroot>]/var/run/zones/<zonename>.zoneadm.lock.  If a zoneadm instance
7520  * can grab that lock, it is allowed to manipulate the zone.
7521  *
7522  * Since zoneadm may call external applications which in turn invoke
7523  * zoneadm again, we introduce the notion of "lock inheritance".  Any
7524  * instance of zoneadm that has another instance in its ancestry is assumed
7525  * to be acting on behalf of the original zoneadm, and is thus allowed to
7526  * manipulate its zone.
7527  *
7528  * This inheritance is implemented via the _ZONEADM_LOCK_HELD environment
7529  * variable.  When zoneadm is granted a lock on its zone, this environment
7530  * variable is set to 1.  When it releases the lock, the variable is set to
7531  * 0.  Since a child process inherits its parent's environment, checking
7532  * the state of this variable indicates whether or not any ancestor owns
7533  * the lock.
7534  */
7535 void
7536 zonecfg_init_lock_file(const char *zone_name, char **lock_env)
7537 {
7538         *lock_env = getenv(LOCK_ENV_VAR);
7539         if (*lock_env == NULL) {
7540                 if (putenv(zoneadm_lock_not_held) != 0) {
7541                         zerror(zone_name, gettext("could not set env: %s"),
7542                             strerror(errno));
7543                         exit(1);
7544                 }
7545         } else {
7546                 if (atoi(*lock_env) == 1)
7547                         zone_lock_cnt = 1;
7548         }
7549 }
7550 
7551 void
7552 zonecfg_release_lock_file(const char *zone_name, int lockfd)
7553 {
7554         /*
7555          * If we are cleaning up from a failed attempt to lock the zone for
7556          * the first time, we might have a zone_lock_cnt of 0.  In that
7557          * error case, we don't want to do anything but close the lock
7558          * file.
7559          */
7560         assert(zone_lock_cnt >= 0);
7561         if (zone_lock_cnt > 0) {
7562                 assert(getenv(LOCK_ENV_VAR) != NULL);
7563                 assert(atoi(getenv(LOCK_ENV_VAR)) == 1);
7564                 if (--zone_lock_cnt > 0) {
7565                         assert(lockfd == -1);
7566                         return;
7567                 }
7568                 if (putenv(zoneadm_lock_not_held) != 0) {
7569                         zerror(zone_name, gettext("could not set env: %s"),
7570                             strerror(errno));
7571                         exit(1);
7572                 }
7573         }
7574         assert(lockfd >= 0);
7575         (void) close(lockfd);
7576 }
7577 
7578 int
7579 zonecfg_grab_lock_file(const char *zone_name, int *lockfd)
7580 {
7581         char pathbuf[PATH_MAX];
7582         struct flock flock;
7583 
7584         /*
7585          * If we already have the lock, we can skip this expensive song
7586          * and dance.
7587          */
7588         assert(zone_lock_cnt >= 0);
7589         assert(getenv(LOCK_ENV_VAR) != NULL);
7590         if (zone_lock_cnt > 0) {
7591                 assert(atoi(getenv(LOCK_ENV_VAR)) == 1);
7592                 zone_lock_cnt++;
7593                 *lockfd = -1;
7594                 return (Z_OK);
7595         }
7596         assert(getenv(LOCK_ENV_VAR) != NULL);
7597         assert(atoi(getenv(LOCK_ENV_VAR)) == 0);
7598 
7599         if (snprintf(pathbuf, sizeof (pathbuf), "%s%s", zonecfg_get_root(),
7600             ZONES_TMPDIR) >= sizeof (pathbuf)) {
7601                 zerror(zone_name, gettext("alternate root path is too long"));
7602                 return (-1);
7603         }
7604         if (mkdir(pathbuf, S_IRWXU) < 0 && errno != EEXIST) {
7605                 zerror(zone_name, gettext("could not mkdir %s: %s"), pathbuf,
7606                     strerror(errno));
7607                 return (-1);
7608         }
7609         (void) chmod(pathbuf, S_IRWXU);
7610 
7611         /*
7612          * One of these lock files is created for each zone (when needed).
7613          * The lock files are not cleaned up (except on system reboot),
7614          * but since there is only one per zone, there is no resource
7615          * starvation issue.
7616          */
7617         if (snprintf(pathbuf, sizeof (pathbuf), "%s%s/%s.zoneadm.lock",
7618             zonecfg_get_root(), ZONES_TMPDIR, zone_name) >= sizeof (pathbuf)) {
7619                 zerror(zone_name, gettext("alternate root path is too long"));
7620                 return (-1);
7621         }
7622         if ((*lockfd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
7623                 zerror(zone_name, gettext("could not open %s: %s"), pathbuf,
7624                     strerror(errno));
7625                 return (-1);
7626         }
7627         /*
7628          * Lock the file to synchronize with other zoneadmds
7629          */
7630         flock.l_type = F_WRLCK;
7631         flock.l_whence = SEEK_SET;
7632         flock.l_start = (off_t)0;
7633         flock.l_len = (off_t)0;
7634         if ((fcntl(*lockfd, F_SETLKW, &flock) < 0) ||
7635             (putenv(zoneadm_lock_held) != 0)) {
7636                 zerror(zone_name, gettext("unable to lock %s: %s"), pathbuf,
7637                     strerror(errno));
7638                 zonecfg_release_lock_file(zone_name, *lockfd);
7639                 return (-1);
7640         }
7641         zone_lock_cnt = 1;
7642         return (Z_OK);
7643 }
7644 
7645 boolean_t
7646 zonecfg_lock_file_held(int *lockfd)
7647 {
7648         if (*lockfd >= 0 || zone_lock_cnt > 0)
7649                 return (B_TRUE);
7650         return (B_FALSE);
7651 }
7652 
7653 static boolean_t
7654 get_doorname(const char *zone_name, char *buffer)
7655 {
7656         return (snprintf(buffer, PATH_MAX, "%s" ZONE_DOOR_PATH,
7657             zonecfg_get_root(), zone_name) < PATH_MAX);
7658 }
7659 
7660 /*
7661  * system daemons are not audited.  For the global zone, this occurs
7662  * "naturally" since init is started with the default audit
7663  * characteristics.  Since zoneadmd is a system daemon and it starts
7664  * init for a zone, it is necessary to clear out the audit
7665  * characteristics inherited from whomever started zoneadmd.  This is
7666  * indicated by the audit id, which is set from the ruid parameter of
7667  * adt_set_user(), below.
7668  */
7669 
7670 static void
7671 prepare_audit_context(const char *zone_name)
7672 {
7673         adt_session_data_t      *ah;
7674         char                    *failure = gettext("audit failure: %s");
7675 
7676         if (adt_start_session(&ah, NULL, 0)) {
7677                 zerror(zone_name, failure, strerror(errno));
7678                 return;
7679         }
7680         if (adt_set_user(ah, ADT_NO_AUDIT, ADT_NO_AUDIT,
7681             ADT_NO_AUDIT, ADT_NO_AUDIT, NULL, ADT_NEW)) {
7682                 zerror(zone_name, failure, strerror(errno));
7683                 (void) adt_end_session(ah);
7684                 return;
7685         }
7686         if (adt_set_proc(ah))
7687                 zerror(zone_name, failure, strerror(errno));
7688 
7689         (void) adt_end_session(ah);
7690 }
7691 
7692 static int
7693 start_zoneadmd(const char *zone_name, boolean_t lock)
7694 {
7695         char doorpath[PATH_MAX];
7696         pid_t child_pid;
7697         int error = -1;
7698         int doorfd, lockfd;
7699         struct door_info info;
7700 
7701         if (!get_doorname(zone_name, doorpath))
7702                 return (-1);
7703 
7704         if (lock)
7705                 if (zonecfg_grab_lock_file(zone_name, &lockfd) != Z_OK)
7706                         return (-1);
7707 
7708         /*
7709          * Now that we have the lock, re-confirm that the daemon is
7710          * *not* up and working fine.  If it is still down, we have a green
7711          * light to start it.
7712          */
7713         if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
7714                 if (errno != ENOENT) {
7715                         zperror(doorpath);
7716                         goto out;
7717                 }
7718         } else {
7719                 if (door_info(doorfd, &info) == 0 &&
7720                     ((info.di_attributes & DOOR_REVOKED) == 0)) {
7721                         error = Z_OK;
7722                         (void) close(doorfd);
7723                         goto out;
7724                 }
7725                 (void) close(doorfd);
7726         }
7727 
7728         if ((child_pid = fork()) == -1) {
7729                 zperror(gettext("could not fork"));
7730                 goto out;
7731         }
7732 
7733         if (child_pid == 0) {
7734                 const char *argv[6], **ap;
7735 
7736                 /* child process */
7737                 prepare_audit_context(zone_name);
7738 
7739                 ap = argv;
7740                 *ap++ = "zoneadmd";
7741                 *ap++ = "-z";
7742                 *ap++ = zone_name;
7743                 if (zonecfg_in_alt_root()) {
7744                         *ap++ = "-R";
7745                         *ap++ = zonecfg_get_root();
7746                 }
7747                 *ap = NULL;
7748 
7749                 (void) execv("/usr/lib/zones/zoneadmd", (char * const *)argv);
7750                 /*
7751                  * TRANSLATION_NOTE
7752                  * zoneadmd is a literal that should not be translated.
7753                  */
7754                 zperror(gettext("could not exec zoneadmd"));
7755                 _exit(1);
7756         } else {
7757                 /* parent process */
7758                 pid_t retval;
7759                 int pstatus = 0;
7760 
7761                 do {
7762                         retval = waitpid(child_pid, &pstatus, 0);
7763                 } while (retval != child_pid);
7764                 if (WIFSIGNALED(pstatus) || (WIFEXITED(pstatus) &&
7765                     WEXITSTATUS(pstatus) != 0)) {
7766                         zerror(zone_name, gettext("could not start %s"),
7767                             "zoneadmd");
7768                         goto out;
7769                 }
7770         }
7771         error = Z_OK;
7772 out:
7773         if (lock)
7774                 zonecfg_release_lock_file(zone_name, lockfd);
7775         return (error);
7776 }
7777 
7778 int
7779 zonecfg_ping_zoneadmd(const char *zone_name)
7780 {
7781         char doorpath[PATH_MAX];
7782         int doorfd;
7783         struct door_info info;
7784 
7785         if (!get_doorname(zone_name, doorpath))
7786                 return (-1);
7787 
7788         if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
7789                 return (-1);
7790         }
7791         if (door_info(doorfd, &info) == 0 &&
7792             ((info.di_attributes & DOOR_REVOKED) == 0)) {
7793                 (void) close(doorfd);
7794                 return (Z_OK);
7795         }
7796         (void) close(doorfd);
7797         return (-1);
7798 }
7799 
7800 int
7801 zonecfg_call_zoneadmd(const char *zone_name, zone_cmd_arg_t *arg, char *locale,
7802     boolean_t lock)
7803 {
7804         char doorpath[PATH_MAX];
7805         int doorfd, result;
7806         door_arg_t darg;
7807 
7808         zoneid_t zoneid;
7809         uint64_t uniqid = 0;
7810 
7811         zone_cmd_rval_t *rvalp;
7812         size_t rlen;
7813         char *cp, *errbuf;
7814 
7815         rlen = getpagesize();
7816         if ((rvalp = malloc(rlen)) == NULL) {
7817                 zerror(zone_name, gettext("failed to allocate %lu bytes: %s"),
7818                     rlen, strerror(errno));
7819                 return (-1);
7820         }
7821 
7822         if ((zoneid = getzoneidbyname(zone_name)) != ZONE_ID_UNDEFINED) {
7823                 (void) zone_getattr(zoneid, ZONE_ATTR_UNIQID, &uniqid,
7824                     sizeof (uniqid));
7825         }
7826         arg->uniqid = uniqid;
7827         (void) strlcpy(arg->locale, locale, sizeof (arg->locale));
7828         if (!get_doorname(zone_name, doorpath)) {
7829                 zerror(zone_name, gettext("alternate root path is too long"));
7830                 free(rvalp);
7831                 return (-1);
7832         }
7833 
7834         /*
7835          * Loop trying to start zoneadmd; if something goes seriously
7836          * wrong we break out and fail.
7837          */
7838         for (;;) {
7839                 if (start_zoneadmd(zone_name, lock) != Z_OK)
7840                         break;
7841 
7842                 if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
7843                         zperror(gettext("failed to open zone door"));
7844                         break;
7845                 }
7846 
7847                 darg.data_ptr = (char *)arg;
7848                 darg.data_size = sizeof (*arg);
7849                 darg.desc_ptr = NULL;
7850                 darg.desc_num = 0;
7851                 darg.rbuf = (char *)rvalp;
7852                 darg.rsize = rlen;
7853                 if (door_call(doorfd, &darg) != 0) {
7854                         (void) close(doorfd);
7855                         /*
7856                          * We'll get EBADF if the door has been revoked.
7857                          */
7858                         if (errno != EBADF) {
7859                                 zperror(gettext("door_call failed"));
7860                                 break;
7861                         }
7862                         continue;       /* take another lap */
7863                 }
7864                 (void) close(doorfd);
7865 
7866                 if (darg.data_size == 0) {
7867                         /* Door server is going away; kick it again. */
7868                         continue;
7869                 }
7870 
7871                 errbuf = rvalp->errbuf;
7872                 while (*errbuf != '\0') {
7873                         /*
7874                          * Remove any newlines since zerror()
7875                          * will append one automatically.
7876                          */
7877                         cp = strchr(errbuf, '\n');
7878                         if (cp != NULL)
7879                                 *cp = '\0';
7880                         zerror(zone_name, "%s", errbuf);
7881                         if (cp == NULL)
7882                                 break;
7883                         errbuf = cp + 1;
7884                 }
7885                 result = rvalp->rval == 0 ? 0 : -1;
7886                 free(rvalp);
7887                 return (result);
7888         }
7889 
7890         free(rvalp);
7891         return (-1);
7892 }
7893 
7894 boolean_t
7895 zonecfg_valid_auths(const char *auths, const char *zonename)
7896 {
7897         char *right;
7898         char *tmpauths;
7899         char *lasts;
7900         char authname[MAXAUTHS];
7901         boolean_t status = B_TRUE;
7902 
7903         tmpauths = strdup(auths);
7904         if (tmpauths == NULL) {
7905                 zerror(zonename, gettext("Out of memory"));
7906                 return (B_FALSE);
7907         }
7908         right = strtok_r(tmpauths, ",", &lasts);
7909         while (right != NULL) {
7910                 (void) snprintf(authname, MAXAUTHS, "%s%s",
7911                     ZONE_AUTH_PREFIX, right);
7912                 if (getauthnam(authname) == NULL) {
7913                         status = B_FALSE;
7914                         zerror(zonename,
7915                             gettext("'%s' is not a valid authorization"),
7916                             right);
7917                 }
7918                 right = strtok_r(NULL, ",", &lasts);
7919         }
7920         free(tmpauths);
7921         return (status);
7922 }
7923 
7924 int
7925 zonecfg_delete_admins(zone_dochandle_t handle, char *zonename)
7926 {
7927         int err;
7928         struct zone_admintab admintab;
7929         boolean_t changed = B_FALSE;
7930 
7931         if ((err = zonecfg_setadminent(handle)) != Z_OK) {
7932                 return (err);
7933         }
7934         while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
7935                 err = zonecfg_delete_admin(handle, &admintab,
7936                     zonename);
7937                 if (err != Z_OK) {
7938                         (void) zonecfg_endadminent(handle);
7939                         return (err);
7940                 } else {
7941                         changed = B_TRUE;
7942                 }
7943                 if ((err = zonecfg_setadminent(handle)) != Z_OK) {
7944                         return (err);
7945                 }
7946         }
7947         (void) zonecfg_endadminent(handle);
7948         return (changed? Z_OK:Z_NO_ENTRY);
7949 }
7950 
7951 /*
7952  * Checks if a long authorization applies to this zone.
7953  * If so, it returns true, after destructively stripping
7954  * the authorization of its prefix and zone suffix.
7955  */
7956 static boolean_t
7957 is_zone_auth(char **auth, char *zonename, char *oldzonename)
7958 {
7959         char *suffix;
7960         size_t offset;
7961 
7962         offset = strlen(ZONE_AUTH_PREFIX);
7963         if ((strncmp(*auth, ZONE_AUTH_PREFIX, offset) == 0) &&
7964             ((suffix = strchr(*auth, '/')) != NULL)) {
7965                 if (strcmp(suffix + 1, zonename) == 0) {
7966                         *auth += offset;
7967                         suffix[0] = '\0';
7968                         return (B_TRUE);
7969                 } else if ((oldzonename != NULL) &&
7970                     (strcmp(suffix + 1, oldzonename) == 0)) {
7971                         *auth += offset;
7972                         suffix[0] = '\0';
7973                         return (B_TRUE);
7974                 }
7975         }
7976         return (B_FALSE);
7977 }
7978 
7979 /*
7980  * This function determines whether the zone-specific authorization
7981  * assignments in /etc/user_attr have been changed more recently
7982  * than the equivalent data stored in the zone's configuration file.
7983  * This should only happen if the zone-specific authorizations in
7984  * the user_attr file were modified using a tool other than zonecfg.
7985  * If the configuration file is out-of-date with respect to these
7986  * authorization assignments, it is updated to match those specified
7987  * in /etc/user_attr.
7988  */
7989 
7990 int
7991 zonecfg_update_userauths(zone_dochandle_t handle, char *zonename)
7992 {
7993         userattr_t *ua_ptr;
7994         char *authlist;
7995         char *lasts;
7996         FILE  *uaf;
7997         struct zone_admintab admintab;
7998         struct stat config_st, ua_st;
7999         char config_file[MAXPATHLEN];
8000         boolean_t changed = B_FALSE;
8001         int err;
8002 
8003         if ((uaf = fopen(USERATTR_FILENAME, "r")) == NULL) {
8004                 zerror(zonename, gettext("could not open file %s: %s"),
8005                     USERATTR_FILENAME, strerror(errno));
8006                 if (errno == EACCES)
8007                         return (Z_ACCES);
8008                 if (errno == ENOENT)
8009                         return (Z_NO_ZONE);
8010                 return (Z_MISC_FS);
8011         }
8012         if ((err = fstat(fileno(uaf), &ua_st)) != 0) {
8013                 zerror(zonename, gettext("could not stat file %s: %s"),
8014                     USERATTR_FILENAME, strerror(errno));
8015                 (void) fclose(uaf);
8016                 return (Z_MISC_FS);
8017         }
8018         if (!config_file_path(zonename, config_file)) {
8019                 (void) fclose(uaf);
8020                 return (Z_MISC_FS);
8021         }
8022 
8023         if ((err = stat(config_file, &config_st)) != 0) {
8024                 zerror(zonename, gettext("could not stat file %s: %s"),
8025                     config_file, strerror(errno));
8026                 (void) fclose(uaf);
8027                 return (Z_MISC_FS);
8028         }
8029         if (config_st.st_mtime >= ua_st.st_mtime) {
8030                 (void) fclose(uaf);
8031                 return (Z_NO_ENTRY);
8032         }
8033         if ((err = zonecfg_delete_admins(handle, zonename)) == Z_OK) {
8034                 changed = B_TRUE;
8035         } else if (err != Z_NO_ENTRY) {
8036                 (void) fclose(uaf);
8037                 return (err);
8038         }
8039         while ((ua_ptr = fgetuserattr(uaf)) != NULL) {
8040                 if (ua_ptr->name[0] == '#') {
8041                         continue;
8042                 }
8043                 authlist = kva_match(ua_ptr->attr, USERATTR_AUTHS_KW);
8044                 if (authlist != NULL) {
8045                         char *cur_auth;
8046                         boolean_t first;
8047 
8048                         first = B_TRUE;
8049                         bzero(&admintab.zone_admin_auths, MAXAUTHS);
8050                         cur_auth = strtok_r(authlist, ",", &lasts);
8051                         while (cur_auth != NULL) {
8052                                 if (is_zone_auth(&cur_auth, zonename,
8053                                     NULL)) {
8054                                         /*
8055                                          * Add auths for this zone
8056                                          */
8057                                         if (first) {
8058                                                 first = B_FALSE;
8059                                         } else {
8060                                                 (void) strlcat(
8061                                                     admintab.zone_admin_auths,
8062                                                     ",", MAXAUTHS);
8063                                         }
8064                                         (void) strlcat(
8065                                             admintab.zone_admin_auths,
8066                                             cur_auth, MAXAUTHS);
8067                                 }
8068                                 cur_auth = strtok_r(NULL, ",", &lasts);
8069                         }
8070                         if (!first) {
8071                                 /*
8072                                  * Add this right to config file
8073                                  */
8074                                 (void) strlcpy(admintab.zone_admin_user,
8075                                     ua_ptr->name,
8076                                     sizeof (admintab.zone_admin_user));
8077                                 err = zonecfg_add_admin(handle,
8078                                     &admintab, zonename);
8079                                 if (err != Z_OK) {
8080                                         (void) fclose(uaf);
8081                                         return (err);
8082                                 } else {
8083                                         changed = B_TRUE;
8084                                 }
8085                         }
8086                 }
8087         } /* end-of-while-loop */
8088         (void) fclose(uaf);
8089         return (changed? Z_OK: Z_NO_ENTRY);
8090 }
8091 
8092 static void
8093 update_profiles(char *rbac_profs, boolean_t add)
8094 {
8095         char new_profs[MAXPROFS];
8096         char *cur_prof;
8097         boolean_t first = B_TRUE;
8098         boolean_t found = B_FALSE;
8099         char *lasts;
8100 
8101         cur_prof = strtok_r(rbac_profs, ",", &lasts);
8102         while (cur_prof != NULL) {
8103                 if (strcmp(cur_prof, ZONE_MGMT_PROF) == 0) {
8104                         found = B_TRUE;
8105                         if (!add) {
8106                                 cur_prof = strtok_r(NULL, ",", &lasts);
8107                                 continue;
8108                         }
8109                 }
8110                 if (first) {
8111                         first = B_FALSE;
8112                 } else {
8113                         (void) strlcat(new_profs, ",",
8114                             MAXPROFS);
8115                 }
8116                 (void) strlcat(new_profs, cur_prof,
8117                     MAXPROFS);
8118                 cur_prof = strtok_r(NULL, ",", &lasts);
8119         }
8120         /*
8121          * Now prepend the Zone Management profile at the beginning
8122          * of the list if it is needed, and append the rest.
8123          * Return the updated list in the original buffer.
8124          */
8125         if (add && !found) {
8126                 first = B_FALSE;
8127                 (void) strlcpy(rbac_profs, ZONE_MGMT_PROF, MAXPROFS);
8128         } else {
8129                 first = B_TRUE;
8130                 rbac_profs[0] = '\0';
8131         }
8132         if (strlen(new_profs) > 0) {
8133                 if (!first)
8134                         (void) strlcat(rbac_profs, ",", MAXPROFS);
8135                 (void) strlcat(rbac_profs, new_profs, MAXPROFS);
8136         }
8137 }
8138 
8139 #define MAX_CMD_LEN     1024
8140 
8141 static int
8142 do_subproc(char *zonename, char *cmdbuf)
8143 {
8144         char inbuf[MAX_CMD_LEN];
8145         FILE *file;
8146         int status;
8147 
8148         file = popen(cmdbuf, "r");
8149         if (file == NULL) {
8150                 zerror(zonename, gettext("Could not launch: %s"), cmdbuf);
8151                 return (-1);
8152         }
8153 
8154         while (fgets(inbuf, sizeof (inbuf), file) != NULL)
8155                 (void) fprintf(stderr, "%s", inbuf);
8156         status = pclose(file);
8157 
8158         if (WIFSIGNALED(status)) {
8159                 zerror(zonename, gettext("%s unexpectedly terminated "
8160                     "due to signal %d"),
8161                     cmdbuf, WTERMSIG(status));
8162                 return (-1);
8163         }
8164         assert(WIFEXITED(status));
8165         return (WEXITSTATUS(status));
8166 }
8167 
8168 /*
8169  * This function updates the local /etc/user_attr file to
8170  * correspond to the admin settings that are currently being
8171  * committed. The updates are done via usermod and/or rolemod
8172  * depending on the type of the specified user. It is also
8173  * invoked to remove entries from user_attr corresponding to
8174  * removed admin assignments, using an empty auths string.
8175  *
8176  * Because the removed entries are no longer included in the
8177  * cofiguration that is being committed, a linked list of
8178  * removed admin entries is maintained to keep track of such
8179  * transactions. The head of the list is stored in the zone_dh_userauths
8180  * element of the handle strcture.
8181  */
8182 static int
8183 zonecfg_authorize_user_impl(zone_dochandle_t handle, char *user,
8184     char *auths, char *zonename)
8185 {
8186         char *right;
8187         char old_auths[MAXAUTHS];
8188         char new_auths[MAXAUTHS];
8189         char rbac_profs[MAXPROFS];
8190         char *lasts;
8191         userattr_t *u;
8192         boolean_t first = B_TRUE;
8193         boolean_t is_zone_admin = B_FALSE;
8194         char user_cmd[] = "/usr/sbin/usermod";
8195         char role_cmd[] = "/usr/sbin/rolemod";
8196         char *auths_cmd = user_cmd;     /* either usermod or rolemod */
8197         char *new_auth_start;           /* string containing the new auths */
8198         int new_auth_cnt = 0;           /* delta of changed authorizations */
8199 
8200         /*
8201          * First get the existing authorizations for this user
8202          */
8203 
8204         bzero(&old_auths, sizeof (old_auths));
8205         bzero(&new_auths, sizeof (new_auths));
8206         bzero(&rbac_profs, sizeof (rbac_profs));
8207         if ((u = getusernam(user)) != NULL) {
8208                 char *current_auths;
8209                 char *current_profs;
8210                 char *type;
8211 
8212                 type = kva_match(u->attr, USERATTR_TYPE_KW);
8213                 if (type != NULL) {
8214                         if (strcmp(type, USERATTR_TYPE_NONADMIN_KW) == 0)
8215                                 auths_cmd = role_cmd;
8216                 }
8217 
8218                 current_auths = kva_match(u->attr, USERATTR_AUTHS_KW);
8219                 if (current_auths != NULL) {
8220                         char *cur_auth;
8221                         char *delete_name;
8222                         size_t offset;
8223 
8224                         offset = strlen(ZONE_AUTH_PREFIX);
8225 
8226                         (void) strlcpy(old_auths, current_auths, MAXAUTHS);
8227                         cur_auth = strtok_r(current_auths, ",", &lasts);
8228 
8229                         /*
8230                          * Next, remove any existing authorizations
8231                          * for this zone, and determine if the
8232                          * user still needs the Zone Management Profile.
8233                          */
8234                         if (is_renaming(handle))
8235                                 delete_name = handle->zone_dh_delete_name;
8236                         else
8237                                 delete_name = NULL;
8238                         while (cur_auth != NULL) {
8239                                 if (!is_zone_auth(&cur_auth, zonename,
8240                                     delete_name)) {
8241                                         if (first) {
8242                                                 first = B_FALSE;
8243                                         } else {
8244                                                 (void) strlcat(new_auths, ",",
8245                                                     MAXAUTHS);
8246                                         }
8247                                         (void) strlcat(new_auths, cur_auth,
8248                                             MAXAUTHS);
8249                                         /*
8250                                          * If the user has authorizations
8251                                          * for other zones, then set a
8252                                          * flag indicate that the Zone
8253                                          * Management profile should be
8254                                          * preserved in user_attr.
8255                                          */
8256                                         if (strncmp(cur_auth,
8257                                             ZONE_AUTH_PREFIX, offset) == 0)
8258                                                 is_zone_admin = B_TRUE;
8259                                 } else {
8260                                         new_auth_cnt++;
8261                                 }
8262                                 cur_auth = strtok_r(NULL, ",", &lasts);
8263                         }
8264                 }
8265                 current_profs = kva_match(u->attr, USERATTR_PROFILES_KW);
8266                 if (current_profs != NULL) {
8267                         (void) strlcpy(rbac_profs, current_profs, MAXPROFS);
8268                 }
8269                 free_userattr(u);
8270         }
8271         /*
8272          * The following is done to avoid revisiting the
8273          * user_attr entry for this user
8274          */
8275         (void) zonecfg_remove_userauths(handle, user, "", B_FALSE);
8276 
8277         /*
8278          * Convert each right into a properly formatted authorization
8279          */
8280         new_auth_start = new_auths + strlen(new_auths);
8281         if (!first)
8282                 new_auth_start++;
8283         right = strtok_r(auths, ",", &lasts);
8284         while (right != NULL) {
8285                 char auth[MAXAUTHS];
8286 
8287                 (void) snprintf(auth, MAXAUTHS, "%s%s/%s",
8288                     ZONE_AUTH_PREFIX, right, zonename);
8289                 if (first) {
8290                         first = B_FALSE;
8291                 } else {
8292                         (void) strlcat(new_auths, ",", MAXAUTHS);
8293                 }
8294                 (void) strlcat(new_auths, auth, MAXAUTHS);
8295                 is_zone_admin = B_TRUE;
8296                 new_auth_cnt--;
8297                 right = strtok_r(NULL, ",", &lasts);
8298         }
8299 
8300         /*
8301          * Need to update the authorizations in user_attr unless
8302          * the number of old and new authorizations is unchanged
8303          * and the new auths are a substrings of the old auths.
8304          *
8305          * If the user's previous authorizations have changed
8306          * execute the usermod progam to update them in user_attr.
8307          */
8308         if ((new_auth_cnt != 0) ||
8309             (strstr(old_auths, new_auth_start) == NULL)) {
8310                 char    *cmdbuf;
8311                 size_t  cmd_len;
8312 
8313                 update_profiles(rbac_profs, is_zone_admin);
8314                 cmd_len = snprintf(NULL, 0, "%s -A \"%s\" -P \"%s\" %s",
8315                     auths_cmd, new_auths, rbac_profs, user) + 1;
8316                 if ((cmdbuf = malloc(cmd_len)) == NULL) {
8317                         return (Z_NOMEM);
8318                 }
8319                 (void) snprintf(cmdbuf, cmd_len, "%s -A \"%s\" -P \"%s\" %s",
8320                     auths_cmd, new_auths, rbac_profs, user);
8321                 if (do_subproc(zonename, cmdbuf) != 0) {
8322                         free(cmdbuf);
8323                         return (Z_SYSTEM);
8324                 }
8325                 free(cmdbuf);
8326         }
8327 
8328         return (Z_OK);
8329 }
8330 
8331 int
8332 zonecfg_authorize_users(zone_dochandle_t handle, char *zonename)
8333 {
8334         xmlNodePtr cur;
8335         int err;
8336         char user[MAXUSERNAME];
8337         char auths[MAXAUTHS];
8338 
8339         if ((err = operation_prep(handle)) != Z_OK)
8340                 return (err);
8341 
8342         cur = handle->zone_dh_cur;
8343         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
8344                 if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
8345                         continue;
8346                 if (fetchprop(cur, DTD_ATTR_USER, user,
8347                     sizeof (user)) != Z_OK)
8348                         continue;
8349                 if (fetchprop(cur, DTD_ATTR_AUTHS, auths,
8350                     sizeof (auths)) != Z_OK)
8351                         continue;
8352                 if (zonecfg_authorize_user_impl(handle, user, auths, zonename)
8353                     != Z_OK)
8354                         return (Z_SYSTEM);
8355         }
8356         (void) zonecfg_remove_userauths(handle, "", "", B_TRUE);
8357 
8358         return (Z_OK);
8359 }
8360 
8361 int
8362 zonecfg_deauthorize_user(zone_dochandle_t handle, char *user, char *zonename)
8363 {
8364         return (zonecfg_authorize_user_impl(handle, user, "", zonename));
8365 }
8366 
8367 int
8368 zonecfg_deauthorize_users(zone_dochandle_t handle, char *zonename)
8369 {
8370         xmlNodePtr cur;
8371         int err;
8372         char user[MAXUSERNAME];
8373 
8374         if ((err = operation_prep(handle)) != Z_OK)
8375                 return (err);
8376 
8377         cur = handle->zone_dh_cur;
8378         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
8379                 if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
8380                         continue;
8381                 if (fetchprop(cur, DTD_ATTR_USER, user,
8382                     sizeof (user)) != Z_OK)
8383                         continue;
8384                 if ((err = zonecfg_deauthorize_user(handle, user,
8385                     zonename)) != Z_OK)
8386                         return (err);
8387         }
8388         return (Z_OK);
8389 }
8390 
8391 int
8392 zonecfg_insert_userauths(zone_dochandle_t handle, char *user, char *zonename)
8393 {
8394         zone_userauths_t *new, **prev, *next;
8395 
8396         prev = &handle->zone_dh_userauths;
8397         next = *prev;
8398         while (next) {
8399                 if ((strncmp(next->user, user, MAXUSERNAME) == 0) &&
8400                     (strncmp(next->zonename, zonename,
8401                     ZONENAME_MAX) == 0)) {
8402                         /*
8403                          * user is already in list
8404                          * which isn't supposed to happen!
8405                          */
8406                         return (Z_OK);
8407                 }
8408                 prev = &next->next;
8409                 next = *prev;
8410         }
8411         new = (zone_userauths_t *)malloc(sizeof (zone_userauths_t));
8412         if (new == NULL)
8413                 return (Z_NOMEM);
8414 
8415         (void) strlcpy(new->user, user, sizeof (new->user));
8416         (void) strlcpy(new->zonename, zonename, sizeof (new->zonename));
8417         new->next = NULL;
8418         *prev = new;
8419         return (Z_OK);
8420 }
8421 
8422 int
8423 zonecfg_remove_userauths(zone_dochandle_t handle, char *user, char *zonename,
8424     boolean_t deauthorize)
8425 {
8426         zone_userauths_t *new, **prev, *next;
8427 
8428         prev = &handle->zone_dh_userauths;
8429         next = *prev;
8430 
8431         while (next) {
8432                 if ((strlen(user) == 0 ||
8433                     strncmp(next->user, user, MAXUSERNAME) == 0) &&
8434                     (strlen(zonename) == 0 ||
8435                     (strncmp(next->zonename, zonename, ZONENAME_MAX) == 0))) {
8436                         new = next;
8437                         *prev = next->next;
8438                         next =  *prev;
8439                         if (deauthorize)
8440                                 (void) zonecfg_deauthorize_user(handle,
8441                                     new->user, new->zonename);
8442                         free(new);
8443                         continue;
8444                 }
8445                 prev = &next->next;
8446                 next = *prev;
8447         }
8448         return (Z_OK);
8449 }