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