Print this page
OS-200 need a better mechanism for storing persistent zone_did
OS-511 make zonecfg device resource extensible, like the net resource
OS-224 add more zonecfg net properties
OS-216 store all net config info on zone
OS-4361 libzonecfg should be aware of branded zone native root
Reviewed by: Robert Mustacchi <rm@joyent.com>
OS-3437 zonecfg failure when pool is full leaves VMs appearing to be missing
OS-399 zone phys. mem. cap should be a rctl and have associated kstat


   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2014 Gary Mills
  24  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  25  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.

  26  */
  27 
  28 #include <libsysevent.h>
  29 #include <pthread.h>
  30 #include <stdlib.h>
  31 #include <errno.h>
  32 #include <fnmatch.h>
  33 #include <strings.h>
  34 #include <unistd.h>
  35 #include <assert.h>
  36 #include <libgen.h>
  37 #include <libintl.h>
  38 #include <alloca.h>
  39 #include <ctype.h>
  40 #include <sys/acl.h>
  41 #include <sys/stat.h>
  42 #include <sys/brand.h>
  43 #include <sys/mntio.h>
  44 #include <sys/mnttab.h>
  45 #include <sys/nvpair.h>
  46 #include <sys/types.h>
  47 #include <sys/sockio.h>
  48 #include <sys/systeminfo.h>
  49 #include <ftw.h>
  50 #include <pool.h>
  51 #include <libscf.h>
  52 #include <libproc.h>
  53 #include <sys/priocntl.h>
  54 #include <libuutil.h>
  55 #include <wait.h>
  56 #include <bsm/adt.h>
  57 #include <auth_attr.h>
  58 #include <auth_list.h>
  59 #include <secdb.h>
  60 #include <user_attr.h>
  61 #include <prof_attr.h>


  62 
  63 #include <arpa/inet.h>
  64 #include <netdb.h>
  65 
  66 #include <libxml/xmlmemory.h>
  67 #include <libxml/parser.h>
  68 
  69 #include <libdevinfo.h>
  70 #include <uuid/uuid.h>
  71 #include <dirent.h>
  72 #include <libbrand.h>
  73 
  74 #include <libzonecfg.h>
  75 #include "zonecfg_impl.h"
  76 
  77 #define _PATH_TMPFILE   "/zonecfg.XXXXXX"
  78 #define ZONE_CB_RETRY_COUNT             10
  79 #define ZONE_EVENT_PING_SUBCLASS        "ping"
  80 #define ZONE_EVENT_PING_PUBLISHER       "solaris"
  81 


  82 /* Hard-code the DTD element/attribute/entity names just once, here. */
  83 #define DTD_ELEM_ATTR           (const xmlChar *) "attr"
  84 #define DTD_ELEM_COMMENT        (const xmlChar *) "comment"
  85 #define DTD_ELEM_DEVICE         (const xmlChar *) "device"
  86 #define DTD_ELEM_FS             (const xmlChar *) "filesystem"
  87 #define DTD_ELEM_FSOPTION       (const xmlChar *) "fsoption"
  88 #define DTD_ELEM_NET            (const xmlChar *) "network"

  89 #define DTD_ELEM_RCTL           (const xmlChar *) "rctl"
  90 #define DTD_ELEM_RCTLVALUE      (const xmlChar *) "rctl-value"
  91 #define DTD_ELEM_ZONE           (const xmlChar *) "zone"
  92 #define DTD_ELEM_DATASET        (const xmlChar *) "dataset"
  93 #define DTD_ELEM_TMPPOOL        (const xmlChar *) "tmp_pool"
  94 #define DTD_ELEM_PSET           (const xmlChar *) "pset"
  95 #define DTD_ELEM_MCAP           (const xmlChar *) "mcap"
  96 #define DTD_ELEM_PACKAGE        (const xmlChar *) "package"
  97 #define DTD_ELEM_OBSOLETES      (const xmlChar *) "obsoletes"
  98 #define DTD_ELEM_DEV_PERM       (const xmlChar *) "dev-perm"
  99 #define DTD_ELEM_ADMIN          (const xmlChar *) "admin"
 100 
 101 #define DTD_ATTR_ACTION         (const xmlChar *) "action"
 102 #define DTD_ATTR_ADDRESS        (const xmlChar *) "address"
 103 #define DTD_ATTR_ALLOWED_ADDRESS        (const xmlChar *) "allowed-address"
 104 #define DTD_ATTR_AUTOBOOT       (const xmlChar *) "autoboot"
 105 #define DTD_ATTR_IPTYPE         (const xmlChar *) "ip-type"
 106 #define DTD_ATTR_DEFROUTER      (const xmlChar *) "defrouter"
 107 #define DTD_ATTR_DIR            (const xmlChar *) "directory"

 108 #define DTD_ATTR_LIMIT          (const xmlChar *) "limit"
 109 #define DTD_ATTR_LIMITPRIV      (const xmlChar *) "limitpriv"
 110 #define DTD_ATTR_BOOTARGS       (const xmlChar *) "bootargs"
 111 #define DTD_ATTR_SCHED          (const xmlChar *) "scheduling-class"

 112 #define DTD_ATTR_MATCH          (const xmlChar *) "match"
 113 #define DTD_ATTR_NAME           (const xmlChar *) "name"
 114 #define DTD_ATTR_PHYSICAL       (const xmlChar *) "physical"
 115 #define DTD_ATTR_POOL           (const xmlChar *) "pool"
 116 #define DTD_ATTR_PRIV           (const xmlChar *) "priv"
 117 #define DTD_ATTR_RAW            (const xmlChar *) "raw"
 118 #define DTD_ATTR_SPECIAL        (const xmlChar *) "special"
 119 #define DTD_ATTR_TYPE           (const xmlChar *) "type"
 120 #define DTD_ATTR_VALUE          (const xmlChar *) "value"

 121 #define DTD_ATTR_ZONEPATH       (const xmlChar *) "zonepath"
 122 #define DTD_ATTR_NCPU_MIN       (const xmlChar *) "ncpu_min"
 123 #define DTD_ATTR_NCPU_MAX       (const xmlChar *) "ncpu_max"
 124 #define DTD_ATTR_IMPORTANCE     (const xmlChar *) "importance"
 125 #define DTD_ATTR_PHYSCAP        (const xmlChar *) "physcap"
 126 #define DTD_ATTR_VERSION        (const xmlChar *) "version"
 127 #define DTD_ATTR_ID             (const xmlChar *) "id"
 128 #define DTD_ATTR_UID            (const xmlChar *) "uid"
 129 #define DTD_ATTR_GID            (const xmlChar *) "gid"
 130 #define DTD_ATTR_MODE           (const xmlChar *) "mode"
 131 #define DTD_ATTR_ACL            (const xmlChar *) "acl"
 132 #define DTD_ATTR_BRAND          (const xmlChar *) "brand"

 133 #define DTD_ATTR_HOSTID         (const xmlChar *) "hostid"
 134 #define DTD_ATTR_USER           (const xmlChar *) "user"
 135 #define DTD_ATTR_AUTHS          (const xmlChar *) "auths"
 136 #define DTD_ATTR_FS_ALLOWED     (const xmlChar *) "fs-allowed"
 137 
 138 #define DTD_ENTITY_BOOLEAN      "boolean"
 139 #define DTD_ENTITY_DEVPATH      "devpath"
 140 #define DTD_ENTITY_DRIVER       "driver"
 141 #define DTD_ENTITY_DRVMIN       "drv_min"
 142 #define DTD_ENTITY_FALSE        "false"
 143 #define DTD_ENTITY_INT          "int"
 144 #define DTD_ENTITY_STRING       "string"
 145 #define DTD_ENTITY_TRUE         "true"
 146 #define DTD_ENTITY_UINT         "uint"
 147 
 148 #define DTD_ENTITY_BOOL_LEN     6       /* "false" */
 149 
 150 #define ATTACH_FORCED   "SUNWattached.xml"
 151 
 152 #define TMP_POOL_NAME   "SUNWtmp_%s"


 159  *
 160  * This holds the alias, the full rctl name, the default priv value, action
 161  * and lower limit.  The functions that handle rctl aliases step through
 162  * this table, matching on the alias, and using the full values for setting
 163  * the rctl entry as well the limit for validation.
 164  */
 165 static struct alias {
 166         char *shortname;
 167         char *realname;
 168         char *priv;
 169         char *action;
 170         uint64_t low_limit;
 171 } aliases[] = {
 172         {ALIAS_MAXLWPS, "zone.max-lwps", "privileged", "deny", 100},
 173         {ALIAS_MAXSHMMEM, "zone.max-shm-memory", "privileged", "deny", 0},
 174         {ALIAS_MAXSHMIDS, "zone.max-shm-ids", "privileged", "deny", 0},
 175         {ALIAS_MAXMSGIDS, "zone.max-msg-ids", "privileged", "deny", 0},
 176         {ALIAS_MAXSEMIDS, "zone.max-sem-ids", "privileged", "deny", 0},
 177         {ALIAS_MAXLOCKEDMEM, "zone.max-locked-memory", "privileged", "deny", 0},
 178         {ALIAS_MAXSWAP, "zone.max-swap", "privileged", "deny", 0},


 179         {ALIAS_SHARES, "zone.cpu-shares", "privileged", "none", 0},
 180         {ALIAS_CPUCAP, "zone.cpu-cap", "privileged", "deny", 0},
 181         {ALIAS_MAXPROCS, "zone.max-processes", "privileged", "deny", 100},
 182         {NULL, NULL, NULL, NULL, 0}
 183 };
 184 
 185 /*
 186  * Structure for applying rctls to a running zone.  It allows important
 187  * process values to be passed together easily.
 188  */
 189 typedef struct pr_info_handle {
 190         struct ps_prochandle *pr;
 191         pid_t pid;
 192 } pr_info_handle_t;
 193 
 194 struct zone_dochandle {
 195         char            *zone_dh_rootdir;
 196         xmlDocPtr       zone_dh_doc;
 197         xmlNodePtr      zone_dh_cur;
 198         xmlNodePtr      zone_dh_top;


 252 }
 253 
 254 const char *
 255 zonecfg_get_root(void)
 256 {
 257         return (zonecfg_root);
 258 }
 259 
 260 boolean_t
 261 zonecfg_in_alt_root(void)
 262 {
 263         return (*zonecfg_root != '\0');
 264 }
 265 
 266 /*
 267  * Callers of the _file_path() functions are expected to have the second
 268  * parameter be a (char foo[MAXPATHLEN]).
 269  */
 270 
 271 static boolean_t
 272 config_file_path(const char *zonename, char *answer)

 273 {
 274         return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root,
 275             ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN);










 276 }
 277 
 278 static boolean_t
 279 snap_file_path(const char *zonename, char *answer)
 280 {
 281         return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml",
 282             zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN);
 283 }
 284 







 285 /*ARGSUSED*/
 286 static void
 287 zonecfg_error_func(void *ctx, const char *msg, ...)
 288 {
 289         /*
 290          * This function does nothing by design.  Its purpose is to prevent
 291          * libxml from dumping unwanted messages to stdout/stderr.
 292          */
 293 }
 294 
 295 zone_dochandle_t
 296 zonecfg_init_handle(void)
 297 {
 298         zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle));
 299         if (handle == NULL) {
 300                 errno = Z_NOMEM;
 301                 return (NULL);
 302         }
 303 
 304         /* generic libxml initialization */


 333 zonecfg_destroy_impl(char *filename)
 334 {
 335         if (unlink(filename) == -1) {
 336                 if (errno == EACCES)
 337                         return (Z_ACCES);
 338                 if (errno == ENOENT)
 339                         return (Z_NO_ZONE);
 340                 return (Z_MISC_FS);
 341         }
 342         return (Z_OK);
 343 }
 344 
 345 int
 346 zonecfg_destroy(const char *zonename, boolean_t force)
 347 {
 348         char path[MAXPATHLEN];
 349         struct zoneent ze;
 350         int err, state_err;
 351         zone_state_t state;
 352 
 353         if (!config_file_path(zonename, path))
 354                 return (Z_MISC_FS);
 355 
 356         state_err = zone_get_state((char *)zonename, &state);
 357         err = access(path, W_OK);
 358 
 359         /*
 360          * If there is no file, and no index entry, reliably indicate that no
 361          * such zone exists.
 362          */
 363         if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT))
 364                 return (Z_NO_ZONE);
 365 
 366         /*
 367          * Handle any other filesystem related errors (except if the XML
 368          * file is missing, which we treat silently), unless we're forcing,
 369          * in which case we plow on.
 370          */
 371         if (err == -1 && errno != ENOENT) {
 372                 if (errno == EACCES)
 373                         return (Z_ACCES);


 390         if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK)
 391                 if (!force)
 392                         return (err);
 393 
 394         err = zonecfg_destroy_impl(path);
 395 
 396         /*
 397          * Treat failure to find the XML file silently, since, well, it's
 398          * gone, and with the index file cleaned up, we're done.
 399          */
 400         if (err == Z_OK || err == Z_NO_ZONE)
 401                 return (Z_OK);
 402         return (err);
 403 }
 404 
 405 int
 406 zonecfg_destroy_snapshot(const char *zonename)
 407 {
 408         char path[MAXPATHLEN];
 409 
 410         if (!snap_file_path(zonename, path))
 411                 return (Z_MISC_FS);
 412         return (zonecfg_destroy_impl(path));
 413 }
 414 
 415 static int
 416 getroot(zone_dochandle_t handle, xmlNodePtr *root)
 417 {
 418         if (zonecfg_check_handle(handle) == Z_BAD_HANDLE)
 419                 return (Z_BAD_HANDLE);
 420 
 421         *root = xmlDocGetRootElement(handle->zone_dh_doc);
 422 
 423         if (*root == NULL)
 424                 return (Z_EMPTY_DOCUMENT);
 425 
 426         if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE))
 427                 return (Z_WRONG_DOC_TYPE);
 428 
 429         return (Z_OK);
 430 }


 557 {
 558         xmlNodePtr root, child, next;
 559 
 560         root = xmlDocGetRootElement(handle->zone_dh_doc);
 561         for (child = root->xmlChildrenNode; child != NULL; child = next) {
 562                 next = child->next;
 563                 if (child->name == NULL)
 564                         continue;
 565                 if (xmlStrcmp(child->name, DTD_ELEM_PACKAGE) == 0) {
 566                         next = child->next;
 567                         xmlUnlinkNode(child);
 568                         xmlFreeNode(child);
 569                 }
 570         }
 571 }
 572 
 573 static int
 574 zonecfg_get_handle_impl(const char *zonename, const char *filename,
 575     zone_dochandle_t handle)
 576 {
 577         xmlValidCtxtPtr cvp;
 578         struct stat statbuf;
 579         int valid;
 580 
 581         if (zonename == NULL)
 582                 return (Z_NO_ZONE);
 583 
 584         if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) {
 585                 /* distinguish file not found vs. found but not parsed */
 586                 if (stat(filename, &statbuf) == 0)
 587                         return (Z_INVALID_DOCUMENT);
 588                 return (Z_NO_ZONE);
 589         }
 590         if ((cvp = xmlNewValidCtxt()) == NULL)

 591                 return (Z_NOMEM);
 592         cvp->error = zonecfg_error_func;
 593         cvp->warning = zonecfg_error_func;
 594         valid = xmlValidateDocument(cvp, handle->zone_dh_doc);
 595         xmlFreeValidCtxt(cvp);
 596         if (valid == 0)
 597                 return (Z_INVALID_DOCUMENT);

 598 
 599         /* delete any comments such as inherited Sun copyright / ident str */
 600         stripcomments(handle);
 601         return (Z_OK);
 602 }
 603 
 604 int
 605 zonecfg_get_handle(const char *zonename, zone_dochandle_t handle)
 606 {
 607         char path[MAXPATHLEN];
 608 
 609         if (!config_file_path(zonename, path))
 610                 return (Z_MISC_FS);
 611         handle->zone_dh_newzone = B_FALSE;
 612 
 613         return (zonecfg_get_handle_impl(zonename, path, handle));
 614 }
 615 
 616 int
 617 zonecfg_get_attach_handle(const char *path, const char *fname,
 618     const char *zonename, boolean_t preserve_sw, zone_dochandle_t handle)
 619 {
 620         char            migpath[MAXPATHLEN];
 621         int             err;
 622         struct stat     buf;
 623 
 624         if (snprintf(migpath, sizeof (migpath), "%s/root", path) >=
 625             sizeof (migpath))
 626                 return (Z_NOMEM);
 627 
 628         if (stat(migpath, &buf) == -1 || !S_ISDIR(buf.st_mode))
 629                 return (Z_NO_ZONE);


 633                 return (Z_NOMEM);
 634 
 635         if ((err = zonecfg_get_handle_impl(zonename, migpath, handle)) != Z_OK)
 636                 return (err);
 637 
 638         if (!preserve_sw)
 639                 strip_sw_inv(handle);
 640 
 641         handle->zone_dh_newzone = B_TRUE;
 642         if ((err = setrootattr(handle, DTD_ATTR_ZONEPATH, path)) != Z_OK)
 643                 return (err);
 644 
 645         return (setrootattr(handle, DTD_ATTR_NAME, zonename));
 646 }
 647 
 648 int
 649 zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle)
 650 {
 651         char path[MAXPATHLEN];
 652 
 653         if (!snap_file_path(zonename, path))
 654                 return (Z_MISC_FS);
 655         handle->zone_dh_newzone = B_FALSE;
 656         return (zonecfg_get_handle_impl(zonename, path, handle));
 657 }
 658 
 659 int
 660 zonecfg_get_template_handle(const char *template, const char *zonename,
 661     zone_dochandle_t handle)
 662 {
 663         char path[MAXPATHLEN];
 664         int err;
 665 
 666         if (!config_file_path(template, path))
 667                 return (Z_MISC_FS);
 668 
 669         if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK)
 670                 return (err);
 671         handle->zone_dh_newzone = B_TRUE;
 672         return (setrootattr(handle, DTD_ATTR_NAME, zonename));
 673 }
 674 
 675 int
 676 zonecfg_get_xml_handle(const char *path, zone_dochandle_t handle)
 677 {
 678         struct stat buf;
 679         int err;
 680 
 681         if (stat(path, &buf) == -1)
 682                 return (Z_MISC_FS);
 683 
 684         if ((err = zonecfg_get_handle_impl("xml", path, handle)) != Z_OK)
 685                 return (err);
 686         handle->zone_dh_newzone = B_TRUE;
 687         return (Z_OK);
 688 }
 689 
 690 /*
 691  * Initialize two handles from the manifest read on fd.  The rem_handle
 692  * is initialized from the input file, including the sw inventory.  The
 693  * local_handle is initialized with the same zone configuration but with
 694  * no sw inventory.
 695  */
 696 int
 697 zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle,
 698     zone_dochandle_t rem_handle)
 699 {
 700         xmlValidCtxtPtr cvp;
 701         int valid;
 702 
 703         /* load the manifest into the handle for the remote system */
 704         if ((rem_handle->zone_dh_doc = xmlReadFd(fd, NULL, NULL, 0)) == NULL) {
 705                 return (Z_INVALID_DOCUMENT);
 706         }
 707         if ((cvp = xmlNewValidCtxt()) == NULL)

 708                 return (Z_NOMEM);
 709         cvp->error = zonecfg_error_func;
 710         cvp->warning = zonecfg_error_func;
 711         valid = xmlValidateDocument(cvp, rem_handle->zone_dh_doc);
 712         xmlFreeValidCtxt(cvp);
 713         if (valid == 0)
 714                 return (Z_INVALID_DOCUMENT);

 715 
 716         /* delete any comments such as inherited Sun copyright / ident str */
 717         stripcomments(rem_handle);
 718 
 719         rem_handle->zone_dh_newzone = B_TRUE;
 720         rem_handle->zone_dh_sw_inv = B_TRUE;
 721 
 722         /*
 723          * Now use the remote system handle to generate a local system handle
 724          * with an identical zones configuration but no sw inventory.
 725          */
 726         if ((local_handle->zone_dh_doc = xmlCopyDoc(rem_handle->zone_dh_doc,
 727             1)) == NULL) {
 728                 return (Z_INVALID_DOCUMENT);
 729         }
 730 
 731         /*
 732          * We need to re-run xmlValidateDocument on local_handle to properly
 733          * update the in-core representation of the configuration.
 734          */
 735         if ((cvp = xmlNewValidCtxt()) == NULL)
 736                 return (Z_NOMEM);
 737         cvp->error = zonecfg_error_func;
 738         cvp->warning = zonecfg_error_func;
 739         valid = xmlValidateDocument(cvp, local_handle->zone_dh_doc);
 740         xmlFreeValidCtxt(cvp);
 741         if (valid == 0)
 742                 return (Z_INVALID_DOCUMENT);

 743 
 744         strip_sw_inv(local_handle);
 745 
 746         local_handle->zone_dh_newzone = B_TRUE;
 747         local_handle->zone_dh_sw_inv = B_FALSE;
 748 
 749         return (Z_OK);
 750 }
 751 
 752 static boolean_t
 753 is_renaming(zone_dochandle_t handle)
 754 {
 755         if (handle->zone_dh_newzone)
 756                 return (B_FALSE);
 757         if (strlen(handle->zone_dh_delete_name) > 0)
 758                 return (B_TRUE);
 759         return (B_FALSE);
 760 }
 761 
 762 static boolean_t


1176  * Save existing zone 'foo':
1177  *      Make backup of foo.xml -> .backup
1178  *      Create tmpfile (zonecfg.xxxxxx)
1179  *      Write XML to tmpfile
1180  *      Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
1181  *      Modify index file as needed
1182  *      If it fails, recover from .backup -> foo.xml
1183  *
1184  * Rename 'foo' to 'bar':
1185  *      Create tmpfile (zonecfg.xxxxxx)
1186  *      Write XML to tmpfile
1187  *      Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml)
1188  *      Add entry for 'bar' to index file, Remove entry for 'foo' (refresh)
1189  *      If it fails, delete bar.xml; foo.xml is left behind.
1190  */
1191 static int
1192 zonecfg_save_impl(zone_dochandle_t handle, char *filename)
1193 {
1194         char tmpfile[MAXPATHLEN];
1195         char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN];
1196         int tmpfd, err, valid;
1197         xmlValidCtxt cvp = { NULL };
1198         boolean_t backup;

1199 
1200         (void) strlcpy(tmpfile, filename, sizeof (tmpfile));
1201         (void) dirname(tmpfile);
1202         (void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile));
1203 
1204         tmpfd = mkstemp(tmpfile);
1205         if (tmpfd == -1) {
1206                 (void) unlink(tmpfile);
1207                 return (Z_TEMP_FILE);
1208         }
1209         (void) close(tmpfd);
1210 
1211         cvp.error = zonecfg_error_func;
1212         cvp.warning = zonecfg_error_func;
1213 
1214         /*
1215          * We do a final validation of the document.  Since the library has
1216          * malfunctioned if it fails to validate, we follow-up with an
1217          * assert() that the doc is valid.
1218          */
1219         valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1220         assert(valid != 0);
1221 
1222         if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0)
1223                 goto err;
1224 
1225         (void) chmod(tmpfile, 0644);
1226 
1227         /*
1228          * In the event we are doing a standard save, hard link a copy of the
1229          * original file in .backup.<pid>.filename so we can restore it if
1230          * something goes wrong.
1231          */
1232         if (!is_new(handle) && !is_renaming(handle)) {
1233                 backup = B_TRUE;
1234 
1235                 (void) strlcpy(bakdir, filename, sizeof (bakdir));
1236                 (void) strlcpy(bakbase, filename, sizeof (bakbase));
1237                 (void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s",
1238                     dirname(bakdir), getpid(), basename(bakbase));
1239 
1240                 if (link(filename, bakfile) == -1) {


1255                 (void) unlink(tmpfile);
1256                 if (backup)
1257                         (void) unlink(bakfile);
1258                 if (err == EACCES)
1259                         return (Z_ACCES);
1260                 return (Z_MISC_FS);
1261         }
1262 
1263         /*
1264          * If this is a snapshot, we're done-- don't add an index entry.
1265          */
1266         if (is_snapshot(handle))
1267                 return (Z_OK);
1268 
1269         /* now update the index file to reflect whatever we just did */
1270         if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) {
1271                 if (backup) {
1272                         /*
1273                          * Try to restore from our backup.
1274                          */
1275                         (void) unlink(filename);
1276                         (void) rename(bakfile, filename);
1277                 } else {
1278                         /*
1279                          * Either the zone is new, in which case we can delete
1280                          * new.xml, or we're doing a rename, so ditto.
1281                          */
1282                         assert(is_new(handle) || is_renaming(handle));
1283                         (void) unlink(filename);
1284                 }
1285                 return (Z_UPDATING_INDEX);
1286         }
1287 
1288         if (backup)
1289                 (void) unlink(bakfile);
1290 
1291         return (Z_OK);
1292 
1293 err:
1294         (void) unlink(tmpfile);
1295         return (Z_SAVING_FILE);


1298 int
1299 zonecfg_save(zone_dochandle_t handle)
1300 {
1301         char zname[ZONENAME_MAX], path[MAXPATHLEN];
1302         char delpath[MAXPATHLEN];
1303         int err = Z_SAVING_FILE;
1304 
1305         if (zonecfg_check_handle(handle) != Z_OK)
1306                 return (Z_BAD_HANDLE);
1307 
1308         /*
1309          * We don't support saving snapshots or a tree containing a sw
1310          * inventory at this time.
1311          */
1312         if (handle->zone_dh_snapshot || handle->zone_dh_sw_inv)
1313                 return (Z_INVAL);
1314 
1315         if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK)
1316                 return (err);
1317 
1318         if (!config_file_path(zname, path))
1319                 return (Z_MISC_FS);
1320 
1321         addcomment(handle, "\n    DO NOT EDIT THIS "
1322             "FILE.  Use zonecfg(1M) instead.\n");
1323 
1324         /*
1325          * Update user_attr first so that it will be older
1326          * than the config file.
1327          */
1328         (void) zonecfg_authorize_users(handle, zname);
1329         err = zonecfg_save_impl(handle, path);
1330 
1331         stripcomments(handle);
1332 
1333         if (err != Z_OK)
1334                 return (err);
1335 
1336         handle->zone_dh_newzone = B_FALSE;
1337 
1338         if (is_renaming(handle)) {
1339                 if (config_file_path(handle->zone_dh_delete_name, delpath))

1340                         (void) unlink(delpath);

1341                 handle->zone_dh_delete_name[0] = '\0';
1342         }
1343 
1344         return (Z_OK);
1345 }
1346 
1347 int
1348 zonecfg_verify_save(zone_dochandle_t handle, char *filename)
1349 {
1350         int valid;
1351 
1352         xmlValidCtxt cvp = { NULL };
1353 
1354         if (zonecfg_check_handle(handle) != Z_OK)
1355                 return (Z_BAD_HANDLE);
1356 
1357         cvp.error = zonecfg_error_func;
1358         cvp.warning = zonecfg_error_func;
1359 
1360         /*
1361          * We do a final validation of the document.  Since the library has
1362          * malfunctioned if it fails to validate, we follow-up with an
1363          * assert() that the doc is valid.
1364          */
1365         valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1366         assert(valid != 0);
1367 
1368         if (xmlSaveFormatFile(filename, handle->zone_dh_doc, 1) <= 0)
1369                 return (Z_SAVING_FILE);
1370 
1371         return (Z_OK);
1372 }
1373 
1374 int
1375 zonecfg_detach_save(zone_dochandle_t handle, uint_t flags)
1376 {
1377         char zname[ZONENAME_MAX];
1378         char path[MAXPATHLEN];
1379         char migpath[MAXPATHLEN];
1380         xmlValidCtxt cvp = { NULL };
1381         int err = Z_SAVING_FILE;
1382         int valid;
1383 
1384         if (zonecfg_check_handle(handle) != Z_OK)
1385                 return (Z_BAD_HANDLE);
1386 
1387         if (flags & ZONE_DRY_RUN) {
1388                 (void) strlcpy(migpath, "-", sizeof (migpath));
1389         } else {
1390                 if ((err = zonecfg_get_name(handle, zname, sizeof (zname)))
1391                     != Z_OK)
1392                         return (err);
1393 
1394                 if ((err = zone_get_zonepath(zname, path, sizeof (path)))
1395                     != Z_OK)
1396                         return (err);
1397 
1398                 if (snprintf(migpath, sizeof (migpath), "%s/%s", path,
1399                     ZONE_DETACHED) >= sizeof (migpath))
1400                         return (Z_NOMEM);
1401         }
1402 
1403         if ((err = operation_prep(handle)) != Z_OK)
1404                 return (err);
1405 
1406         addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
1407             "Use zonecfg(1M) and zoneadm(1M) attach.\n");
1408 
1409         cvp.error = zonecfg_error_func;
1410         cvp.warning = zonecfg_error_func;
1411 
1412         /*
1413          * We do a final validation of the document.  Since the library has
1414          * malfunctioned if it fails to validate, we follow-up with an
1415          * assert() that the doc is valid.
1416          */
1417         valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1418         assert(valid != 0);
1419 
1420         if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0)
1421                 return (Z_SAVING_FILE);
1422 
1423         if (!(flags & ZONE_DRY_RUN))
1424                 (void) chmod(migpath, 0644);
1425 
1426         stripcomments(handle);
1427 
1428         handle->zone_dh_newzone = B_FALSE;
1429 
1430         return (Z_OK);
1431 }
1432 
1433 boolean_t
1434 zonecfg_detached(const char *path)
1435 {
1436         char            migpath[MAXPATHLEN];
1437         struct stat     buf;
1438 


1471         if (forced) {
1472                 (void) rename(detached, attached);
1473         } else {
1474                 (void) unlink(attached);
1475                 (void) unlink(detached);
1476         }
1477 }
1478 
1479 /*
1480  * Special case: if access(2) fails with ENOENT, then try again using
1481  * ZONE_CONFIG_ROOT instead of config_file_path(zonename).  This is how we
1482  * work around the case of a config file which has not been created yet:
1483  * the user will need access to the directory so use that as a heuristic.
1484  */
1485 
1486 int
1487 zonecfg_access(const char *zonename, int amode)
1488 {
1489         char path[MAXPATHLEN];
1490 
1491         if (!config_file_path(zonename, path))
1492                 return (Z_INVAL);
1493         if (access(path, amode) == 0)
1494                 return (Z_OK);
1495         if (errno == ENOENT) {
1496                 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1497                     ZONE_CONFIG_ROOT) >= sizeof (path))
1498                         return (Z_INVAL);
1499                 if (access(path, amode) == 0)
1500                         return (Z_OK);
1501         }
1502         if (errno == EACCES)
1503                 return (Z_ACCES);
1504         if (errno == EINVAL)
1505                 return (Z_INVAL);
1506         return (Z_MISC_FS);
1507 }
1508 
1509 int
1510 zonecfg_create_snapshot(const char *zonename)
1511 {


1536          * save the resolved path in the snapshot, thus preventing any
1537          * potential problems down the line when zoneadmd goes to unmount
1538          * file systems and depends on initial string matches with resolved
1539          * paths.
1540          */
1541         rpath[res] = '\0';
1542         if (strcmp(zonepath, rpath) != 0) {
1543                 if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK)
1544                         goto out;
1545         }
1546         if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1547             ZONE_SNAPSHOT_ROOT) >= sizeof (path)) {
1548                 error = Z_MISC_FS;
1549                 goto out;
1550         }
1551         if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) {
1552                 error = Z_MISC_FS;
1553                 goto out;
1554         }
1555 
1556         if (!snap_file_path(zonename, path)) {
1557                 error = Z_MISC_FS;
1558                 goto out;
1559         }
1560 
1561         addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
1562             "It is a snapshot of running zone state.\n");
1563 
1564         error = zonecfg_save_impl(handle, path);
1565 
1566         stripcomments(handle);
1567 
1568 out:
1569         zonecfg_fini_handle(handle);
1570         return (error);
1571 }
1572 
1573 int
1574 zonecfg_get_iptype(zone_dochandle_t handle, zone_iptype_t *iptypep)
1575 {
1576         char property[10]; /* 10 is big enough for "shared"/"exclusive" */


2067 
2068 /*
2069  * Determines whether there is a net resource with the physical interface, IP
2070  * address, and default router specified by 'tabptr' in the zone configuration
2071  * to which 'handle' refers.  'tabptr' must have an interface, an address, a
2072  * default router, or a combination of the three.  This function returns Z_OK
2073  * iff there is exactly one net resource matching the query specified by
2074  * 'tabptr'.  The function returns Z_INSUFFICIENT_SPEC if there are multiple
2075  * matches or 'tabptr' does not specify a physical interface, address, or
2076  * default router.  The function returns Z_NO_RESOURCE_ID if are no matches.
2077  *
2078  * Errors might also be returned if the entry that exactly matches the
2079  * query lacks critical network resource information.
2080  *
2081  * If there is a single match, then the matching entry's physical interface, IP
2082  * address, and default router information are stored in 'tabptr'.
2083  */
2084 int
2085 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2086 {
2087         xmlNodePtr cur;
2088         xmlNodePtr firstmatch;
2089         int err;
2090         char address[INET6_ADDRSTRLEN];
2091         char physical[LIFNAMSIZ];


2092         size_t addrspec;                /* nonzero if tabptr has IP addr */
2093         size_t physspec;                /* nonzero if tabptr has interface */


2094         size_t defrouterspec;           /* nonzero if tabptr has def. router */
2095         size_t allowed_addrspec;
2096         zone_iptype_t iptype;
2097 
2098         if (tabptr == NULL)
2099                 return (Z_INVAL);
2100 
2101         /*
2102          * Determine the fields that will be searched.  There must be at least
2103          * one.
2104          *
2105          * zone_nwif_address, zone_nwif_physical, and zone_nwif_defrouter are

2106          * arrays, so no NULL checks are necessary.
2107          */
2108         addrspec = strlen(tabptr->zone_nwif_address);
2109         physspec = strlen(tabptr->zone_nwif_physical);


2110         defrouterspec = strlen(tabptr->zone_nwif_defrouter);
2111         allowed_addrspec = strlen(tabptr->zone_nwif_allowed_address);
2112         if (addrspec != 0 && allowed_addrspec != 0)
2113                 return (Z_INVAL); /* can't specify both */
2114         if (addrspec == 0 && physspec == 0 && defrouterspec == 0 &&
2115             allowed_addrspec == 0)
2116                 return (Z_INSUFFICIENT_SPEC);
2117 
2118         if ((err = operation_prep(handle)) != Z_OK)
2119                 return (err);
2120 
2121         if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK)
2122                 return (err);
2123         /*
2124          * Iterate over the configuration's elements and look for net elements
2125          * that match the query.
2126          */
2127         firstmatch = NULL;
2128         cur = handle->zone_dh_cur;
2129         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2130                 /* Skip non-net elements */
2131                 if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2132                         continue;
2133 
2134                 /*
2135                  * If any relevant fields don't match the query, then skip
2136                  * the current net element.
2137                  */
2138                 if (physspec != 0 && (fetchprop(cur, DTD_ATTR_PHYSICAL,
2139                     physical, sizeof (physical)) != Z_OK ||
2140                     strcmp(tabptr->zone_nwif_physical, physical) != 0))
2141                         continue;









2142                 if (iptype == ZS_SHARED && addrspec != 0 &&
2143                     (fetchprop(cur, DTD_ATTR_ADDRESS, address,
2144                     sizeof (address)) != Z_OK ||
2145                     !zonecfg_same_net_address(tabptr->zone_nwif_address,
2146                     address)))
2147                         continue;
2148                 if (iptype == ZS_EXCLUSIVE && allowed_addrspec != 0 &&
2149                     (fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS, address,
2150                     sizeof (address)) != Z_OK ||
2151                     !zonecfg_same_net_address(tabptr->zone_nwif_allowed_address,
2152                     address)))
2153                         continue;
2154                 if (defrouterspec != 0 && (fetchprop(cur, DTD_ATTR_DEFROUTER,
2155                     address, sizeof (address)) != Z_OK ||
2156                     !zonecfg_same_net_address(tabptr->zone_nwif_defrouter,
2157                     address)))
2158                         continue;
2159 
2160                 /*
2161                  * The current net element matches the query.  Select it if


2164                 if (firstmatch == NULL)
2165                         firstmatch = cur;
2166                 else
2167                         return (Z_INSUFFICIENT_SPEC);
2168         }
2169         if (firstmatch == NULL)
2170                 return (Z_NO_RESOURCE_ID);
2171 
2172         cur = firstmatch;
2173 
2174         if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
2175             sizeof (tabptr->zone_nwif_physical))) != Z_OK)
2176                 return (err);
2177 
2178         if (iptype == ZS_SHARED &&
2179             (err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
2180             sizeof (tabptr->zone_nwif_address))) != Z_OK)
2181                 return (err);
2182 
2183         if (iptype == ZS_EXCLUSIVE &&















2184             (err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
2185             tabptr->zone_nwif_allowed_address,
2186             sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK)
2187                 return (err);
2188 
2189         if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
2190             tabptr->zone_nwif_defrouter,
2191             sizeof (tabptr->zone_nwif_defrouter))) != Z_OK)
2192                 return (err);
2193 


























2194         return (Z_OK);
2195 }
2196 
2197 static int
2198 zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2199 {
2200         xmlNodePtr newnode, cur = handle->zone_dh_cur;

2201         int err;
2202 
2203         newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL);
2204         if (strlen(tabptr->zone_nwif_address) > 0 &&
2205             (err = newprop(newnode, DTD_ATTR_ADDRESS,
2206             tabptr->zone_nwif_address)) != Z_OK)
2207                 return (err);
2208         if (strlen(tabptr->zone_nwif_allowed_address) > 0 &&
2209             (err = newprop(newnode, DTD_ATTR_ALLOWED_ADDRESS,
2210             tabptr->zone_nwif_allowed_address)) != Z_OK)
2211                 return (err);
2212         if ((err = newprop(newnode, DTD_ATTR_PHYSICAL,
2213             tabptr->zone_nwif_physical)) != Z_OK)
2214                 return (err);
2215         /*
2216          * Do not add this property when it is not set, for backwards
2217          * compatibility and because it is optional.
2218          */
2219         if ((strlen(tabptr->zone_nwif_defrouter) > 0) &&
2220             ((err = newprop(newnode, DTD_ATTR_DEFROUTER,
2221             tabptr->zone_nwif_defrouter)) != Z_OK))
2222                 return (err);



























2223         return (Z_OK);
2224 }
2225 
2226 int
2227 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2228 {
2229         int err;
2230 
2231         if (tabptr == NULL)
2232                 return (Z_INVAL);
2233 
2234         if ((err = operation_prep(handle)) != Z_OK)
2235                 return (err);
2236 
2237         if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK)
2238                 return (err);
2239 
2240         return (Z_OK);
2241 }
2242 
2243 static int
2244 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2245 {
2246         xmlNodePtr cur = handle->zone_dh_cur;
2247         boolean_t addr_match, phys_match, allowed_addr_match;

2248 
2249         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2250                 if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2251                         continue;
2252 
2253                 addr_match = match_prop(cur, DTD_ATTR_ADDRESS,
2254                     tabptr->zone_nwif_address);
2255                 allowed_addr_match = match_prop(cur, DTD_ATTR_ALLOWED_ADDRESS,
2256                     tabptr->zone_nwif_allowed_address);
2257                 phys_match = match_prop(cur, DTD_ATTR_PHYSICAL,
2258                     tabptr->zone_nwif_physical);




2259 
2260                 if (addr_match && allowed_addr_match && phys_match) {

2261                         xmlUnlinkNode(cur);
2262                         xmlFreeNode(cur);
2263                         return (Z_OK);
2264                 }
2265         }
2266         return (Z_NO_RESOURCE_ID);
2267 }
2268 
2269 int
2270 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2271 {
2272         int err;
2273 
2274         if (tabptr == NULL)
2275                 return (Z_INVAL);
2276 
2277         if ((err = operation_prep(handle)) != Z_OK)
2278                 return (err);
2279 
2280         if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK)


2289         struct zone_nwiftab *oldtabptr,
2290         struct zone_nwiftab *newtabptr)
2291 {
2292         int err;
2293 
2294         if (oldtabptr == NULL || newtabptr == NULL)
2295                 return (Z_INVAL);
2296 
2297         if ((err = operation_prep(handle)) != Z_OK)
2298                 return (err);
2299 
2300         if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK)
2301                 return (err);
2302 
2303         if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK)
2304                 return (err);
2305 
2306         return (Z_OK);
2307 }
2308 




















































2309 /*
2310  * Must be a comma-separated list of alpha-numeric file system names.
2311  */
2312 static int
2313 zonecfg_valid_fs_allowed(const char *fsallowedp)
2314 {
2315         char tmp[ZONE_FS_ALLOWED_MAX];
2316         char *cp = tmp;
2317         char *p;
2318 
2319         if (strlen(fsallowedp) > ZONE_FS_ALLOWED_MAX)
2320                 return (Z_TOO_BIG);
2321 
2322         (void) strlcpy(tmp, fsallowedp, sizeof (tmp));
2323 
2324         while (*cp != '\0') {
2325                 p = cp;
2326                 while (*p != '\0' && *p != ',') {
2327                         if (!isalnum(*p) && *p != '-')
2328                                 return (Z_INVALID_PROPERTY);


2438  * attribute is cleared.  Non-NULL hostids are validated.  This function returns
2439  * Z_OK on success.  Any other return value indicates failure.
2440  */
2441 int
2442 zonecfg_set_hostid(zone_dochandle_t handle, const char *hostidp)
2443 {
2444         int err;
2445 
2446         /*
2447          * A NULL hostid string is interpreted as a request to clear the
2448          * hostid.
2449          */
2450         if (hostidp == NULL || (err = zonecfg_valid_hostid(hostidp)) == Z_OK)
2451                 return (setrootattr(handle, DTD_ATTR_HOSTID, hostidp));
2452         return (err);
2453 }
2454 
2455 int
2456 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2457 {
2458         xmlNodePtr cur, firstmatch;
2459         int err;
2460         char match[MAXPATHLEN];
2461 
2462         if (tabptr == NULL)
2463                 return (Z_INVAL);
2464 
2465         if ((err = operation_prep(handle)) != Z_OK)
2466                 return (err);
2467 
2468         cur = handle->zone_dh_cur;
2469         firstmatch = NULL;
2470         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2471                 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2472                         continue;
2473                 if (strlen(tabptr->zone_dev_match) == 0)
2474                         continue;
2475 
2476                 if ((fetchprop(cur, DTD_ATTR_MATCH, match,
2477                     sizeof (match)) == Z_OK)) {
2478                         if (strcmp(tabptr->zone_dev_match,


2483                                         return (Z_INSUFFICIENT_SPEC);
2484                         } else {
2485                                 /*
2486                                  * If another property matched but this
2487                                  * one doesn't then reset firstmatch.
2488                                  */
2489                                 if (firstmatch == cur)
2490                                         firstmatch = NULL;
2491                         }
2492                 }
2493         }
2494         if (firstmatch == NULL)
2495                 return (Z_NO_RESOURCE_ID);
2496 
2497         cur = firstmatch;
2498 
2499         if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
2500             sizeof (tabptr->zone_dev_match))) != Z_OK)
2501                 return (err);
2502 


























2503         return (Z_OK);
2504 }
2505 
2506 static int
2507 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
2508 {
2509         xmlNodePtr newnode, cur = handle->zone_dh_cur;

2510         int err;
2511 
2512         newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL);
2513 
2514         if ((err = newprop(newnode, DTD_ATTR_MATCH,
2515             tabptr->zone_dev_match)) != Z_OK)
2516                 return (err);
2517 















2518         return (Z_OK);
2519 }
2520 
2521 int
2522 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2523 {
2524         int err;
2525 
2526         if (tabptr == NULL)
2527                 return (Z_INVAL);
2528 
2529         if ((err = operation_prep(handle)) != Z_OK)
2530                 return (err);
2531 
2532         if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK)
2533                 return (err);
2534 
2535         return (Z_OK);
2536 }
2537 


4695 
4696         handle->zone_dh_cur = cur->next;
4697         return (Z_OK);
4698 }
4699 
4700 int
4701 zonecfg_endfsent(zone_dochandle_t handle)
4702 {
4703         return (zonecfg_endent(handle));
4704 }
4705 
4706 int
4707 zonecfg_setnwifent(zone_dochandle_t handle)
4708 {
4709         return (zonecfg_setent(handle));
4710 }
4711 
4712 int
4713 zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
4714 {
4715         xmlNodePtr cur;

4716         int err;
4717 
4718         if (handle == NULL)
4719                 return (Z_INVAL);
4720 
4721         if ((cur = handle->zone_dh_cur) == NULL)
4722                 return (Z_NO_ENTRY);
4723 
4724         for (; cur != NULL; cur = cur->next)
4725                 if (!xmlStrcmp(cur->name, DTD_ELEM_NET))
4726                         break;
4727         if (cur == NULL) {
4728                 handle->zone_dh_cur = handle->zone_dh_top;
4729                 return (Z_NO_ENTRY);
4730         }
4731 
4732         if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
4733             sizeof (tabptr->zone_nwif_address))) != Z_OK) {
4734                 handle->zone_dh_cur = handle->zone_dh_top;
4735                 return (err);
4736         }
4737 
4738         if ((err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
4739             tabptr->zone_nwif_allowed_address,
4740             sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK) {
4741                 handle->zone_dh_cur = handle->zone_dh_top;
4742                 return (err);
4743         }
4744 
4745         if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
4746             sizeof (tabptr->zone_nwif_physical))) != Z_OK) {
4747                 handle->zone_dh_cur = handle->zone_dh_top;
4748                 return (err);
4749         }
4750 


















4751         if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
4752             tabptr->zone_nwif_defrouter,
4753             sizeof (tabptr->zone_nwif_defrouter))) != Z_OK) {
4754                 handle->zone_dh_cur = handle->zone_dh_top;
4755                 return (err);
4756         }
4757 























4758         handle->zone_dh_cur = cur->next;
4759         return (Z_OK);
4760 }
4761 
4762 int
4763 zonecfg_endnwifent(zone_dochandle_t handle)
4764 {
4765         return (zonecfg_endent(handle));
4766 }
4767 
4768 int
4769 zonecfg_setdevent(zone_dochandle_t handle)
4770 {
4771         return (zonecfg_setent(handle));
4772 }
4773 
4774 int
4775 zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr)
4776 {
4777         xmlNodePtr cur;
4778         int err;
4779 
4780         if (handle == NULL)
4781                 return (Z_INVAL);
4782 
4783         if ((cur = handle->zone_dh_cur) == NULL)
4784                 return (Z_NO_ENTRY);
4785 
4786         for (; cur != NULL; cur = cur->next)
4787                 if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
4788                         break;
4789         if (cur == NULL) {
4790                 handle->zone_dh_cur = handle->zone_dh_top;
4791                 return (Z_NO_ENTRY);
4792         }
4793 
4794         if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
4795             sizeof (tabptr->zone_dev_match))) != Z_OK) {
4796                 handle->zone_dh_cur = handle->zone_dh_top;
4797                 return (err);
4798         }
4799 

























4800         handle->zone_dh_cur = cur->next;
4801         return (Z_OK);
4802 }
4803 
4804 int
4805 zonecfg_enddevent(zone_dochandle_t handle)
4806 {
4807         return (zonecfg_endent(handle));
4808 }
4809 
4810 int
4811 zonecfg_setrctlent(zone_dochandle_t handle)
4812 {
4813         return (zonecfg_setent(handle));
4814 }
4815 
4816 int
4817 zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr)
4818 {
4819         xmlNodePtr cur, val;


5508                         return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL);
5509 
5510                 return (Z_OK);
5511         }
5512 
5513         if (strcmp(zone_name, "global") == 0)
5514                 return (zonecfg_default_brand(brandname, rp_sz));
5515 
5516         if ((handle = zonecfg_init_handle()) == NULL)
5517                 return (Z_NOMEM);
5518 
5519         err = zonecfg_get_handle((char *)zone_name, handle);
5520         if (err == Z_OK)
5521                 err = zonecfg_get_brand(handle, brandname, rp_sz);
5522 
5523         zonecfg_fini_handle(handle);
5524         return (err);
5525 }
5526 
5527 /*






























































































































































5528  * Return the appropriate root for the active /dev.
5529  * For normal zone, the path is $ZONEPATH/root;
5530  * for scratch zone, the dev path is $ZONEPATH/lu.
5531  */
5532 int
5533 zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz)
5534 {
5535         int err;
5536         char *suffix;
5537         zone_state_t state;
5538 
5539         /* This function makes sense for non-global zones only. */
5540         if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
5541                 return (Z_BOGUS_ZONE_NAME);
5542         if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK)
5543                 return (err);
5544 
5545         if (zone_get_state(zone_name, &state) == Z_OK &&
5546             state == ZONE_STATE_MOUNTED)
5547                 suffix = "/lu";


6822         }
6823 
6824         return (res);
6825 }
6826 
6827 int
6828 zonecfg_getpsetent(zone_dochandle_t handle, struct zone_psettab *tabptr)
6829 {
6830         int err;
6831 
6832         if ((err = zonecfg_setent(handle)) != Z_OK)
6833                 return (err);
6834 
6835         err = zonecfg_lookup_pset(handle, tabptr);
6836 
6837         (void) zonecfg_endent(handle);
6838 
6839         return (err);
6840 }
6841 
6842 static int
6843 add_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6844 {
6845         xmlNodePtr newnode, cur = handle->zone_dh_cur;
6846         int err;
6847 
6848         newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_MCAP, NULL);
6849         if ((err = newprop(newnode, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap))
6850             != Z_OK)
6851                 return (err);
6852 
6853         return (Z_OK);
6854 }
6855 
6856 int
6857 zonecfg_delete_mcap(zone_dochandle_t handle)
6858 {
6859         int err;
6860         xmlNodePtr cur = handle->zone_dh_cur;
6861 
6862         if ((err = operation_prep(handle)) != Z_OK)
6863                 return (err);
6864 
6865         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6866                 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
6867                         continue;
6868 
6869                 xmlUnlinkNode(cur);
6870                 xmlFreeNode(cur);
6871                 return (Z_OK);
6872         }
6873         return (Z_NO_RESOURCE_ID);
6874 }
6875 
6876 int
6877 zonecfg_modify_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6878 {
6879         int err;
6880 
6881         if (tabptr == NULL)
6882                 return (Z_INVAL);
6883 
6884         err = zonecfg_delete_mcap(handle);
6885         /* it is ok if there is no mcap entry */
6886         if (err != Z_OK && err != Z_NO_RESOURCE_ID)
6887                 return (err);
6888 
6889         if ((err = add_mcap(handle, tabptr)) != Z_OK)
6890                 return (err);
6891 
6892         return (Z_OK);
6893 }
6894 
6895 int
6896 zonecfg_lookup_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6897 {
6898         xmlNodePtr cur;
6899         int err;
6900 
6901         if (tabptr == NULL)
6902                 return (Z_INVAL);
6903 
6904         if ((err = operation_prep(handle)) != Z_OK)
6905                 return (err);
6906 
6907         cur = handle->zone_dh_cur;
6908         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6909                 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
6910                         continue;
6911                 if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP,
6912                     tabptr->zone_physmem_cap,
6913                     sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
6914                         handle->zone_dh_cur = handle->zone_dh_top;
6915                         return (err);
6916                 }
6917 
6918                 return (Z_OK);



6919         }
6920 
6921         return (Z_NO_ENTRY);
6922 }
6923 
6924 static int
6925 getmcapent_core(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6926 {
6927         xmlNodePtr cur;
6928         int err;
6929 
6930         if (handle == NULL)
6931                 return (Z_INVAL);
6932 
6933         if ((cur = handle->zone_dh_cur) == NULL)
6934                 return (Z_NO_ENTRY);
6935 
6936         for (; cur != NULL; cur = cur->next)
6937                 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) == 0)
6938                         break;
6939         if (cur == NULL) {
6940                 handle->zone_dh_cur = handle->zone_dh_top;
6941                 return (Z_NO_ENTRY);
6942         }
6943 
6944         if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap,
6945             sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
6946                 handle->zone_dh_cur = handle->zone_dh_top;
6947                 return (err);


6948         }
6949 
6950         handle->zone_dh_cur = cur->next;
6951         return (Z_OK);
6952 }
6953 
6954 int
6955 zonecfg_getmcapent(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6956 {
6957         int err;
6958 
6959         if ((err = zonecfg_setent(handle)) != Z_OK)
6960                 return (err);
6961 
6962         err = getmcapent_core(handle, tabptr);
6963 
6964         (void) zonecfg_endent(handle);
6965 
6966         return (err);
6967 }
6968 
6969 /*
6970  * Get the full tree of pkg metadata in a set of nested AVL trees.
6971  * pkgs_avl is an AVL tree of pkgs.
6972  *
6973  * The zone xml data contains DTD_ELEM_PACKAGE elements.
6974  */
6975 int
6976 zonecfg_getpkgdata(zone_dochandle_t handle, uu_avl_pool_t *pkg_pool,
6977     uu_avl_t *pkgs_avl)
6978 {
6979         xmlNodePtr cur;
6980         int res;
6981         zone_pkg_entry_t *pkg;
6982         char name[MAXNAMELEN];
6983         char version[ZONE_PKG_VERSMAX];
6984 
6985         if (handle == NULL)
6986                 return (Z_INVAL);
6987 
6988         if ((res = zonecfg_setent(handle)) != Z_OK)


7614         struct stat config_st, ua_st;
7615         char config_file[MAXPATHLEN];
7616         boolean_t changed = B_FALSE;
7617         int err;
7618 
7619         if ((uaf = fopen(USERATTR_FILENAME, "r")) == NULL) {
7620                 zerror(zonename, gettext("could not open file %s: %s"),
7621                     USERATTR_FILENAME, strerror(errno));
7622                 if (errno == EACCES)
7623                         return (Z_ACCES);
7624                 if (errno == ENOENT)
7625                         return (Z_NO_ZONE);
7626                 return (Z_MISC_FS);
7627         }
7628         if ((err = fstat(fileno(uaf), &ua_st)) != 0) {
7629                 zerror(zonename, gettext("could not stat file %s: %s"),
7630                     USERATTR_FILENAME, strerror(errno));
7631                 (void) fclose(uaf);
7632                 return (Z_MISC_FS);
7633         }
7634         if (!config_file_path(zonename, config_file)) {
7635                 (void) fclose(uaf);
7636                 return (Z_MISC_FS);
7637         }
7638 
7639         if ((err = stat(config_file, &config_st)) != 0) {
7640                 zerror(zonename, gettext("could not stat file %s: %s"),
7641                     config_file, strerror(errno));
7642                 (void) fclose(uaf);
7643                 return (Z_MISC_FS);
7644         }
7645         if (config_st.st_mtime >= ua_st.st_mtime) {
7646                 (void) fclose(uaf);
7647                 return (Z_NO_ENTRY);
7648         }
7649         if ((err = zonecfg_delete_admins(handle, zonename)) == Z_OK) {
7650                 changed = B_TRUE;
7651         } else if (err != Z_NO_ENTRY) {
7652                 (void) fclose(uaf);
7653                 return (err);
7654         }




   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2014 Gary Mills
  24  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  25  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
  26  * Copyright 2015 Joyent Inc.
  27  */
  28 
  29 #include <libsysevent.h>
  30 #include <pthread.h>
  31 #include <stdlib.h>
  32 #include <errno.h>
  33 #include <fnmatch.h>
  34 #include <strings.h>
  35 #include <unistd.h>
  36 #include <assert.h>
  37 #include <libgen.h>
  38 #include <libintl.h>
  39 #include <alloca.h>
  40 #include <ctype.h>
  41 #include <sys/acl.h>
  42 #include <sys/stat.h>
  43 #include <sys/brand.h>
  44 #include <sys/mntio.h>
  45 #include <sys/mnttab.h>
  46 #include <sys/nvpair.h>
  47 #include <sys/types.h>
  48 #include <sys/sockio.h>
  49 #include <sys/systeminfo.h>
  50 #include <ftw.h>
  51 #include <pool.h>
  52 #include <libscf.h>
  53 #include <libproc.h>
  54 #include <sys/priocntl.h>
  55 #include <libuutil.h>
  56 #include <wait.h>
  57 #include <bsm/adt.h>
  58 #include <auth_attr.h>
  59 #include <auth_list.h>
  60 #include <secdb.h>
  61 #include <user_attr.h>
  62 #include <prof_attr.h>
  63 #include <sys/debug.h>
  64 #include <os_dtd.h>
  65 
  66 #include <arpa/inet.h>
  67 #include <netdb.h>
  68 
  69 #include <libxml/xmlmemory.h>
  70 #include <libxml/parser.h>
  71 
  72 #include <libdevinfo.h>
  73 #include <uuid/uuid.h>
  74 #include <dirent.h>
  75 #include <libbrand.h>
  76 
  77 #include <libzonecfg.h>
  78 #include "zonecfg_impl.h"
  79 
  80 #define _PATH_TMPFILE   "/zonecfg.XXXXXX"
  81 #define ZONE_CB_RETRY_COUNT             10
  82 #define ZONE_EVENT_PING_SUBCLASS        "ping"
  83 #define ZONE_EVENT_PING_PUBLISHER       "solaris"
  84 
  85 #define DEBUGID_FILE    "/etc/zones/did.txt"
  86 
  87 /* Hard-code the DTD element/attribute/entity names just once, here. */
  88 #define DTD_ELEM_ATTR           (const xmlChar *) "attr"
  89 #define DTD_ELEM_COMMENT        (const xmlChar *) "comment"
  90 #define DTD_ELEM_DEVICE         (const xmlChar *) "device"
  91 #define DTD_ELEM_FS             (const xmlChar *) "filesystem"
  92 #define DTD_ELEM_FSOPTION       (const xmlChar *) "fsoption"
  93 #define DTD_ELEM_NET            (const xmlChar *) "network"
  94 #define DTD_ELEM_NETATTR        (const xmlChar *) "net-attr"
  95 #define DTD_ELEM_RCTL           (const xmlChar *) "rctl"
  96 #define DTD_ELEM_RCTLVALUE      (const xmlChar *) "rctl-value"
  97 #define DTD_ELEM_ZONE           (const xmlChar *) "zone"
  98 #define DTD_ELEM_DATASET        (const xmlChar *) "dataset"
  99 #define DTD_ELEM_TMPPOOL        (const xmlChar *) "tmp_pool"
 100 #define DTD_ELEM_PSET           (const xmlChar *) "pset"
 101 #define DTD_ELEM_MCAP           (const xmlChar *) "mcap"
 102 #define DTD_ELEM_PACKAGE        (const xmlChar *) "package"
 103 #define DTD_ELEM_OBSOLETES      (const xmlChar *) "obsoletes"
 104 #define DTD_ELEM_DEV_PERM       (const xmlChar *) "dev-perm"
 105 #define DTD_ELEM_ADMIN          (const xmlChar *) "admin"
 106 
 107 #define DTD_ATTR_ACTION         (const xmlChar *) "action"
 108 #define DTD_ATTR_ADDRESS        (const xmlChar *) "address"
 109 #define DTD_ATTR_ALLOWED_ADDRESS        (const xmlChar *) "allowed-address"
 110 #define DTD_ATTR_AUTOBOOT       (const xmlChar *) "autoboot"
 111 #define DTD_ATTR_IPTYPE         (const xmlChar *) "ip-type"
 112 #define DTD_ATTR_DEFROUTER      (const xmlChar *) "defrouter"
 113 #define DTD_ATTR_DIR            (const xmlChar *) "directory"
 114 #define DTD_ATTR_GNIC           (const xmlChar *) "global-nic"
 115 #define DTD_ATTR_LIMIT          (const xmlChar *) "limit"
 116 #define DTD_ATTR_LIMITPRIV      (const xmlChar *) "limitpriv"
 117 #define DTD_ATTR_BOOTARGS       (const xmlChar *) "bootargs"
 118 #define DTD_ATTR_SCHED          (const xmlChar *) "scheduling-class"
 119 #define DTD_ATTR_MAC            (const xmlChar *) "mac-addr"
 120 #define DTD_ATTR_MATCH          (const xmlChar *) "match"
 121 #define DTD_ATTR_NAME           (const xmlChar *) "name"
 122 #define DTD_ATTR_PHYSICAL       (const xmlChar *) "physical"
 123 #define DTD_ATTR_POOL           (const xmlChar *) "pool"
 124 #define DTD_ATTR_PRIV           (const xmlChar *) "priv"
 125 #define DTD_ATTR_RAW            (const xmlChar *) "raw"
 126 #define DTD_ATTR_SPECIAL        (const xmlChar *) "special"
 127 #define DTD_ATTR_TYPE           (const xmlChar *) "type"
 128 #define DTD_ATTR_VALUE          (const xmlChar *) "value"
 129 #define DTD_ATTR_VLANID         (const xmlChar *) "vlan-id"
 130 #define DTD_ATTR_ZONEPATH       (const xmlChar *) "zonepath"
 131 #define DTD_ATTR_NCPU_MIN       (const xmlChar *) "ncpu_min"
 132 #define DTD_ATTR_NCPU_MAX       (const xmlChar *) "ncpu_max"
 133 #define DTD_ATTR_IMPORTANCE     (const xmlChar *) "importance"
 134 #define DTD_ATTR_PHYSCAP        (const xmlChar *) "physcap"
 135 #define DTD_ATTR_VERSION        (const xmlChar *) "version"
 136 #define DTD_ATTR_ID             (const xmlChar *) "id"
 137 #define DTD_ATTR_UID            (const xmlChar *) "uid"
 138 #define DTD_ATTR_GID            (const xmlChar *) "gid"
 139 #define DTD_ATTR_MODE           (const xmlChar *) "mode"
 140 #define DTD_ATTR_ACL            (const xmlChar *) "acl"
 141 #define DTD_ATTR_BRAND          (const xmlChar *) "brand"
 142 #define DTD_ATTR_DID            (const xmlChar *) "debugid"
 143 #define DTD_ATTR_HOSTID         (const xmlChar *) "hostid"
 144 #define DTD_ATTR_USER           (const xmlChar *) "user"
 145 #define DTD_ATTR_AUTHS          (const xmlChar *) "auths"
 146 #define DTD_ATTR_FS_ALLOWED     (const xmlChar *) "fs-allowed"
 147 
 148 #define DTD_ENTITY_BOOLEAN      "boolean"
 149 #define DTD_ENTITY_DEVPATH      "devpath"
 150 #define DTD_ENTITY_DRIVER       "driver"
 151 #define DTD_ENTITY_DRVMIN       "drv_min"
 152 #define DTD_ENTITY_FALSE        "false"
 153 #define DTD_ENTITY_INT          "int"
 154 #define DTD_ENTITY_STRING       "string"
 155 #define DTD_ENTITY_TRUE         "true"
 156 #define DTD_ENTITY_UINT         "uint"
 157 
 158 #define DTD_ENTITY_BOOL_LEN     6       /* "false" */
 159 
 160 #define ATTACH_FORCED   "SUNWattached.xml"
 161 
 162 #define TMP_POOL_NAME   "SUNWtmp_%s"


 169  *
 170  * This holds the alias, the full rctl name, the default priv value, action
 171  * and lower limit.  The functions that handle rctl aliases step through
 172  * this table, matching on the alias, and using the full values for setting
 173  * the rctl entry as well the limit for validation.
 174  */
 175 static struct alias {
 176         char *shortname;
 177         char *realname;
 178         char *priv;
 179         char *action;
 180         uint64_t low_limit;
 181 } aliases[] = {
 182         {ALIAS_MAXLWPS, "zone.max-lwps", "privileged", "deny", 100},
 183         {ALIAS_MAXSHMMEM, "zone.max-shm-memory", "privileged", "deny", 0},
 184         {ALIAS_MAXSHMIDS, "zone.max-shm-ids", "privileged", "deny", 0},
 185         {ALIAS_MAXMSGIDS, "zone.max-msg-ids", "privileged", "deny", 0},
 186         {ALIAS_MAXSEMIDS, "zone.max-sem-ids", "privileged", "deny", 0},
 187         {ALIAS_MAXLOCKEDMEM, "zone.max-locked-memory", "privileged", "deny", 0},
 188         {ALIAS_MAXSWAP, "zone.max-swap", "privileged", "deny", 0},
 189         {ALIAS_MAXPHYSMEM, "zone.max-physical-memory", "privileged", "deny",
 190             1048576},
 191         {ALIAS_SHARES, "zone.cpu-shares", "privileged", "none", 0},
 192         {ALIAS_CPUCAP, "zone.cpu-cap", "privileged", "deny", 0},
 193         {ALIAS_MAXPROCS, "zone.max-processes", "privileged", "deny", 100},
 194         {NULL, NULL, NULL, NULL, 0}
 195 };
 196 
 197 /*
 198  * Structure for applying rctls to a running zone.  It allows important
 199  * process values to be passed together easily.
 200  */
 201 typedef struct pr_info_handle {
 202         struct ps_prochandle *pr;
 203         pid_t pid;
 204 } pr_info_handle_t;
 205 
 206 struct zone_dochandle {
 207         char            *zone_dh_rootdir;
 208         xmlDocPtr       zone_dh_doc;
 209         xmlNodePtr      zone_dh_cur;
 210         xmlNodePtr      zone_dh_top;


 264 }
 265 
 266 const char *
 267 zonecfg_get_root(void)
 268 {
 269         return (zonecfg_root);
 270 }
 271 
 272 boolean_t
 273 zonecfg_in_alt_root(void)
 274 {
 275         return (*zonecfg_root != '\0');
 276 }
 277 
 278 /*
 279  * Callers of the _file_path() functions are expected to have the second
 280  * parameter be a (char foo[MAXPATHLEN]).
 281  */
 282 
 283 static boolean_t
 284 file_path_common(const char *zonename, const char *subdir, const char *stem,
 285     char *answer, size_t answer_size)
 286 {
 287         const char *native_root = zone_get_nroot();
 288 
 289         if (native_root == NULL || zonecfg_in_alt_root()) {
 290                 /*
 291                  * Do not prepend the native system root (e.g. "/native") if an
 292                  * alternative configuration root has been selected.
 293                  */
 294                 native_root = "";
 295         }
 296 
 297         return (snprintf(answer, answer_size, "%s%s%s/%s.%s", native_root,
 298             zonecfg_root, subdir, zonename, stem) < answer_size);
 299 }
 300 
 301 static boolean_t
 302 config_file_path(const char *zonename, char *answer, size_t answer_size)
 303 {
 304         return (file_path_common(zonename, ZONE_CONFIG_ROOT, "xml", answer,
 305             answer_size));
 306 }
 307 
 308 static boolean_t
 309 snap_file_path(const char *zonename, char *answer, size_t answer_size)
 310 {
 311         return (file_path_common(zonename, ZONE_SNAPSHOT_ROOT, "snapshot.xml",
 312             answer, answer_size));
 313 }
 314 
 315 /*ARGSUSED*/
 316 static void
 317 zonecfg_error_func(void *ctx, const char *msg, ...)
 318 {
 319         /*
 320          * This function does nothing by design.  Its purpose is to prevent
 321          * libxml from dumping unwanted messages to stdout/stderr.
 322          */
 323 }
 324 
 325 zone_dochandle_t
 326 zonecfg_init_handle(void)
 327 {
 328         zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle));
 329         if (handle == NULL) {
 330                 errno = Z_NOMEM;
 331                 return (NULL);
 332         }
 333 
 334         /* generic libxml initialization */


 363 zonecfg_destroy_impl(char *filename)
 364 {
 365         if (unlink(filename) == -1) {
 366                 if (errno == EACCES)
 367                         return (Z_ACCES);
 368                 if (errno == ENOENT)
 369                         return (Z_NO_ZONE);
 370                 return (Z_MISC_FS);
 371         }
 372         return (Z_OK);
 373 }
 374 
 375 int
 376 zonecfg_destroy(const char *zonename, boolean_t force)
 377 {
 378         char path[MAXPATHLEN];
 379         struct zoneent ze;
 380         int err, state_err;
 381         zone_state_t state;
 382 
 383         if (!config_file_path(zonename, path, sizeof (path)))
 384                 return (Z_MISC_FS);
 385 
 386         state_err = zone_get_state((char *)zonename, &state);
 387         err = access(path, W_OK);
 388 
 389         /*
 390          * If there is no file, and no index entry, reliably indicate that no
 391          * such zone exists.
 392          */
 393         if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT))
 394                 return (Z_NO_ZONE);
 395 
 396         /*
 397          * Handle any other filesystem related errors (except if the XML
 398          * file is missing, which we treat silently), unless we're forcing,
 399          * in which case we plow on.
 400          */
 401         if (err == -1 && errno != ENOENT) {
 402                 if (errno == EACCES)
 403                         return (Z_ACCES);


 420         if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK)
 421                 if (!force)
 422                         return (err);
 423 
 424         err = zonecfg_destroy_impl(path);
 425 
 426         /*
 427          * Treat failure to find the XML file silently, since, well, it's
 428          * gone, and with the index file cleaned up, we're done.
 429          */
 430         if (err == Z_OK || err == Z_NO_ZONE)
 431                 return (Z_OK);
 432         return (err);
 433 }
 434 
 435 int
 436 zonecfg_destroy_snapshot(const char *zonename)
 437 {
 438         char path[MAXPATHLEN];
 439 
 440         if (!snap_file_path(zonename, path, sizeof (path)))
 441                 return (Z_MISC_FS);
 442         return (zonecfg_destroy_impl(path));
 443 }
 444 
 445 static int
 446 getroot(zone_dochandle_t handle, xmlNodePtr *root)
 447 {
 448         if (zonecfg_check_handle(handle) == Z_BAD_HANDLE)
 449                 return (Z_BAD_HANDLE);
 450 
 451         *root = xmlDocGetRootElement(handle->zone_dh_doc);
 452 
 453         if (*root == NULL)
 454                 return (Z_EMPTY_DOCUMENT);
 455 
 456         if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE))
 457                 return (Z_WRONG_DOC_TYPE);
 458 
 459         return (Z_OK);
 460 }


 587 {
 588         xmlNodePtr root, child, next;
 589 
 590         root = xmlDocGetRootElement(handle->zone_dh_doc);
 591         for (child = root->xmlChildrenNode; child != NULL; child = next) {
 592                 next = child->next;
 593                 if (child->name == NULL)
 594                         continue;
 595                 if (xmlStrcmp(child->name, DTD_ELEM_PACKAGE) == 0) {
 596                         next = child->next;
 597                         xmlUnlinkNode(child);
 598                         xmlFreeNode(child);
 599                 }
 600         }
 601 }
 602 
 603 static int
 604 zonecfg_get_handle_impl(const char *zonename, const char *filename,
 605     zone_dochandle_t handle)
 606 {

 607         struct stat statbuf;
 608         boolean_t valid;
 609 
 610         if (zonename == NULL)
 611                 return (Z_NO_ZONE);
 612 
 613         if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) {
 614                 /* distinguish file not found vs. found but not parsed */
 615                 if (stat(filename, &statbuf) == 0)
 616                         return (Z_INVALID_DOCUMENT);
 617                 return (Z_NO_ZONE);
 618         }
 619 
 620         if (os_dtd_validate(handle->zone_dh_doc, B_FALSE, &valid) != 0) {
 621                 return (Z_NOMEM);
 622         }
 623         if (!valid) {



 624                 return (Z_INVALID_DOCUMENT);
 625         }
 626 
 627         /* delete any comments such as inherited Sun copyright / ident str */
 628         stripcomments(handle);
 629         return (Z_OK);
 630 }
 631 
 632 int
 633 zonecfg_get_handle(const char *zonename, zone_dochandle_t handle)
 634 {
 635         char path[MAXPATHLEN];
 636 
 637         if (!config_file_path(zonename, path, sizeof (path)))
 638                 return (Z_MISC_FS);
 639         handle->zone_dh_newzone = B_FALSE;
 640 
 641         return (zonecfg_get_handle_impl(zonename, path, handle));
 642 }
 643 
 644 int
 645 zonecfg_get_attach_handle(const char *path, const char *fname,
 646     const char *zonename, boolean_t preserve_sw, zone_dochandle_t handle)
 647 {
 648         char            migpath[MAXPATHLEN];
 649         int             err;
 650         struct stat     buf;
 651 
 652         if (snprintf(migpath, sizeof (migpath), "%s/root", path) >=
 653             sizeof (migpath))
 654                 return (Z_NOMEM);
 655 
 656         if (stat(migpath, &buf) == -1 || !S_ISDIR(buf.st_mode))
 657                 return (Z_NO_ZONE);


 661                 return (Z_NOMEM);
 662 
 663         if ((err = zonecfg_get_handle_impl(zonename, migpath, handle)) != Z_OK)
 664                 return (err);
 665 
 666         if (!preserve_sw)
 667                 strip_sw_inv(handle);
 668 
 669         handle->zone_dh_newzone = B_TRUE;
 670         if ((err = setrootattr(handle, DTD_ATTR_ZONEPATH, path)) != Z_OK)
 671                 return (err);
 672 
 673         return (setrootattr(handle, DTD_ATTR_NAME, zonename));
 674 }
 675 
 676 int
 677 zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle)
 678 {
 679         char path[MAXPATHLEN];
 680 
 681         if (!snap_file_path(zonename, path, sizeof (path)))
 682                 return (Z_MISC_FS);
 683         handle->zone_dh_newzone = B_FALSE;
 684         return (zonecfg_get_handle_impl(zonename, path, handle));
 685 }
 686 
 687 int
 688 zonecfg_get_template_handle(const char *template, const char *zonename,
 689     zone_dochandle_t handle)
 690 {
 691         char path[MAXPATHLEN];
 692         int err;
 693 
 694         if (!config_file_path(template, path, sizeof (path)))
 695                 return (Z_MISC_FS);
 696 
 697         if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK)
 698                 return (err);
 699         handle->zone_dh_newzone = B_TRUE;
 700         return (setrootattr(handle, DTD_ATTR_NAME, zonename));
 701 }
 702 
 703 int
 704 zonecfg_get_xml_handle(const char *path, zone_dochandle_t handle)
 705 {
 706         struct stat buf;
 707         int err;
 708 
 709         if (stat(path, &buf) == -1)
 710                 return (Z_MISC_FS);
 711 
 712         if ((err = zonecfg_get_handle_impl("xml", path, handle)) != Z_OK)
 713                 return (err);
 714         handle->zone_dh_newzone = B_TRUE;
 715         return (Z_OK);
 716 }
 717 
 718 /*
 719  * Initialize two handles from the manifest read on fd.  The rem_handle
 720  * is initialized from the input file, including the sw inventory.  The
 721  * local_handle is initialized with the same zone configuration but with
 722  * no sw inventory.
 723  */
 724 int
 725 zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle,
 726     zone_dochandle_t rem_handle)
 727 {
 728         boolean_t valid;

 729 
 730         /* load the manifest into the handle for the remote system */
 731         if ((rem_handle->zone_dh_doc = xmlReadFd(fd, NULL, NULL, 0)) == NULL) {
 732                 return (Z_INVALID_DOCUMENT);
 733         }
 734 
 735         if (os_dtd_validate(rem_handle->zone_dh_doc, B_FALSE, &valid) != 0) {
 736                 return (Z_NOMEM);
 737         }
 738         if (!valid) {



 739                 return (Z_INVALID_DOCUMENT);
 740         }
 741 
 742         /* delete any comments such as inherited Sun copyright / ident str */
 743         stripcomments(rem_handle);
 744 
 745         rem_handle->zone_dh_newzone = B_TRUE;
 746         rem_handle->zone_dh_sw_inv = B_TRUE;
 747 
 748         /*
 749          * Now use the remote system handle to generate a local system handle
 750          * with an identical zones configuration but no sw inventory.
 751          */
 752         if ((local_handle->zone_dh_doc = xmlCopyDoc(rem_handle->zone_dh_doc,
 753             1)) == NULL) {
 754                 return (Z_INVALID_DOCUMENT);
 755         }
 756 
 757         /*
 758          * We need to re-run xmlValidateDocument on local_handle to properly
 759          * update the in-core representation of the configuration.
 760          */
 761         if (os_dtd_validate(local_handle->zone_dh_doc, B_FALSE, &valid) != 0) {
 762                 return (Z_NOMEM);
 763         }
 764         if (!valid) {



 765                 return (Z_INVALID_DOCUMENT);
 766         }
 767 
 768         strip_sw_inv(local_handle);
 769 
 770         local_handle->zone_dh_newzone = B_TRUE;
 771         local_handle->zone_dh_sw_inv = B_FALSE;
 772 
 773         return (Z_OK);
 774 }
 775 
 776 static boolean_t
 777 is_renaming(zone_dochandle_t handle)
 778 {
 779         if (handle->zone_dh_newzone)
 780                 return (B_FALSE);
 781         if (strlen(handle->zone_dh_delete_name) > 0)
 782                 return (B_TRUE);
 783         return (B_FALSE);
 784 }
 785 
 786 static boolean_t


1200  * Save existing zone 'foo':
1201  *      Make backup of foo.xml -> .backup
1202  *      Create tmpfile (zonecfg.xxxxxx)
1203  *      Write XML to tmpfile
1204  *      Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
1205  *      Modify index file as needed
1206  *      If it fails, recover from .backup -> foo.xml
1207  *
1208  * Rename 'foo' to 'bar':
1209  *      Create tmpfile (zonecfg.xxxxxx)
1210  *      Write XML to tmpfile
1211  *      Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml)
1212  *      Add entry for 'bar' to index file, Remove entry for 'foo' (refresh)
1213  *      If it fails, delete bar.xml; foo.xml is left behind.
1214  */
1215 static int
1216 zonecfg_save_impl(zone_dochandle_t handle, char *filename)
1217 {
1218         char tmpfile[MAXPATHLEN];
1219         char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN];
1220         int tmpfd, err;

1221         boolean_t backup;
1222         boolean_t valid;
1223 
1224         (void) strlcpy(tmpfile, filename, sizeof (tmpfile));
1225         (void) dirname(tmpfile);
1226         (void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile));
1227 
1228         tmpfd = mkstemp(tmpfile);
1229         if (tmpfd == -1) {
1230                 (void) unlink(tmpfile);
1231                 return (Z_TEMP_FILE);
1232         }
1233         (void) close(tmpfd);
1234 



1235         /*
1236          * We do a final validation of the document.  Since the library has
1237          * malfunctioned if it fails to validate, we follow-up with an
1238          * assert() that the doc is valid.
1239          */
1240         VERIFY0(os_dtd_validate(handle->zone_dh_doc, B_FALSE, &valid));
1241         VERIFY(valid == B_TRUE);
1242 
1243         if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0)
1244                 goto err;
1245 
1246         (void) chmod(tmpfile, 0644);
1247 
1248         /*
1249          * In the event we are doing a standard save, hard link a copy of the
1250          * original file in .backup.<pid>.filename so we can restore it if
1251          * something goes wrong.
1252          */
1253         if (!is_new(handle) && !is_renaming(handle)) {
1254                 backup = B_TRUE;
1255 
1256                 (void) strlcpy(bakdir, filename, sizeof (bakdir));
1257                 (void) strlcpy(bakbase, filename, sizeof (bakbase));
1258                 (void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s",
1259                     dirname(bakdir), getpid(), basename(bakbase));
1260 
1261                 if (link(filename, bakfile) == -1) {


1276                 (void) unlink(tmpfile);
1277                 if (backup)
1278                         (void) unlink(bakfile);
1279                 if (err == EACCES)
1280                         return (Z_ACCES);
1281                 return (Z_MISC_FS);
1282         }
1283 
1284         /*
1285          * If this is a snapshot, we're done-- don't add an index entry.
1286          */
1287         if (is_snapshot(handle))
1288                 return (Z_OK);
1289 
1290         /* now update the index file to reflect whatever we just did */
1291         if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) {
1292                 if (backup) {
1293                         /*
1294                          * Try to restore from our backup.
1295                          */

1296                         (void) rename(bakfile, filename);
1297                 } else {
1298                         /*
1299                          * Either the zone is new, in which case we can delete
1300                          * new.xml, or we're doing a rename, so ditto.
1301                          */
1302                         assert(is_new(handle) || is_renaming(handle));
1303                         (void) unlink(filename);
1304                 }
1305                 return (Z_UPDATING_INDEX);
1306         }
1307 
1308         if (backup)
1309                 (void) unlink(bakfile);
1310 
1311         return (Z_OK);
1312 
1313 err:
1314         (void) unlink(tmpfile);
1315         return (Z_SAVING_FILE);


1318 int
1319 zonecfg_save(zone_dochandle_t handle)
1320 {
1321         char zname[ZONENAME_MAX], path[MAXPATHLEN];
1322         char delpath[MAXPATHLEN];
1323         int err = Z_SAVING_FILE;
1324 
1325         if (zonecfg_check_handle(handle) != Z_OK)
1326                 return (Z_BAD_HANDLE);
1327 
1328         /*
1329          * We don't support saving snapshots or a tree containing a sw
1330          * inventory at this time.
1331          */
1332         if (handle->zone_dh_snapshot || handle->zone_dh_sw_inv)
1333                 return (Z_INVAL);
1334 
1335         if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK)
1336                 return (err);
1337 
1338         if (!config_file_path(zname, path, sizeof (path)))
1339                 return (Z_MISC_FS);
1340 
1341         addcomment(handle, "\n    DO NOT EDIT THIS "
1342             "FILE.  Use zonecfg(1M) instead.\n");
1343 
1344         /*
1345          * Update user_attr first so that it will be older
1346          * than the config file.
1347          */
1348         (void) zonecfg_authorize_users(handle, zname);
1349         err = zonecfg_save_impl(handle, path);
1350 
1351         stripcomments(handle);
1352 
1353         if (err != Z_OK)
1354                 return (err);
1355 
1356         handle->zone_dh_newzone = B_FALSE;
1357 
1358         if (is_renaming(handle)) {
1359                 if (config_file_path(handle->zone_dh_delete_name, delpath,
1360                     sizeof (delpath))) {
1361                         (void) unlink(delpath);
1362                 }
1363                 handle->zone_dh_delete_name[0] = '\0';
1364         }
1365 
1366         return (Z_OK);
1367 }
1368 
1369 int
1370 zonecfg_verify_save(zone_dochandle_t handle, char *filename)
1371 {
1372         boolean_t valid;
1373 


1374         if (zonecfg_check_handle(handle) != Z_OK)
1375                 return (Z_BAD_HANDLE);
1376 



1377         /*
1378          * We do a final validation of the document.  Since the library has
1379          * malfunctioned if it fails to validate, we follow-up with an
1380          * assert() that the doc is valid.
1381          */
1382         VERIFY0(os_dtd_validate(handle->zone_dh_doc, B_FALSE, &valid));
1383         VERIFY(valid == B_TRUE);
1384 
1385         if (xmlSaveFormatFile(filename, handle->zone_dh_doc, 1) <= 0)
1386                 return (Z_SAVING_FILE);
1387 
1388         return (Z_OK);
1389 }
1390 
1391 int
1392 zonecfg_detach_save(zone_dochandle_t handle, uint_t flags)
1393 {
1394         char zname[ZONENAME_MAX];
1395         char path[MAXPATHLEN];
1396         char migpath[MAXPATHLEN];

1397         int err = Z_SAVING_FILE;
1398         boolean_t valid;
1399 
1400         if (zonecfg_check_handle(handle) != Z_OK)
1401                 return (Z_BAD_HANDLE);
1402 
1403         if (flags & ZONE_DRY_RUN) {
1404                 (void) strlcpy(migpath, "-", sizeof (migpath));
1405         } else {
1406                 if ((err = zonecfg_get_name(handle, zname, sizeof (zname)))
1407                     != Z_OK)
1408                         return (err);
1409 
1410                 if ((err = zone_get_zonepath(zname, path, sizeof (path)))
1411                     != Z_OK)
1412                         return (err);
1413 
1414                 if (snprintf(migpath, sizeof (migpath), "%s/%s", path,
1415                     ZONE_DETACHED) >= sizeof (migpath))
1416                         return (Z_NOMEM);
1417         }
1418 
1419         if ((err = operation_prep(handle)) != Z_OK)
1420                 return (err);
1421 
1422         addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
1423             "Use zonecfg(1M) and zoneadm(1M) attach.\n");
1424 



1425         /*
1426          * We do a final validation of the document.  Since the library has
1427          * malfunctioned if it fails to validate, we follow-up with an
1428          * assert() that the doc is valid.
1429          */
1430         VERIFY0(os_dtd_validate(handle->zone_dh_doc, B_FALSE, &valid));
1431         VERIFY(valid == B_TRUE);
1432 
1433         if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0)
1434                 return (Z_SAVING_FILE);
1435 
1436         if (!(flags & ZONE_DRY_RUN))
1437                 (void) chmod(migpath, 0644);
1438 
1439         stripcomments(handle);
1440 
1441         handle->zone_dh_newzone = B_FALSE;
1442 
1443         return (Z_OK);
1444 }
1445 
1446 boolean_t
1447 zonecfg_detached(const char *path)
1448 {
1449         char            migpath[MAXPATHLEN];
1450         struct stat     buf;
1451 


1484         if (forced) {
1485                 (void) rename(detached, attached);
1486         } else {
1487                 (void) unlink(attached);
1488                 (void) unlink(detached);
1489         }
1490 }
1491 
1492 /*
1493  * Special case: if access(2) fails with ENOENT, then try again using
1494  * ZONE_CONFIG_ROOT instead of config_file_path(zonename).  This is how we
1495  * work around the case of a config file which has not been created yet:
1496  * the user will need access to the directory so use that as a heuristic.
1497  */
1498 
1499 int
1500 zonecfg_access(const char *zonename, int amode)
1501 {
1502         char path[MAXPATHLEN];
1503 
1504         if (!config_file_path(zonename, path, sizeof (path)))
1505                 return (Z_INVAL);
1506         if (access(path, amode) == 0)
1507                 return (Z_OK);
1508         if (errno == ENOENT) {
1509                 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1510                     ZONE_CONFIG_ROOT) >= sizeof (path))
1511                         return (Z_INVAL);
1512                 if (access(path, amode) == 0)
1513                         return (Z_OK);
1514         }
1515         if (errno == EACCES)
1516                 return (Z_ACCES);
1517         if (errno == EINVAL)
1518                 return (Z_INVAL);
1519         return (Z_MISC_FS);
1520 }
1521 
1522 int
1523 zonecfg_create_snapshot(const char *zonename)
1524 {


1549          * save the resolved path in the snapshot, thus preventing any
1550          * potential problems down the line when zoneadmd goes to unmount
1551          * file systems and depends on initial string matches with resolved
1552          * paths.
1553          */
1554         rpath[res] = '\0';
1555         if (strcmp(zonepath, rpath) != 0) {
1556                 if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK)
1557                         goto out;
1558         }
1559         if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1560             ZONE_SNAPSHOT_ROOT) >= sizeof (path)) {
1561                 error = Z_MISC_FS;
1562                 goto out;
1563         }
1564         if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) {
1565                 error = Z_MISC_FS;
1566                 goto out;
1567         }
1568 
1569         if (!snap_file_path(zonename, path, sizeof (path))) {
1570                 error = Z_MISC_FS;
1571                 goto out;
1572         }
1573 
1574         addcomment(handle, "\n    DO NOT EDIT THIS FILE.  "
1575             "It is a snapshot of running zone state.\n");
1576 
1577         error = zonecfg_save_impl(handle, path);
1578 
1579         stripcomments(handle);
1580 
1581 out:
1582         zonecfg_fini_handle(handle);
1583         return (error);
1584 }
1585 
1586 int
1587 zonecfg_get_iptype(zone_dochandle_t handle, zone_iptype_t *iptypep)
1588 {
1589         char property[10]; /* 10 is big enough for "shared"/"exclusive" */


2080 
2081 /*
2082  * Determines whether there is a net resource with the physical interface, IP
2083  * address, and default router specified by 'tabptr' in the zone configuration
2084  * to which 'handle' refers.  'tabptr' must have an interface, an address, a
2085  * default router, or a combination of the three.  This function returns Z_OK
2086  * iff there is exactly one net resource matching the query specified by
2087  * 'tabptr'.  The function returns Z_INSUFFICIENT_SPEC if there are multiple
2088  * matches or 'tabptr' does not specify a physical interface, address, or
2089  * default router.  The function returns Z_NO_RESOURCE_ID if are no matches.
2090  *
2091  * Errors might also be returned if the entry that exactly matches the
2092  * query lacks critical network resource information.
2093  *
2094  * If there is a single match, then the matching entry's physical interface, IP
2095  * address, and default router information are stored in 'tabptr'.
2096  */
2097 int
2098 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2099 {
2100         xmlNodePtr cur, val;
2101         xmlNodePtr firstmatch;
2102         int err;
2103         char address[INET6_ADDRSTRLEN];
2104         char physical[LIFNAMSIZ];
2105         char mac[MAXMACADDRLEN];
2106         char gnic[LIFNAMSIZ];
2107         size_t addrspec;                /* nonzero if tabptr has IP addr */
2108         size_t physspec;                /* nonzero if tabptr has interface */
2109         size_t macspec;                 /* nonzero if tabptr has mac addr */
2110         size_t gnicspec;                /* nonzero if tabptr has gnic */
2111         size_t defrouterspec;           /* nonzero if tabptr has def. router */
2112         size_t allowed_addrspec;
2113         zone_iptype_t iptype;
2114 
2115         if (tabptr == NULL)
2116                 return (Z_INVAL);
2117 
2118         /*
2119          * Determine the fields that will be searched.  There must be at least
2120          * one.
2121          *
2122          * zone_nwif_address, zone_nwif_physical, zone_nwif_defrouter,
2123          * zone_nwif_mac, zone_nwif_vlan_id and zone_nwif_gnic  are
2124          * arrays, so no NULL checks are necessary.
2125          */
2126         addrspec = strlen(tabptr->zone_nwif_address);
2127         physspec = strlen(tabptr->zone_nwif_physical);
2128         macspec = strlen(tabptr->zone_nwif_mac);
2129         gnicspec = strlen(tabptr->zone_nwif_gnic);
2130         defrouterspec = strlen(tabptr->zone_nwif_defrouter);
2131         allowed_addrspec = strlen(tabptr->zone_nwif_allowed_address);
2132         if (addrspec != 0 && allowed_addrspec != 0)
2133                 return (Z_INVAL); /* can't specify both */
2134         if (addrspec == 0 && physspec == 0 && defrouterspec == 0 &&
2135             allowed_addrspec == 0 && macspec == 0 && gnicspec == 0)
2136                 return (Z_INSUFFICIENT_SPEC);
2137 
2138         if ((err = operation_prep(handle)) != Z_OK)
2139                 return (err);
2140 
2141         if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK)
2142                 return (err);
2143         /*
2144          * Iterate over the configuration's elements and look for net elements
2145          * that match the query.
2146          */
2147         firstmatch = NULL;
2148         cur = handle->zone_dh_cur;
2149         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2150                 /* Skip non-net elements */
2151                 if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2152                         continue;
2153 
2154                 /*
2155                  * If any relevant fields don't match the query, then skip
2156                  * the current net element.
2157                  */
2158                 if (physspec != 0 && (fetchprop(cur, DTD_ATTR_PHYSICAL,
2159                     physical, sizeof (physical)) != Z_OK ||
2160                     strcmp(tabptr->zone_nwif_physical, physical) != 0))
2161                         continue;
2162                 if (iptype == ZS_EXCLUSIVE && macspec != 0 &&
2163                     (fetchprop(cur, DTD_ATTR_MAC, mac, sizeof (mac)) != Z_OK ||
2164                     strcmp(tabptr->zone_nwif_mac, mac) != 0))
2165                         continue;
2166                 if (iptype == ZS_EXCLUSIVE && gnicspec != 0 &&
2167                     (fetchprop(cur, DTD_ATTR_GNIC, gnic,
2168                     sizeof (gnic)) != Z_OK ||
2169                     strcmp(tabptr->zone_nwif_gnic, gnic) != 0))
2170                         continue;
2171                 if (iptype == ZS_SHARED && addrspec != 0 &&
2172                     (fetchprop(cur, DTD_ATTR_ADDRESS, address,
2173                     sizeof (address)) != Z_OK ||
2174                     !zonecfg_same_net_address(tabptr->zone_nwif_address,
2175                     address)))
2176                         continue;
2177                 if (iptype == ZS_EXCLUSIVE && allowed_addrspec != 0 &&
2178                     (fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS, address,
2179                     sizeof (address)) != Z_OK ||
2180                     !zonecfg_same_net_address(tabptr->zone_nwif_allowed_address,
2181                     address)))
2182                         continue;
2183                 if (defrouterspec != 0 && (fetchprop(cur, DTD_ATTR_DEFROUTER,
2184                     address, sizeof (address)) != Z_OK ||
2185                     !zonecfg_same_net_address(tabptr->zone_nwif_defrouter,
2186                     address)))
2187                         continue;
2188 
2189                 /*
2190                  * The current net element matches the query.  Select it if


2193                 if (firstmatch == NULL)
2194                         firstmatch = cur;
2195                 else
2196                         return (Z_INSUFFICIENT_SPEC);
2197         }
2198         if (firstmatch == NULL)
2199                 return (Z_NO_RESOURCE_ID);
2200 
2201         cur = firstmatch;
2202 
2203         if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
2204             sizeof (tabptr->zone_nwif_physical))) != Z_OK)
2205                 return (err);
2206 
2207         if (iptype == ZS_SHARED &&
2208             (err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
2209             sizeof (tabptr->zone_nwif_address))) != Z_OK)
2210                 return (err);
2211 
2212         if (iptype == ZS_EXCLUSIVE &&
2213             (err = fetchprop(cur, DTD_ATTR_MAC, tabptr->zone_nwif_mac,
2214             sizeof (tabptr->zone_nwif_mac))) != Z_OK)
2215                 return (err);
2216 
2217         if (iptype == ZS_EXCLUSIVE &&
2218             (err = fetchprop(cur, DTD_ATTR_VLANID, tabptr->zone_nwif_vlan_id,
2219             sizeof (tabptr->zone_nwif_vlan_id))) != Z_OK)
2220                 return (err);
2221 
2222         if (iptype == ZS_EXCLUSIVE &&
2223             (err = fetchprop(cur, DTD_ATTR_GNIC, tabptr->zone_nwif_gnic,
2224             sizeof (tabptr->zone_nwif_gnic))) != Z_OK)
2225                 return (err);
2226 
2227         if (iptype == ZS_EXCLUSIVE &&
2228             (err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
2229             tabptr->zone_nwif_allowed_address,
2230             sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK)
2231                 return (err);
2232 
2233         if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
2234             tabptr->zone_nwif_defrouter,
2235             sizeof (tabptr->zone_nwif_defrouter))) != Z_OK)
2236                 return (err);
2237 
2238         tabptr->zone_nwif_attrp = NULL;
2239         for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
2240                 struct zone_res_attrtab *valptr;
2241 
2242                 valptr = (struct zone_res_attrtab *)malloc(
2243                     sizeof (struct zone_res_attrtab));
2244                 if (valptr == NULL)
2245                         return (Z_NOMEM);
2246 
2247                 valptr->zone_res_attr_name[0] =
2248                     valptr->zone_res_attr_value[0] = '\0';
2249                 if (zonecfg_add_res_attr(&(tabptr->zone_nwif_attrp), valptr)
2250                     != Z_OK) {
2251                         free(valptr);
2252                         break;
2253                 }
2254 
2255                 if ((fetchprop(val, DTD_ATTR_NAME, valptr->zone_res_attr_name,
2256                     sizeof (valptr->zone_res_attr_name)) != Z_OK))
2257                         break;
2258                 if ((fetchprop(val, DTD_ATTR_VALUE,
2259                     valptr->zone_res_attr_value,
2260                     sizeof (valptr->zone_res_attr_value)) != Z_OK))
2261                         break;
2262         }
2263 
2264         return (Z_OK);
2265 }
2266 
2267 static int
2268 zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2269 {
2270         xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode;
2271         struct zone_res_attrtab *valptr;
2272         int err;
2273 
2274         newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL);
2275         if (strlen(tabptr->zone_nwif_address) > 0 &&
2276             (err = newprop(newnode, DTD_ATTR_ADDRESS,
2277             tabptr->zone_nwif_address)) != Z_OK)
2278                 return (err);
2279         if (strlen(tabptr->zone_nwif_allowed_address) > 0 &&
2280             (err = newprop(newnode, DTD_ATTR_ALLOWED_ADDRESS,
2281             tabptr->zone_nwif_allowed_address)) != Z_OK)
2282                 return (err);
2283         if ((err = newprop(newnode, DTD_ATTR_PHYSICAL,
2284             tabptr->zone_nwif_physical)) != Z_OK)
2285                 return (err);
2286         /*
2287          * Do not add these properties when they are not set, for backwards
2288          * compatibility and because they are optional.
2289          */
2290         if ((strlen(tabptr->zone_nwif_defrouter) > 0) &&
2291             ((err = newprop(newnode, DTD_ATTR_DEFROUTER,
2292             tabptr->zone_nwif_defrouter)) != Z_OK))
2293                 return (err);
2294         if (strlen(tabptr->zone_nwif_mac) > 0 &&
2295             (err = newprop(newnode, DTD_ATTR_MAC,
2296             tabptr->zone_nwif_mac)) != Z_OK)
2297                 return (err);
2298         if (strlen(tabptr->zone_nwif_vlan_id) > 0 &&
2299             (err = newprop(newnode, DTD_ATTR_VLANID,
2300             tabptr->zone_nwif_vlan_id)) != Z_OK)
2301                 return (err);
2302         if (strlen(tabptr->zone_nwif_gnic) > 0 &&
2303             (err = newprop(newnode, DTD_ATTR_GNIC,
2304             tabptr->zone_nwif_gnic)) != Z_OK)
2305                 return (err);
2306 
2307         for (valptr = tabptr->zone_nwif_attrp; valptr != NULL;
2308             valptr = valptr->zone_res_attr_next) {
2309                 valnode = xmlNewTextChild(newnode, NULL, DTD_ELEM_NETATTR,
2310                     NULL);
2311                 err = newprop(valnode, DTD_ATTR_NAME,
2312                     valptr->zone_res_attr_name);
2313                 if (err != Z_OK)
2314                         return (err);
2315                 err = newprop(valnode, DTD_ATTR_VALUE,
2316                     valptr->zone_res_attr_value);
2317                 if (err != Z_OK)
2318                         return (err);
2319         }
2320 
2321         return (Z_OK);
2322 }
2323 
2324 int
2325 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2326 {
2327         int err;
2328 
2329         if (tabptr == NULL)
2330                 return (Z_INVAL);
2331 
2332         if ((err = operation_prep(handle)) != Z_OK)
2333                 return (err);
2334 
2335         if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK)
2336                 return (err);
2337 
2338         return (Z_OK);
2339 }
2340 
2341 static int
2342 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2343 {
2344         xmlNodePtr cur = handle->zone_dh_cur;
2345         boolean_t addr_match, phys_match, allowed_addr_match, mac_match,
2346             gnic_match;
2347 
2348         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2349                 if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2350                         continue;
2351 
2352                 addr_match = match_prop(cur, DTD_ATTR_ADDRESS,
2353                     tabptr->zone_nwif_address);
2354                 allowed_addr_match = match_prop(cur, DTD_ATTR_ALLOWED_ADDRESS,
2355                     tabptr->zone_nwif_allowed_address);
2356                 phys_match = match_prop(cur, DTD_ATTR_PHYSICAL,
2357                     tabptr->zone_nwif_physical);
2358                 mac_match = match_prop(cur, DTD_ATTR_MAC,
2359                     tabptr->zone_nwif_mac);
2360                 gnic_match = match_prop(cur, DTD_ATTR_GNIC,
2361                     tabptr->zone_nwif_gnic);
2362 
2363                 if ((addr_match || allowed_addr_match || mac_match ||
2364                     gnic_match) && phys_match) {
2365                         xmlUnlinkNode(cur);
2366                         xmlFreeNode(cur);
2367                         return (Z_OK);
2368                 }
2369         }
2370         return (Z_NO_RESOURCE_ID);
2371 }
2372 
2373 int
2374 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2375 {
2376         int err;
2377 
2378         if (tabptr == NULL)
2379                 return (Z_INVAL);
2380 
2381         if ((err = operation_prep(handle)) != Z_OK)
2382                 return (err);
2383 
2384         if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK)


2393         struct zone_nwiftab *oldtabptr,
2394         struct zone_nwiftab *newtabptr)
2395 {
2396         int err;
2397 
2398         if (oldtabptr == NULL || newtabptr == NULL)
2399                 return (Z_INVAL);
2400 
2401         if ((err = operation_prep(handle)) != Z_OK)
2402                 return (err);
2403 
2404         if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK)
2405                 return (err);
2406 
2407         if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK)
2408                 return (err);
2409 
2410         return (Z_OK);
2411 }
2412 
2413 void
2414 zonecfg_free_res_attr_list(struct zone_res_attrtab *valtab)
2415 {
2416         if (valtab == NULL)
2417                 return;
2418         zonecfg_free_res_attr_list(valtab->zone_res_attr_next);
2419         free(valtab);
2420 }
2421 
2422 int
2423 zonecfg_add_res_attr(struct zone_res_attrtab **headptr,
2424     struct zone_res_attrtab *valtabptr)
2425 {
2426         struct zone_res_attrtab *last, *old, *new;
2427 
2428         last = *headptr;
2429         for (old = last; old != NULL; old = old->zone_res_attr_next)
2430                 last = old;     /* walk to the end of the list */
2431         new = valtabptr;        /* alloc'd by caller */
2432         new->zone_res_attr_next = NULL;
2433         if (last == NULL)
2434                 *headptr = new;
2435         else
2436                 last->zone_res_attr_next = new;
2437         return (Z_OK);
2438 }
2439 
2440 int
2441 zonecfg_remove_res_attr(struct zone_res_attrtab **headptr,
2442     struct zone_res_attrtab *valtabptr)
2443 {
2444         struct zone_res_attrtab *last, *this, *next;
2445 
2446         last = *headptr;
2447         for (this = last; this != NULL; this = this->zone_res_attr_next) {
2448                 if (strcmp(this->zone_res_attr_name,
2449                     valtabptr->zone_res_attr_name) == 0 &&
2450                     strcmp(this->zone_res_attr_value,
2451                     valtabptr->zone_res_attr_value) == 0) {
2452                         next = this->zone_res_attr_next;
2453                         if (this == *headptr)
2454                                 *headptr = next;
2455                         else
2456                                 last->zone_res_attr_next = next;
2457                         free(this);
2458                         return (Z_OK);
2459                 } else
2460                         last = this;
2461         }
2462         return (Z_NO_PROPERTY_ID);
2463 }
2464 
2465 /*
2466  * Must be a comma-separated list of alpha-numeric file system names.
2467  */
2468 static int
2469 zonecfg_valid_fs_allowed(const char *fsallowedp)
2470 {
2471         char tmp[ZONE_FS_ALLOWED_MAX];
2472         char *cp = tmp;
2473         char *p;
2474 
2475         if (strlen(fsallowedp) > ZONE_FS_ALLOWED_MAX)
2476                 return (Z_TOO_BIG);
2477 
2478         (void) strlcpy(tmp, fsallowedp, sizeof (tmp));
2479 
2480         while (*cp != '\0') {
2481                 p = cp;
2482                 while (*p != '\0' && *p != ',') {
2483                         if (!isalnum(*p) && *p != '-')
2484                                 return (Z_INVALID_PROPERTY);


2594  * attribute is cleared.  Non-NULL hostids are validated.  This function returns
2595  * Z_OK on success.  Any other return value indicates failure.
2596  */
2597 int
2598 zonecfg_set_hostid(zone_dochandle_t handle, const char *hostidp)
2599 {
2600         int err;
2601 
2602         /*
2603          * A NULL hostid string is interpreted as a request to clear the
2604          * hostid.
2605          */
2606         if (hostidp == NULL || (err = zonecfg_valid_hostid(hostidp)) == Z_OK)
2607                 return (setrootattr(handle, DTD_ATTR_HOSTID, hostidp));
2608         return (err);
2609 }
2610 
2611 int
2612 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2613 {
2614         xmlNodePtr cur, val, firstmatch;
2615         int err;
2616         char match[MAXPATHLEN];
2617 
2618         if (tabptr == NULL)
2619                 return (Z_INVAL);
2620 
2621         if ((err = operation_prep(handle)) != Z_OK)
2622                 return (err);
2623 
2624         cur = handle->zone_dh_cur;
2625         firstmatch = NULL;
2626         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2627                 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2628                         continue;
2629                 if (strlen(tabptr->zone_dev_match) == 0)
2630                         continue;
2631 
2632                 if ((fetchprop(cur, DTD_ATTR_MATCH, match,
2633                     sizeof (match)) == Z_OK)) {
2634                         if (strcmp(tabptr->zone_dev_match,


2639                                         return (Z_INSUFFICIENT_SPEC);
2640                         } else {
2641                                 /*
2642                                  * If another property matched but this
2643                                  * one doesn't then reset firstmatch.
2644                                  */
2645                                 if (firstmatch == cur)
2646                                         firstmatch = NULL;
2647                         }
2648                 }
2649         }
2650         if (firstmatch == NULL)
2651                 return (Z_NO_RESOURCE_ID);
2652 
2653         cur = firstmatch;
2654 
2655         if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
2656             sizeof (tabptr->zone_dev_match))) != Z_OK)
2657                 return (err);
2658 
2659         tabptr->zone_dev_attrp = NULL;
2660         for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
2661                 struct zone_res_attrtab *valptr;
2662 
2663                 valptr = (struct zone_res_attrtab *)malloc(
2664                     sizeof (struct zone_res_attrtab));
2665                 if (valptr == NULL)
2666                         return (Z_NOMEM);
2667 
2668                 valptr->zone_res_attr_name[0] =
2669                     valptr->zone_res_attr_value[0] = '\0';
2670                 if (zonecfg_add_res_attr(&(tabptr->zone_dev_attrp), valptr)
2671                     != Z_OK) {
2672                         free(valptr);
2673                         break;
2674                 }
2675 
2676                 if ((fetchprop(val, DTD_ATTR_NAME, valptr->zone_res_attr_name,
2677                     sizeof (valptr->zone_res_attr_name)) != Z_OK))
2678                         break;
2679                 if ((fetchprop(val, DTD_ATTR_VALUE,
2680                     valptr->zone_res_attr_value,
2681                     sizeof (valptr->zone_res_attr_value)) != Z_OK))
2682                         break;
2683         }
2684 
2685         return (Z_OK);
2686 }
2687 
2688 static int
2689 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
2690 {
2691         xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode;
2692         struct zone_res_attrtab *valptr;
2693         int err;
2694 
2695         newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL);
2696 
2697         if ((err = newprop(newnode, DTD_ATTR_MATCH,
2698             tabptr->zone_dev_match)) != Z_OK)
2699                 return (err);
2700 
2701         for (valptr = tabptr->zone_dev_attrp; valptr != NULL;
2702             valptr = valptr->zone_res_attr_next) {
2703                 valnode = xmlNewTextChild(newnode, NULL, DTD_ELEM_NETATTR,
2704                     NULL);
2705                 err = newprop(valnode, DTD_ATTR_NAME,
2706                     valptr->zone_res_attr_name);
2707                 if (err != Z_OK)
2708                         return (err);
2709                 err = newprop(valnode, DTD_ATTR_VALUE,
2710                     valptr->zone_res_attr_value);
2711                 if (err != Z_OK)
2712                         return (err);
2713         }
2714 
2715 
2716         return (Z_OK);
2717 }
2718 
2719 int
2720 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2721 {
2722         int err;
2723 
2724         if (tabptr == NULL)
2725                 return (Z_INVAL);
2726 
2727         if ((err = operation_prep(handle)) != Z_OK)
2728                 return (err);
2729 
2730         if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK)
2731                 return (err);
2732 
2733         return (Z_OK);
2734 }
2735 


4893 
4894         handle->zone_dh_cur = cur->next;
4895         return (Z_OK);
4896 }
4897 
4898 int
4899 zonecfg_endfsent(zone_dochandle_t handle)
4900 {
4901         return (zonecfg_endent(handle));
4902 }
4903 
4904 int
4905 zonecfg_setnwifent(zone_dochandle_t handle)
4906 {
4907         return (zonecfg_setent(handle));
4908 }
4909 
4910 int
4911 zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
4912 {
4913         xmlNodePtr cur, val;
4914         struct zone_res_attrtab *valptr;
4915         int err;
4916 
4917         if (handle == NULL)
4918                 return (Z_INVAL);
4919 
4920         if ((cur = handle->zone_dh_cur) == NULL)
4921                 return (Z_NO_ENTRY);
4922 
4923         for (; cur != NULL; cur = cur->next)
4924                 if (!xmlStrcmp(cur->name, DTD_ELEM_NET))
4925                         break;
4926         if (cur == NULL) {
4927                 handle->zone_dh_cur = handle->zone_dh_top;
4928                 return (Z_NO_ENTRY);
4929         }
4930 
4931         if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
4932             sizeof (tabptr->zone_nwif_address))) != Z_OK) {
4933                 handle->zone_dh_cur = handle->zone_dh_top;
4934                 return (err);
4935         }
4936 
4937         if ((err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
4938             tabptr->zone_nwif_allowed_address,
4939             sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK) {
4940                 handle->zone_dh_cur = handle->zone_dh_top;
4941                 return (err);
4942         }
4943 
4944         if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
4945             sizeof (tabptr->zone_nwif_physical))) != Z_OK) {
4946                 handle->zone_dh_cur = handle->zone_dh_top;
4947                 return (err);
4948         }
4949 
4950         if ((err = fetchprop(cur, DTD_ATTR_MAC, tabptr->zone_nwif_mac,
4951             sizeof (tabptr->zone_nwif_mac))) != Z_OK) {
4952                 handle->zone_dh_cur = handle->zone_dh_top;
4953                 return (err);
4954         }
4955 
4956         if ((err = fetchprop(cur, DTD_ATTR_VLANID, tabptr->zone_nwif_vlan_id,
4957             sizeof (tabptr->zone_nwif_vlan_id))) != Z_OK) {
4958                 handle->zone_dh_cur = handle->zone_dh_top;
4959                 return (err);
4960         }
4961 
4962         if ((err = fetchprop(cur, DTD_ATTR_GNIC, tabptr->zone_nwif_gnic,
4963             sizeof (tabptr->zone_nwif_gnic))) != Z_OK) {
4964                 handle->zone_dh_cur = handle->zone_dh_top;
4965                 return (err);
4966         }
4967 
4968         if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
4969             tabptr->zone_nwif_defrouter,
4970             sizeof (tabptr->zone_nwif_defrouter))) != Z_OK) {
4971                 handle->zone_dh_cur = handle->zone_dh_top;
4972                 return (err);
4973         }
4974 
4975         tabptr->zone_nwif_attrp = NULL;
4976         for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
4977                 valptr = (struct zone_res_attrtab *)malloc(
4978                     sizeof (struct zone_res_attrtab));
4979                 if (valptr == NULL)
4980                         return (Z_NOMEM);
4981 
4982                 valptr->zone_res_attr_name[0] =
4983                     valptr->zone_res_attr_value[0] = '\0';
4984                 if (zonecfg_add_res_attr(&(tabptr->zone_nwif_attrp), valptr)
4985                     != Z_OK) {
4986                         free(valptr);
4987                         break;
4988                 }
4989 
4990                 if (fetchprop(val, DTD_ATTR_NAME, valptr->zone_res_attr_name,
4991                     sizeof (valptr->zone_res_attr_name)) != Z_OK)
4992                         break;
4993                 if (fetchprop(val, DTD_ATTR_VALUE, valptr->zone_res_attr_value,
4994                     sizeof (valptr->zone_res_attr_value)) != Z_OK)
4995                         break;
4996         }
4997 
4998         handle->zone_dh_cur = cur->next;
4999         return (Z_OK);
5000 }
5001 
5002 int
5003 zonecfg_endnwifent(zone_dochandle_t handle)
5004 {
5005         return (zonecfg_endent(handle));
5006 }
5007 
5008 int
5009 zonecfg_setdevent(zone_dochandle_t handle)
5010 {
5011         return (zonecfg_setent(handle));
5012 }
5013 
5014 int
5015 zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr)
5016 {
5017         xmlNodePtr cur, val;
5018         int err;
5019 
5020         if (handle == NULL)
5021                 return (Z_INVAL);
5022 
5023         if ((cur = handle->zone_dh_cur) == NULL)
5024                 return (Z_NO_ENTRY);
5025 
5026         for (; cur != NULL; cur = cur->next)
5027                 if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
5028                         break;
5029         if (cur == NULL) {
5030                 handle->zone_dh_cur = handle->zone_dh_top;
5031                 return (Z_NO_ENTRY);
5032         }
5033 
5034         if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
5035             sizeof (tabptr->zone_dev_match))) != Z_OK) {
5036                 handle->zone_dh_cur = handle->zone_dh_top;
5037                 return (err);
5038         }
5039 
5040         tabptr->zone_dev_attrp = NULL;
5041         for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
5042                 struct zone_res_attrtab *valptr;
5043 
5044                 valptr = (struct zone_res_attrtab *)malloc(
5045                     sizeof (struct zone_res_attrtab));
5046                 if (valptr == NULL)
5047                         return (Z_NOMEM);
5048 
5049                 valptr->zone_res_attr_name[0] =
5050                     valptr->zone_res_attr_value[0] = '\0';
5051                 if (zonecfg_add_res_attr(&(tabptr->zone_dev_attrp), valptr)
5052                     != Z_OK) {
5053                         free(valptr);
5054                         break;
5055                 }
5056 
5057                 if ((fetchprop(val, DTD_ATTR_NAME, valptr->zone_res_attr_name,
5058                     sizeof (valptr->zone_res_attr_name)) != Z_OK))
5059                         break;
5060                 if ((fetchprop(val, DTD_ATTR_VALUE, valptr->zone_res_attr_value,
5061                     sizeof (valptr->zone_res_attr_value)) != Z_OK))
5062                         break;
5063         }
5064 
5065         handle->zone_dh_cur = cur->next;
5066         return (Z_OK);
5067 }
5068 
5069 int
5070 zonecfg_enddevent(zone_dochandle_t handle)
5071 {
5072         return (zonecfg_endent(handle));
5073 }
5074 
5075 int
5076 zonecfg_setrctlent(zone_dochandle_t handle)
5077 {
5078         return (zonecfg_setent(handle));
5079 }
5080 
5081 int
5082 zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr)
5083 {
5084         xmlNodePtr cur, val;


5773                         return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL);
5774 
5775                 return (Z_OK);
5776         }
5777 
5778         if (strcmp(zone_name, "global") == 0)
5779                 return (zonecfg_default_brand(brandname, rp_sz));
5780 
5781         if ((handle = zonecfg_init_handle()) == NULL)
5782                 return (Z_NOMEM);
5783 
5784         err = zonecfg_get_handle((char *)zone_name, handle);
5785         if (err == Z_OK)
5786                 err = zonecfg_get_brand(handle, brandname, rp_sz);
5787 
5788         zonecfg_fini_handle(handle);
5789         return (err);
5790 }
5791 
5792 /*
5793  * Atomically get a new zone_did value.  The currently allocated value
5794  * is stored in /etc/zones/did.txt.  Lock the file, read the current value,
5795  * increment, save the new value and unlock the file.  Return the new value
5796  * or -1 if there was an error.  The ID namespace is large enough that we
5797  * don't worry about recycling an ID when a zone is deleted.
5798  */
5799 static zoneid_t
5800 new_zone_did()
5801 {
5802         int fd;
5803         int len;
5804         int val;
5805         struct flock lck;
5806         char buf[80];
5807 
5808         if ((fd = open(DEBUGID_FILE, O_RDWR | O_CREAT,
5809             S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
5810                 perror("new_zone_did open failed");
5811                 return (-1);
5812         }
5813 
5814         /* Initialize the lock. */
5815         lck.l_whence = SEEK_SET;
5816         lck.l_start = 0;
5817         lck.l_len = 0;
5818 
5819         /* Wait until we acquire an exclusive lock on the file. */
5820         lck.l_type = F_WRLCK;
5821         if (fcntl(fd, F_SETLKW, &lck) == -1) {
5822                 perror("new_zone_did lock failed");
5823                 (void) close(fd);
5824                 return (-1);
5825         }
5826 
5827         /* Get currently allocated value */
5828         len = read(fd, buf, sizeof (buf));
5829         if (len == -1) {
5830                 perror("new_zone_did read failed");
5831                 val = -1;
5832         } else {
5833                 if (lseek(fd, 0L, SEEK_SET) == -1) {
5834                         perror("new_zone_did seek failed");
5835                         val = -1;
5836                 } else {
5837                         if (len == 0) {
5838                                 /* Just created the file, initialize at 1 */
5839                                 val = 1;
5840                         } else {
5841                                 val = atoi(buf);
5842                                 val++;
5843                         }
5844 
5845                         (void) snprintf(buf, sizeof (buf), "%d\n", val);
5846                         len = strlen(buf);
5847 
5848                         /* Save newly allocated value */
5849                         if (write(fd, buf, len) == -1) {
5850                                 perror("new_zone_did write failed");
5851                                 val = -1;
5852                         }
5853                 }
5854         }
5855 
5856         /* Release the file lock. */
5857         lck.l_type = F_UNLCK;
5858         if (fcntl(fd, F_SETLK, &lck) == -1) {
5859                 perror("new_zone_did unlock failed");
5860                 val = -1;
5861         }
5862 
5863         if (close(fd) != 0)
5864                 perror("new_zone_did close failed");
5865 
5866         return (val);
5867 }
5868 
5869 /*
5870  * Called by zoneadmd to get the zone's debug ID.
5871  * If the zone doesn't already have an ID, a new one is generated and
5872  * persistently saved onto the zone.  Normally either zoneadm or zonecfg
5873  * will assign a new ID for the zone, so zoneadmd should never have to
5874  * generate one, but we also handle that here just to be paranoid.
5875  */
5876 zoneid_t
5877 zone_get_did(char *zone_name)
5878 {
5879         int res;
5880         zoneid_t new_did;
5881         zone_dochandle_t handle;
5882         char did_str[80];
5883 
5884         if ((handle = zonecfg_init_handle()) == NULL)
5885                 return (getpid());
5886 
5887         if (zonecfg_get_handle((char *)zone_name, handle) != Z_OK)
5888                 return (getpid());
5889 
5890         res = getrootattr(handle, DTD_ATTR_DID, did_str, sizeof (did_str));
5891 
5892         /* If the zone already has an assigned debug ID, return it. */
5893         if (res == Z_OK && did_str[0] != '\0') {
5894                 zonecfg_fini_handle(handle);
5895                 return (atoi(did_str));
5896         }
5897 
5898         /*
5899          * The zone doesn't have an assigned debug ID yet, generate one and
5900          * save it as part of the zone definition.
5901          */
5902         if ((new_did = new_zone_did()) == -1) {
5903                 /*
5904                  * We should really never hit this block of code.
5905                  * Generating a new ID failed for some reason.  Use the current
5906                  * pid as a temporary ID so that the zone can continue to boot
5907                  * but we don't persistently save this temporary ID on the zone.
5908                  */
5909                 zonecfg_fini_handle(handle);
5910                 return (getpid());
5911         }
5912 
5913         /* Now persistently save this new ID onto the zone. */
5914         (void) snprintf(did_str, sizeof (did_str), "%d", new_did);
5915         (void) setrootattr(handle, DTD_ATTR_DID, did_str);
5916         (void) zonecfg_save(handle);
5917 
5918         zonecfg_fini_handle(handle);
5919         return (new_did);
5920 }
5921 
5922 zoneid_t
5923 zonecfg_get_did(zone_dochandle_t handle)
5924 {
5925         char did_str[80];
5926         int err;
5927         zoneid_t did;
5928 
5929         err = getrootattr(handle, DTD_ATTR_DID, did_str, sizeof (did_str));
5930         if (err == Z_OK && did_str[0] != '\0')
5931                 did = atoi(did_str);
5932         else
5933                 did = -1;
5934 
5935         return (did);
5936 }
5937 
5938 void
5939 zonecfg_set_did(zone_dochandle_t handle)
5940 {
5941         zoneid_t new_did;
5942         char did_str[80];
5943 
5944         if ((new_did = new_zone_did()) == -1)
5945                 return;
5946         (void) snprintf(did_str, sizeof (did_str), "%d", new_did);
5947         (void) setrootattr(handle, DTD_ATTR_DID, did_str);
5948 }
5949 
5950 /*
5951  * Return the appropriate root for the active /dev.
5952  * For normal zone, the path is $ZONEPATH/root;
5953  * for scratch zone, the dev path is $ZONEPATH/lu.
5954  */
5955 int
5956 zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz)
5957 {
5958         int err;
5959         char *suffix;
5960         zone_state_t state;
5961 
5962         /* This function makes sense for non-global zones only. */
5963         if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
5964                 return (Z_BOGUS_ZONE_NAME);
5965         if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK)
5966                 return (err);
5967 
5968         if (zone_get_state(zone_name, &state) == Z_OK &&
5969             state == ZONE_STATE_MOUNTED)
5970                 suffix = "/lu";


7245         }
7246 
7247         return (res);
7248 }
7249 
7250 int
7251 zonecfg_getpsetent(zone_dochandle_t handle, struct zone_psettab *tabptr)
7252 {
7253         int err;
7254 
7255         if ((err = zonecfg_setent(handle)) != Z_OK)
7256                 return (err);
7257 
7258         err = zonecfg_lookup_pset(handle, tabptr);
7259 
7260         (void) zonecfg_endent(handle);
7261 
7262         return (err);
7263 }
7264 
7265 /*
7266  * Cleanup obsolete constructs in the configuration.
7267  * Return true of the config has been updated and must be commited.
7268  */










7269 int
7270 zonecfg_fix_obsolete(zone_dochandle_t handle)
7271 {
7272         int res = 0;
7273         int add_physmem_rctl = 0;





































7274         xmlNodePtr cur;
7275         char    zone_physmem_cap[MAXNAMELEN];
7276 
7277         if (operation_prep(handle) != Z_OK)
7278                 return (res);
7279 
7280         /*
7281          * If an obsolete mcap entry exists, convert it to the rctl.
7282          */
7283         cur = handle->zone_dh_cur;
7284         for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
7285                 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
7286                         continue;






7287 
7288                 if (fetchprop(cur, DTD_ATTR_PHYSCAP,
7289                     zone_physmem_cap, sizeof (zone_physmem_cap)) == Z_OK) {
7290                         res = 1;
7291                         add_physmem_rctl = 1;
7292                 }
7293 
7294                 xmlUnlinkNode(cur);
7295                 xmlFreeNode(cur);















7296                 break;



7297         }
7298 
7299         if (add_physmem_rctl) {
7300                 uint64_t cap;
7301                 char *endp;
7302 
7303                 cap = strtoull(zone_physmem_cap, &endp, 10);
7304                 (void) zonecfg_set_aliased_rctl(handle, ALIAS_MAXPHYSMEM, cap);
7305         }
7306 
7307         return (res);

7308 }
7309 















7310 /*
7311  * Get the full tree of pkg metadata in a set of nested AVL trees.
7312  * pkgs_avl is an AVL tree of pkgs.
7313  *
7314  * The zone xml data contains DTD_ELEM_PACKAGE elements.
7315  */
7316 int
7317 zonecfg_getpkgdata(zone_dochandle_t handle, uu_avl_pool_t *pkg_pool,
7318     uu_avl_t *pkgs_avl)
7319 {
7320         xmlNodePtr cur;
7321         int res;
7322         zone_pkg_entry_t *pkg;
7323         char name[MAXNAMELEN];
7324         char version[ZONE_PKG_VERSMAX];
7325 
7326         if (handle == NULL)
7327                 return (Z_INVAL);
7328 
7329         if ((res = zonecfg_setent(handle)) != Z_OK)


7955         struct stat config_st, ua_st;
7956         char config_file[MAXPATHLEN];
7957         boolean_t changed = B_FALSE;
7958         int err;
7959 
7960         if ((uaf = fopen(USERATTR_FILENAME, "r")) == NULL) {
7961                 zerror(zonename, gettext("could not open file %s: %s"),
7962                     USERATTR_FILENAME, strerror(errno));
7963                 if (errno == EACCES)
7964                         return (Z_ACCES);
7965                 if (errno == ENOENT)
7966                         return (Z_NO_ZONE);
7967                 return (Z_MISC_FS);
7968         }
7969         if ((err = fstat(fileno(uaf), &ua_st)) != 0) {
7970                 zerror(zonename, gettext("could not stat file %s: %s"),
7971                     USERATTR_FILENAME, strerror(errno));
7972                 (void) fclose(uaf);
7973                 return (Z_MISC_FS);
7974         }
7975         if (!config_file_path(zonename, config_file, sizeof (config_file))) {
7976                 (void) fclose(uaf);
7977                 return (Z_MISC_FS);
7978         }
7979 
7980         if ((err = stat(config_file, &config_st)) != 0) {
7981                 zerror(zonename, gettext("could not stat file %s: %s"),
7982                     config_file, strerror(errno));
7983                 (void) fclose(uaf);
7984                 return (Z_MISC_FS);
7985         }
7986         if (config_st.st_mtime >= ua_st.st_mtime) {
7987                 (void) fclose(uaf);
7988                 return (Z_NO_ENTRY);
7989         }
7990         if ((err = zonecfg_delete_admins(handle, zonename)) == Z_OK) {
7991                 changed = B_TRUE;
7992         } else if (err != Z_NO_ENTRY) {
7993                 (void) fclose(uaf);
7994                 return (err);
7995         }