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