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