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