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