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