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