10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51507Sgjelinek * Common Development and Distribution License (the "License").
61507Sgjelinek * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
211645Scomay
220Sstevel@tonic-gate /*
2312582SGlenn.Faden@Sun.COM * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
261166Sdstaff #include <libsysevent.h>
271166Sdstaff #include <pthread.h>
281166Sdstaff #include <stdlib.h>
290Sstevel@tonic-gate #include <errno.h>
300Sstevel@tonic-gate #include <fnmatch.h>
310Sstevel@tonic-gate #include <strings.h>
320Sstevel@tonic-gate #include <unistd.h>
330Sstevel@tonic-gate #include <assert.h>
340Sstevel@tonic-gate #include <libgen.h>
350Sstevel@tonic-gate #include <libintl.h>
360Sstevel@tonic-gate #include <alloca.h>
370Sstevel@tonic-gate #include <ctype.h>
382712Snn35248 #include <sys/acl.h>
392712Snn35248 #include <sys/stat.h>
402712Snn35248 #include <sys/brand.h>
410Sstevel@tonic-gate #include <sys/mntio.h>
420Sstevel@tonic-gate #include <sys/mnttab.h>
432712Snn35248 #include <sys/nvpair.h>
44565Sdp #include <sys/types.h>
453448Sdh155122 #include <sys/sockio.h>
468662SJordan.Vaughan@Sun.com #include <sys/systeminfo.h>
471507Sgjelinek #include <ftw.h>
483247Sgjelinek #include <pool.h>
493247Sgjelinek #include <libscf.h>
503247Sgjelinek #include <libproc.h>
513247Sgjelinek #include <sys/priocntl.h>
524229Sgjelinek #include <libuutil.h>
537089Sgjelinek #include <wait.h>
547089Sgjelinek #include <bsm/adt.h>
5512578SGlenn.Faden@Sun.COM #include <auth_attr.h>
5612578SGlenn.Faden@Sun.COM #include <auth_list.h>
5712578SGlenn.Faden@Sun.COM #include <secdb.h>
5812578SGlenn.Faden@Sun.COM #include <user_attr.h>
5912578SGlenn.Faden@Sun.COM #include <prof_attr.h>
600Sstevel@tonic-gate
610Sstevel@tonic-gate #include <arpa/inet.h>
620Sstevel@tonic-gate #include <netdb.h>
630Sstevel@tonic-gate
640Sstevel@tonic-gate #include <libxml/xmlmemory.h>
650Sstevel@tonic-gate #include <libxml/parser.h>
660Sstevel@tonic-gate
670Sstevel@tonic-gate #include <libdevinfo.h>
68766Scarlsonj #include <uuid/uuid.h>
691507Sgjelinek #include <dirent.h>
702712Snn35248 #include <libbrand.h>
711507Sgjelinek
720Sstevel@tonic-gate #include <libzonecfg.h>
730Sstevel@tonic-gate #include "zonecfg_impl.h"
740Sstevel@tonic-gate
750Sstevel@tonic-gate #define _PATH_TMPFILE "/zonecfg.XXXXXX"
761166Sdstaff #define ZONE_CB_RETRY_COUNT 10
771166Sdstaff #define ZONE_EVENT_PING_SUBCLASS "ping"
781166Sdstaff #define ZONE_EVENT_PING_PUBLISHER "solaris"
790Sstevel@tonic-gate
800Sstevel@tonic-gate /* Hard-code the DTD element/attribute/entity names just once, here. */
810Sstevel@tonic-gate #define DTD_ELEM_ATTR (const xmlChar *) "attr"
820Sstevel@tonic-gate #define DTD_ELEM_COMMENT (const xmlChar *) "comment"
830Sstevel@tonic-gate #define DTD_ELEM_DEVICE (const xmlChar *) "device"
840Sstevel@tonic-gate #define DTD_ELEM_FS (const xmlChar *) "filesystem"
850Sstevel@tonic-gate #define DTD_ELEM_FSOPTION (const xmlChar *) "fsoption"
860Sstevel@tonic-gate #define DTD_ELEM_NET (const xmlChar *) "network"
870Sstevel@tonic-gate #define DTD_ELEM_RCTL (const xmlChar *) "rctl"
880Sstevel@tonic-gate #define DTD_ELEM_RCTLVALUE (const xmlChar *) "rctl-value"
890Sstevel@tonic-gate #define DTD_ELEM_ZONE (const xmlChar *) "zone"
90789Sahrens #define DTD_ELEM_DATASET (const xmlChar *) "dataset"
913247Sgjelinek #define DTD_ELEM_TMPPOOL (const xmlChar *) "tmp_pool"
923247Sgjelinek #define DTD_ELEM_PSET (const xmlChar *) "pset"
933247Sgjelinek #define DTD_ELEM_MCAP (const xmlChar *) "mcap"
941507Sgjelinek #define DTD_ELEM_PACKAGE (const xmlChar *) "package"
951507Sgjelinek #define DTD_ELEM_PATCH (const xmlChar *) "patch"
965829Sgjelinek #define DTD_ELEM_OBSOLETES (const xmlChar *) "obsoletes"
971507Sgjelinek #define DTD_ELEM_DEV_PERM (const xmlChar *) "dev-perm"
9812578SGlenn.Faden@Sun.COM #define DTD_ELEM_ADMIN (const xmlChar *) "admin"
990Sstevel@tonic-gate
1000Sstevel@tonic-gate #define DTD_ATTR_ACTION (const xmlChar *) "action"
1010Sstevel@tonic-gate #define DTD_ATTR_ADDRESS (const xmlChar *) "address"
10212748SSowmini.Varadhan@oracle.COM #define DTD_ATTR_ALLOWED_ADDRESS (const xmlChar *) "allowed-address"
1030Sstevel@tonic-gate #define DTD_ATTR_AUTOBOOT (const xmlChar *) "autoboot"
1043448Sdh155122 #define DTD_ATTR_IPTYPE (const xmlChar *) "ip-type"
1056076Sgfaden #define DTD_ATTR_DEFROUTER (const xmlChar *) "defrouter"
1060Sstevel@tonic-gate #define DTD_ATTR_DIR (const xmlChar *) "directory"
1070Sstevel@tonic-gate #define DTD_ATTR_LIMIT (const xmlChar *) "limit"
1081645Scomay #define DTD_ATTR_LIMITPRIV (const xmlChar *) "limitpriv"
1092267Sdp #define DTD_ATTR_BOOTARGS (const xmlChar *) "bootargs"
1103247Sgjelinek #define DTD_ATTR_SCHED (const xmlChar *) "scheduling-class"
1110Sstevel@tonic-gate #define DTD_ATTR_MATCH (const xmlChar *) "match"
1120Sstevel@tonic-gate #define DTD_ATTR_NAME (const xmlChar *) "name"
1130Sstevel@tonic-gate #define DTD_ATTR_PHYSICAL (const xmlChar *) "physical"
1140Sstevel@tonic-gate #define DTD_ATTR_POOL (const xmlChar *) "pool"
1150Sstevel@tonic-gate #define DTD_ATTR_PRIV (const xmlChar *) "priv"
1160Sstevel@tonic-gate #define DTD_ATTR_RAW (const xmlChar *) "raw"
1170Sstevel@tonic-gate #define DTD_ATTR_SPECIAL (const xmlChar *) "special"
1180Sstevel@tonic-gate #define DTD_ATTR_TYPE (const xmlChar *) "type"
1190Sstevel@tonic-gate #define DTD_ATTR_VALUE (const xmlChar *) "value"
1200Sstevel@tonic-gate #define DTD_ATTR_ZONEPATH (const xmlChar *) "zonepath"
1213247Sgjelinek #define DTD_ATTR_NCPU_MIN (const xmlChar *) "ncpu_min"
1223247Sgjelinek #define DTD_ATTR_NCPU_MAX (const xmlChar *) "ncpu_max"
1233247Sgjelinek #define DTD_ATTR_IMPORTANCE (const xmlChar *) "importance"
1243247Sgjelinek #define DTD_ATTR_PHYSCAP (const xmlChar *) "physcap"
1251507Sgjelinek #define DTD_ATTR_VERSION (const xmlChar *) "version"
1261507Sgjelinek #define DTD_ATTR_ID (const xmlChar *) "id"
1271507Sgjelinek #define DTD_ATTR_UID (const xmlChar *) "uid"
1281507Sgjelinek #define DTD_ATTR_GID (const xmlChar *) "gid"
1291507Sgjelinek #define DTD_ATTR_MODE (const xmlChar *) "mode"
1301507Sgjelinek #define DTD_ATTR_ACL (const xmlChar *) "acl"
1312712Snn35248 #define DTD_ATTR_BRAND (const xmlChar *) "brand"
1328662SJordan.Vaughan@Sun.com #define DTD_ATTR_HOSTID (const xmlChar *) "hostid"
13312578SGlenn.Faden@Sun.COM #define DTD_ATTR_USER (const xmlChar *) "user"
13412578SGlenn.Faden@Sun.COM #define DTD_ATTR_AUTHS (const xmlChar *) "auths"
13512633Sjohn.levon@sun.com #define DTD_ATTR_FS_ALLOWED (const xmlChar *) "fs-allowed"
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate #define DTD_ENTITY_BOOLEAN "boolean"
1380Sstevel@tonic-gate #define DTD_ENTITY_DEVPATH "devpath"
1390Sstevel@tonic-gate #define DTD_ENTITY_DRIVER "driver"
1400Sstevel@tonic-gate #define DTD_ENTITY_DRVMIN "drv_min"
1410Sstevel@tonic-gate #define DTD_ENTITY_FALSE "false"
1420Sstevel@tonic-gate #define DTD_ENTITY_INT "int"
1430Sstevel@tonic-gate #define DTD_ENTITY_STRING "string"
1440Sstevel@tonic-gate #define DTD_ENTITY_TRUE "true"
1450Sstevel@tonic-gate #define DTD_ENTITY_UINT "uint"
1460Sstevel@tonic-gate
147228Sdp #define DTD_ENTITY_BOOL_LEN 6 /* "false" */
148228Sdp
1491507Sgjelinek #define ATTACH_FORCED "SUNWattached.xml"
1501507Sgjelinek
1513247Sgjelinek #define TMP_POOL_NAME "SUNWtmp_%s"
1523247Sgjelinek #define MAX_TMP_POOL_NAME (ZONENAME_MAX + 9)
1533247Sgjelinek #define RCAP_SERVICE "system/rcap:default"
1543247Sgjelinek #define POOLD_SERVICE "system/pools/dynamic:default"
1553247Sgjelinek
1563247Sgjelinek /*
1573247Sgjelinek * rctl alias definitions
1583247Sgjelinek *
1593247Sgjelinek * This holds the alias, the full rctl name, the default priv value, action
1603247Sgjelinek * and lower limit. The functions that handle rctl aliases step through
1613247Sgjelinek * this table, matching on the alias, and using the full values for setting
1623247Sgjelinek * the rctl entry as well the limit for validation.
1633247Sgjelinek */
1643247Sgjelinek static struct alias {
1653247Sgjelinek char *shortname;
1663247Sgjelinek char *realname;
1673247Sgjelinek char *priv;
1683247Sgjelinek char *action;
1693247Sgjelinek uint64_t low_limit;
1703247Sgjelinek } aliases[] = {
1713247Sgjelinek {ALIAS_MAXLWPS, "zone.max-lwps", "privileged", "deny", 100},
1723247Sgjelinek {ALIAS_MAXSHMMEM, "zone.max-shm-memory", "privileged", "deny", 0},
1733247Sgjelinek {ALIAS_MAXSHMIDS, "zone.max-shm-ids", "privileged", "deny", 0},
1743247Sgjelinek {ALIAS_MAXMSGIDS, "zone.max-msg-ids", "privileged", "deny", 0},
1753247Sgjelinek {ALIAS_MAXSEMIDS, "zone.max-sem-ids", "privileged", "deny", 0},
1763247Sgjelinek {ALIAS_MAXLOCKEDMEM, "zone.max-locked-memory", "privileged", "deny", 0},
1773247Sgjelinek {ALIAS_MAXSWAP, "zone.max-swap", "privileged", "deny", 0},
1783247Sgjelinek {ALIAS_SHARES, "zone.cpu-shares", "privileged", "none", 0},
1793792Sakolb {ALIAS_CPUCAP, "zone.cpu-cap", "privileged", "deny", 0},
18012725SMenno.Lageman@Sun.COM {ALIAS_MAXPROCS, "zone.max-processes", "privileged", "deny", 100},
1813247Sgjelinek {NULL, NULL, NULL, NULL, 0}
1823247Sgjelinek };
1833247Sgjelinek
1843247Sgjelinek /*
1853247Sgjelinek * Structure for applying rctls to a running zone. It allows important
1863247Sgjelinek * process values to be passed together easily.
1873247Sgjelinek */
1883247Sgjelinek typedef struct pr_info_handle {
1893247Sgjelinek struct ps_prochandle *pr;
1903247Sgjelinek pid_t pid;
1913247Sgjelinek } pr_info_handle_t;
1923247Sgjelinek
1930Sstevel@tonic-gate struct zone_dochandle {
1940Sstevel@tonic-gate char *zone_dh_rootdir;
1950Sstevel@tonic-gate xmlDocPtr zone_dh_doc;
1960Sstevel@tonic-gate xmlNodePtr zone_dh_cur;
1970Sstevel@tonic-gate xmlNodePtr zone_dh_top;
198565Sdp boolean_t zone_dh_newzone;
199565Sdp boolean_t zone_dh_snapshot;
2001507Sgjelinek boolean_t zone_dh_sw_inv;
20112578SGlenn.Faden@Sun.COM zone_userauths_t *zone_dh_userauths;
202565Sdp char zone_dh_delete_name[ZONENAME_MAX];
2030Sstevel@tonic-gate };
2040Sstevel@tonic-gate
2051166Sdstaff struct znotify {
2061166Sdstaff void * zn_private;
2071166Sdstaff evchan_t *zn_eventchan;
2081166Sdstaff int (*zn_callback)(const char *zonename, zoneid_t zid,
2091166Sdstaff const char *newstate, const char *oldstate, hrtime_t when, void *p);
2101166Sdstaff pthread_mutex_t zn_mutex;
2111166Sdstaff pthread_cond_t zn_cond;
2121166Sdstaff pthread_mutex_t zn_bigmutex;
2131166Sdstaff volatile enum {ZN_UNLOCKED, ZN_LOCKED, ZN_PING_INFLIGHT,
2141166Sdstaff ZN_PING_RECEIVED} zn_state;
2151166Sdstaff char zn_subscriber_id[MAX_SUBID_LEN];
2161166Sdstaff volatile boolean_t zn_failed;
2171166Sdstaff int zn_failure_count;
2181166Sdstaff };
2191166Sdstaff
2207089Sgjelinek /* used to track nested zone-lock operations */
2217089Sgjelinek static int zone_lock_cnt = 0;
2227089Sgjelinek
2237089Sgjelinek /* used to communicate lock status to children */
2247089Sgjelinek #define LOCK_ENV_VAR "_ZONEADM_LOCK_HELD"
2257089Sgjelinek static char zoneadm_lock_held[] = LOCK_ENV_VAR"=1";
2267089Sgjelinek static char zoneadm_lock_not_held[] = LOCK_ENV_VAR"=0";
2274229Sgjelinek
228766Scarlsonj char *zonecfg_root = "";
229766Scarlsonj
2300Sstevel@tonic-gate /*
2310Sstevel@tonic-gate * For functions which return int, which is most of the functions herein,
2320Sstevel@tonic-gate * the return values should be from the Z_foo set defined in <libzonecfg.h>.
2330Sstevel@tonic-gate * In some instances, we take pains mapping some libc errno values to Z_foo
2340Sstevel@tonic-gate * values from this set.
2350Sstevel@tonic-gate */
2360Sstevel@tonic-gate
2370Sstevel@tonic-gate /*
238766Scarlsonj * Set the root (/) path for all zonecfg configuration files. This is a
239766Scarlsonj * private interface used by Live Upgrade extensions to access zone
240766Scarlsonj * configuration inside mounted alternate boot environments.
241*13117SSusan.Kamm-Worrell@Sun.COM * This interface is also used by zoneadm mount and unmount subcommands.
242766Scarlsonj */
243766Scarlsonj void
zonecfg_set_root(const char * rootpath)244766Scarlsonj zonecfg_set_root(const char *rootpath)
245766Scarlsonj {
246766Scarlsonj if (*zonecfg_root != '\0')
247766Scarlsonj free(zonecfg_root);
248766Scarlsonj if (rootpath == NULL || rootpath[0] == '\0' || rootpath[1] == '\0' ||
249766Scarlsonj (zonecfg_root = strdup(rootpath)) == NULL)
250766Scarlsonj zonecfg_root = "";
251766Scarlsonj }
252766Scarlsonj
253766Scarlsonj const char *
zonecfg_get_root(void)254766Scarlsonj zonecfg_get_root(void)
255766Scarlsonj {
256766Scarlsonj return (zonecfg_root);
257766Scarlsonj }
258766Scarlsonj
259766Scarlsonj boolean_t
zonecfg_in_alt_root(void)260766Scarlsonj zonecfg_in_alt_root(void)
261766Scarlsonj {
262766Scarlsonj return (*zonecfg_root != '\0');
263766Scarlsonj }
264766Scarlsonj
265766Scarlsonj /*
2660Sstevel@tonic-gate * Callers of the _file_path() functions are expected to have the second
2670Sstevel@tonic-gate * parameter be a (char foo[MAXPATHLEN]).
2680Sstevel@tonic-gate */
2690Sstevel@tonic-gate
270766Scarlsonj static boolean_t
config_file_path(const char * zonename,char * answer)2710Sstevel@tonic-gate config_file_path(const char *zonename, char *answer)
2720Sstevel@tonic-gate {
273766Scarlsonj return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root,
274766Scarlsonj ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN);
2750Sstevel@tonic-gate }
2760Sstevel@tonic-gate
277766Scarlsonj static boolean_t
snap_file_path(const char * zonename,char * answer)278766Scarlsonj snap_file_path(const char *zonename, char *answer)
2790Sstevel@tonic-gate {
280766Scarlsonj return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml",
281766Scarlsonj zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN);
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate /*ARGSUSED*/
2850Sstevel@tonic-gate static void
zonecfg_error_func(void * ctx,const char * msg,...)2860Sstevel@tonic-gate zonecfg_error_func(void *ctx, const char *msg, ...)
2870Sstevel@tonic-gate {
2880Sstevel@tonic-gate /*
2890Sstevel@tonic-gate * This function does nothing by design. Its purpose is to prevent
2900Sstevel@tonic-gate * libxml from dumping unwanted messages to stdout/stderr.
2910Sstevel@tonic-gate */
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate
2940Sstevel@tonic-gate zone_dochandle_t
zonecfg_init_handle(void)2950Sstevel@tonic-gate zonecfg_init_handle(void)
2960Sstevel@tonic-gate {
297565Sdp zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle));
2980Sstevel@tonic-gate if (handle == NULL) {
2990Sstevel@tonic-gate errno = Z_NOMEM;
3000Sstevel@tonic-gate return (NULL);
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate
3030Sstevel@tonic-gate /* generic libxml initialization */
30411318SJordan.Vaughan@Sun.com (void) xmlLineNumbersDefault(1);
3050Sstevel@tonic-gate xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
3060Sstevel@tonic-gate xmlDoValidityCheckingDefaultValue = 1;
3070Sstevel@tonic-gate (void) xmlKeepBlanksDefault(0);
3080Sstevel@tonic-gate xmlGetWarningsDefaultValue = 0;
3090Sstevel@tonic-gate xmlSetGenericErrorFunc(NULL, zonecfg_error_func);
3100Sstevel@tonic-gate
3110Sstevel@tonic-gate return (handle);
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate
3140Sstevel@tonic-gate int
zonecfg_check_handle(zone_dochandle_t handle)3150Sstevel@tonic-gate zonecfg_check_handle(zone_dochandle_t handle)
3160Sstevel@tonic-gate {
3170Sstevel@tonic-gate if (handle == NULL || handle->zone_dh_doc == NULL)
3180Sstevel@tonic-gate return (Z_BAD_HANDLE);
3190Sstevel@tonic-gate return (Z_OK);
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate
3220Sstevel@tonic-gate void
zonecfg_fini_handle(zone_dochandle_t handle)3230Sstevel@tonic-gate zonecfg_fini_handle(zone_dochandle_t handle)
3240Sstevel@tonic-gate {
3250Sstevel@tonic-gate if (zonecfg_check_handle(handle) == Z_OK)
3260Sstevel@tonic-gate xmlFreeDoc(handle->zone_dh_doc);
3270Sstevel@tonic-gate if (handle != NULL)
3280Sstevel@tonic-gate free(handle);
3290Sstevel@tonic-gate }
3300Sstevel@tonic-gate
3310Sstevel@tonic-gate static int
zonecfg_destroy_impl(char * filename)3320Sstevel@tonic-gate zonecfg_destroy_impl(char *filename)
3330Sstevel@tonic-gate {
3340Sstevel@tonic-gate if (unlink(filename) == -1) {
3350Sstevel@tonic-gate if (errno == EACCES)
3360Sstevel@tonic-gate return (Z_ACCES);
3370Sstevel@tonic-gate if (errno == ENOENT)
3380Sstevel@tonic-gate return (Z_NO_ZONE);
3390Sstevel@tonic-gate return (Z_MISC_FS);
3400Sstevel@tonic-gate }
3410Sstevel@tonic-gate return (Z_OK);
3420Sstevel@tonic-gate }
3430Sstevel@tonic-gate
3440Sstevel@tonic-gate int
zonecfg_destroy(const char * zonename,boolean_t force)345565Sdp zonecfg_destroy(const char *zonename, boolean_t force)
3460Sstevel@tonic-gate {
3470Sstevel@tonic-gate char path[MAXPATHLEN];
348565Sdp struct zoneent ze;
349565Sdp int err, state_err;
350565Sdp zone_state_t state;
3510Sstevel@tonic-gate
352766Scarlsonj if (!config_file_path(zonename, path))
353766Scarlsonj return (Z_MISC_FS);
354565Sdp
355565Sdp state_err = zone_get_state((char *)zonename, &state);
356565Sdp err = access(path, W_OK);
357565Sdp
358565Sdp /*
359565Sdp * If there is no file, and no index entry, reliably indicate that no
360565Sdp * such zone exists.
361565Sdp */
362565Sdp if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT))
363565Sdp return (Z_NO_ZONE);
364565Sdp
365565Sdp /*
366565Sdp * Handle any other filesystem related errors (except if the XML
367565Sdp * file is missing, which we treat silently), unless we're forcing,
368565Sdp * in which case we plow on.
369565Sdp */
370565Sdp if (err == -1 && errno != ENOENT) {
371565Sdp if (errno == EACCES)
372565Sdp return (Z_ACCES);
373565Sdp else if (!force)
374565Sdp return (Z_MISC_FS);
375565Sdp }
376565Sdp
377565Sdp if (state > ZONE_STATE_INSTALLED)
378565Sdp return (Z_BAD_ZONE_STATE);
379565Sdp
380565Sdp if (!force && state > ZONE_STATE_CONFIGURED)
381565Sdp return (Z_BAD_ZONE_STATE);
382565Sdp
383565Sdp /*
384565Sdp * Index deletion succeeds even if the entry doesn't exist. So this
385565Sdp * will fail only if we've had some more severe problem.
386565Sdp */
387565Sdp bzero(&ze, sizeof (ze));
388565Sdp (void) strlcpy(ze.zone_name, zonename, sizeof (ze.zone_name));
389565Sdp if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK)
390565Sdp if (!force)
391565Sdp return (err);
392565Sdp
393565Sdp err = zonecfg_destroy_impl(path);
394565Sdp
395565Sdp /*
396565Sdp * Treat failure to find the XML file silently, since, well, it's
397565Sdp * gone, and with the index file cleaned up, we're done.
398565Sdp */
399565Sdp if (err == Z_OK || err == Z_NO_ZONE)
400565Sdp return (Z_OK);
401565Sdp return (err);
4020Sstevel@tonic-gate }
4030Sstevel@tonic-gate
4040Sstevel@tonic-gate int
zonecfg_destroy_snapshot(const char * zonename)405766Scarlsonj zonecfg_destroy_snapshot(const char *zonename)
4060Sstevel@tonic-gate {
4070Sstevel@tonic-gate char path[MAXPATHLEN];
4080Sstevel@tonic-gate
409766Scarlsonj if (!snap_file_path(zonename, path))
410766Scarlsonj return (Z_MISC_FS);
4110Sstevel@tonic-gate return (zonecfg_destroy_impl(path));
4120Sstevel@tonic-gate }
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate static int
getroot(zone_dochandle_t handle,xmlNodePtr * root)415228Sdp getroot(zone_dochandle_t handle, xmlNodePtr *root)
4160Sstevel@tonic-gate {
4170Sstevel@tonic-gate if (zonecfg_check_handle(handle) == Z_BAD_HANDLE)
4180Sstevel@tonic-gate return (Z_BAD_HANDLE);
4190Sstevel@tonic-gate
420228Sdp *root = xmlDocGetRootElement(handle->zone_dh_doc);
421228Sdp
422228Sdp if (*root == NULL)
4230Sstevel@tonic-gate return (Z_EMPTY_DOCUMENT);
424228Sdp
425228Sdp if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE))
4260Sstevel@tonic-gate return (Z_WRONG_DOC_TYPE);
427228Sdp
428228Sdp return (Z_OK);
429228Sdp }
430228Sdp
431228Sdp static int
operation_prep(zone_dochandle_t handle)432228Sdp operation_prep(zone_dochandle_t handle)
433228Sdp {
434228Sdp xmlNodePtr root;
435228Sdp int err;
436228Sdp
437228Sdp if ((err = getroot(handle, &root)) != 0)
438228Sdp return (err);
439228Sdp
440228Sdp handle->zone_dh_cur = root;
441228Sdp handle->zone_dh_top = root;
442228Sdp return (Z_OK);
443228Sdp }
444228Sdp
445228Sdp static int
fetchprop(xmlNodePtr cur,const xmlChar * propname,char * dst,size_t dstsize)4461645Scomay fetchprop(xmlNodePtr cur, const xmlChar *propname, char *dst, size_t dstsize)
4471645Scomay {
4481645Scomay xmlChar *property;
4491645Scomay size_t srcsize;
4501645Scomay
4511645Scomay if ((property = xmlGetProp(cur, propname)) == NULL)
4521645Scomay return (Z_BAD_PROPERTY);
4531645Scomay srcsize = strlcpy(dst, (char *)property, dstsize);
4541645Scomay xmlFree(property);
4551645Scomay if (srcsize >= dstsize)
4561645Scomay return (Z_TOO_BIG);
4571645Scomay return (Z_OK);
4581645Scomay }
4591645Scomay
4601645Scomay static int
fetch_alloc_prop(xmlNodePtr cur,const xmlChar * propname,char ** dst)4611645Scomay fetch_alloc_prop(xmlNodePtr cur, const xmlChar *propname, char **dst)
4621645Scomay {
4631645Scomay xmlChar *property;
4641645Scomay
4651645Scomay if ((property = xmlGetProp(cur, propname)) == NULL)
4661645Scomay return (Z_BAD_PROPERTY);
4671645Scomay if ((*dst = strdup((char *)property)) == NULL) {
4681645Scomay xmlFree(property);
4691645Scomay return (Z_NOMEM);
4701645Scomay }
4711645Scomay xmlFree(property);
4721645Scomay return (Z_OK);
4731645Scomay }
4741645Scomay
4751645Scomay static int
getrootattr(zone_dochandle_t handle,const xmlChar * propname,char * propval,size_t propsize)476228Sdp getrootattr(zone_dochandle_t handle, const xmlChar *propname,
477228Sdp char *propval, size_t propsize)
478228Sdp {
479228Sdp xmlNodePtr root;
480228Sdp int err;
481228Sdp
482228Sdp if ((err = getroot(handle, &root)) != 0)
483228Sdp return (err);
484228Sdp
4851645Scomay return (fetchprop(root, propname, propval, propsize));
4861645Scomay }
4871645Scomay
4881645Scomay static int
get_alloc_rootattr(zone_dochandle_t handle,const xmlChar * propname,char ** propval)4891645Scomay get_alloc_rootattr(zone_dochandle_t handle, const xmlChar *propname,
4901645Scomay char **propval)
4911645Scomay {
4921645Scomay xmlNodePtr root;
4931645Scomay int err;
4941645Scomay
4951645Scomay if ((err = getroot(handle, &root)) != 0)
4961645Scomay return (err);
4971645Scomay
4981645Scomay return (fetch_alloc_prop(root, propname, propval));
499228Sdp }
500228Sdp
501228Sdp static int
setrootattr(zone_dochandle_t handle,const xmlChar * propname,const char * propval)502766Scarlsonj setrootattr(zone_dochandle_t handle, const xmlChar *propname,
503766Scarlsonj const char *propval)
504228Sdp {
505228Sdp int err;
506228Sdp xmlNodePtr root;
507228Sdp
508228Sdp if ((err = getroot(handle, &root)) != Z_OK)
509228Sdp return (err);
510228Sdp
5113247Sgjelinek /*
5123247Sgjelinek * If we get a null propval remove the property (ignore return since it
5133247Sgjelinek * may not be set to begin with).
5143247Sgjelinek */
5153247Sgjelinek if (propval == NULL) {
5163247Sgjelinek (void) xmlUnsetProp(root, propname);
5173247Sgjelinek } else {
5183247Sgjelinek if (xmlSetProp(root, propname, (const xmlChar *) propval)
5193247Sgjelinek == NULL)
5203247Sgjelinek return (Z_INVAL);
5213247Sgjelinek }
5220Sstevel@tonic-gate return (Z_OK);
5230Sstevel@tonic-gate }
5240Sstevel@tonic-gate
525565Sdp static void
addcomment(zone_dochandle_t handle,const char * comment)526565Sdp addcomment(zone_dochandle_t handle, const char *comment)
527565Sdp {
528565Sdp xmlNodePtr node;
529565Sdp node = xmlNewComment((xmlChar *) comment);
530565Sdp
531565Sdp if (node != NULL)
532565Sdp (void) xmlAddPrevSibling(handle->zone_dh_top, node);
533565Sdp }
534565Sdp
535565Sdp static void
stripcomments(zone_dochandle_t handle)536565Sdp stripcomments(zone_dochandle_t handle)
537565Sdp {
538565Sdp xmlDocPtr top;
539565Sdp xmlNodePtr child, next;
540565Sdp
541565Sdp top = handle->zone_dh_doc;
542565Sdp for (child = top->xmlChildrenNode; child != NULL; child = next) {
543565Sdp next = child->next;
544565Sdp if (child->name == NULL)
545565Sdp continue;
546565Sdp if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) {
547565Sdp next = child->next;
548565Sdp xmlUnlinkNode(child);
549565Sdp xmlFreeNode(child);
550565Sdp }
551565Sdp }
552565Sdp }
553565Sdp
5541507Sgjelinek static void
strip_sw_inv(zone_dochandle_t handle)5551507Sgjelinek strip_sw_inv(zone_dochandle_t handle)
5561507Sgjelinek {
5571507Sgjelinek xmlNodePtr root, child, next;
5581507Sgjelinek
5591507Sgjelinek root = xmlDocGetRootElement(handle->zone_dh_doc);
5601507Sgjelinek for (child = root->xmlChildrenNode; child != NULL; child = next) {
5611507Sgjelinek next = child->next;
5621507Sgjelinek if (child->name == NULL)
5631507Sgjelinek continue;
5641507Sgjelinek if (xmlStrcmp(child->name, DTD_ELEM_PACKAGE) == 0 ||
5651507Sgjelinek xmlStrcmp(child->name, DTD_ELEM_PATCH) == 0) {
5661507Sgjelinek next = child->next;
5671507Sgjelinek xmlUnlinkNode(child);
5681507Sgjelinek xmlFreeNode(child);
5691507Sgjelinek }
5701507Sgjelinek }
5711507Sgjelinek }
5721507Sgjelinek
5730Sstevel@tonic-gate static int
zonecfg_get_handle_impl(const char * zonename,const char * filename,zone_dochandle_t handle)574766Scarlsonj zonecfg_get_handle_impl(const char *zonename, const char *filename,
575766Scarlsonj zone_dochandle_t handle)
5760Sstevel@tonic-gate {
5770Sstevel@tonic-gate xmlValidCtxtPtr cvp;
5780Sstevel@tonic-gate struct stat statbuf;
5790Sstevel@tonic-gate int valid;
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate if (zonename == NULL)
5820Sstevel@tonic-gate return (Z_NO_ZONE);
5832712Snn35248
5840Sstevel@tonic-gate if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) {
5850Sstevel@tonic-gate /* distinguish file not found vs. found but not parsed */
5860Sstevel@tonic-gate if (stat(filename, &statbuf) == 0)
5870Sstevel@tonic-gate return (Z_INVALID_DOCUMENT);
5880Sstevel@tonic-gate return (Z_NO_ZONE);
5890Sstevel@tonic-gate }
5900Sstevel@tonic-gate if ((cvp = xmlNewValidCtxt()) == NULL)
5910Sstevel@tonic-gate return (Z_NOMEM);
5920Sstevel@tonic-gate cvp->error = zonecfg_error_func;
5930Sstevel@tonic-gate cvp->warning = zonecfg_error_func;
5940Sstevel@tonic-gate valid = xmlValidateDocument(cvp, handle->zone_dh_doc);
5950Sstevel@tonic-gate xmlFreeValidCtxt(cvp);
5960Sstevel@tonic-gate if (valid == 0)
5970Sstevel@tonic-gate return (Z_INVALID_DOCUMENT);
598565Sdp
5990Sstevel@tonic-gate /* delete any comments such as inherited Sun copyright / ident str */
600565Sdp stripcomments(handle);
6010Sstevel@tonic-gate return (Z_OK);
6020Sstevel@tonic-gate }
6030Sstevel@tonic-gate
6040Sstevel@tonic-gate int
zonecfg_get_handle(const char * zonename,zone_dochandle_t handle)605766Scarlsonj zonecfg_get_handle(const char *zonename, zone_dochandle_t handle)
6060Sstevel@tonic-gate {
6070Sstevel@tonic-gate char path[MAXPATHLEN];
6080Sstevel@tonic-gate
609766Scarlsonj if (!config_file_path(zonename, path))
610766Scarlsonj return (Z_MISC_FS);
611565Sdp handle->zone_dh_newzone = B_FALSE;
612565Sdp
6130Sstevel@tonic-gate return (zonecfg_get_handle_impl(zonename, path, handle));
6140Sstevel@tonic-gate }
6150Sstevel@tonic-gate
6160Sstevel@tonic-gate int
zonecfg_get_attach_handle(const char * path,const char * fname,const char * zonename,boolean_t preserve_sw,zone_dochandle_t handle)6177257Sgjelinek zonecfg_get_attach_handle(const char *path, const char *fname,
6187257Sgjelinek const char *zonename, boolean_t preserve_sw, zone_dochandle_t handle)
6191507Sgjelinek {
6201507Sgjelinek char migpath[MAXPATHLEN];
6211507Sgjelinek int err;
6221507Sgjelinek struct stat buf;
6231507Sgjelinek
6241507Sgjelinek if (snprintf(migpath, sizeof (migpath), "%s/root", path) >=
6251507Sgjelinek sizeof (migpath))
6261507Sgjelinek return (Z_NOMEM);
6271507Sgjelinek
6281507Sgjelinek if (stat(migpath, &buf) == -1 || !S_ISDIR(buf.st_mode))
6291507Sgjelinek return (Z_NO_ZONE);
6301507Sgjelinek
6317257Sgjelinek if (snprintf(migpath, sizeof (migpath), "%s/%s", path, fname) >=
6321507Sgjelinek sizeof (migpath))
6331507Sgjelinek return (Z_NOMEM);
6341507Sgjelinek
6351507Sgjelinek if ((err = zonecfg_get_handle_impl(zonename, migpath, handle)) != Z_OK)
6361507Sgjelinek return (err);
6371507Sgjelinek
6381507Sgjelinek if (!preserve_sw)
6391507Sgjelinek strip_sw_inv(handle);
6401507Sgjelinek
6411507Sgjelinek handle->zone_dh_newzone = B_TRUE;
6421507Sgjelinek if ((err = setrootattr(handle, DTD_ATTR_ZONEPATH, path)) != Z_OK)
6431507Sgjelinek return (err);
6441507Sgjelinek
6451507Sgjelinek return (setrootattr(handle, DTD_ATTR_NAME, zonename));
6461507Sgjelinek }
6471507Sgjelinek
6481507Sgjelinek int
zonecfg_get_snapshot_handle(const char * zonename,zone_dochandle_t handle)649766Scarlsonj zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle)
6500Sstevel@tonic-gate {
6510Sstevel@tonic-gate char path[MAXPATHLEN];
6520Sstevel@tonic-gate
653766Scarlsonj if (!snap_file_path(zonename, path))
654766Scarlsonj return (Z_MISC_FS);
655565Sdp handle->zone_dh_newzone = B_FALSE;
6560Sstevel@tonic-gate return (zonecfg_get_handle_impl(zonename, path, handle));
6570Sstevel@tonic-gate }
6580Sstevel@tonic-gate
6590Sstevel@tonic-gate int
zonecfg_get_template_handle(const char * template,const char * zonename,zone_dochandle_t handle)660766Scarlsonj zonecfg_get_template_handle(const char *template, const char *zonename,
661565Sdp zone_dochandle_t handle)
662565Sdp {
663565Sdp char path[MAXPATHLEN];
664565Sdp int err;
665565Sdp
666766Scarlsonj if (!config_file_path(template, path))
667766Scarlsonj return (Z_MISC_FS);
668565Sdp
669565Sdp if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK)
670565Sdp return (err);
671565Sdp handle->zone_dh_newzone = B_TRUE;
672565Sdp return (setrootattr(handle, DTD_ATTR_NAME, zonename));
673565Sdp }
674565Sdp
6752712Snn35248 int
zonecfg_get_xml_handle(const char * path,zone_dochandle_t handle)6762712Snn35248 zonecfg_get_xml_handle(const char *path, zone_dochandle_t handle)
6772712Snn35248 {
6782712Snn35248 struct stat buf;
6792712Snn35248 int err;
6802712Snn35248
6812712Snn35248 if (stat(path, &buf) == -1)
6822712Snn35248 return (Z_MISC_FS);
6832712Snn35248
6842712Snn35248 if ((err = zonecfg_get_handle_impl("xml", path, handle)) != Z_OK)
6852712Snn35248 return (err);
6862712Snn35248 handle->zone_dh_newzone = B_TRUE;
6872712Snn35248 return (Z_OK);
6882712Snn35248 }
6892712Snn35248
6902078Sgjelinek /*
6912078Sgjelinek * Initialize two handles from the manifest read on fd. The rem_handle
6922078Sgjelinek * is initialized from the input file, including the sw inventory. The
6932078Sgjelinek * local_handle is initialized with the same zone configuration but with
6942078Sgjelinek * no sw inventory.
6952078Sgjelinek */
6962078Sgjelinek int
zonecfg_attach_manifest(int fd,zone_dochandle_t local_handle,zone_dochandle_t rem_handle)6972078Sgjelinek zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle,
6982078Sgjelinek zone_dochandle_t rem_handle)
6992078Sgjelinek {
7002078Sgjelinek xmlValidCtxtPtr cvp;
7012078Sgjelinek int valid;
7022078Sgjelinek
7032078Sgjelinek /* load the manifest into the handle for the remote system */
7042078Sgjelinek if ((rem_handle->zone_dh_doc = xmlReadFd(fd, NULL, NULL, 0)) == NULL) {
7052078Sgjelinek return (Z_INVALID_DOCUMENT);
7062078Sgjelinek }
7072078Sgjelinek if ((cvp = xmlNewValidCtxt()) == NULL)
7082078Sgjelinek return (Z_NOMEM);
7092078Sgjelinek cvp->error = zonecfg_error_func;
7102078Sgjelinek cvp->warning = zonecfg_error_func;
7112078Sgjelinek valid = xmlValidateDocument(cvp, rem_handle->zone_dh_doc);
7122078Sgjelinek xmlFreeValidCtxt(cvp);
7132078Sgjelinek if (valid == 0)
7142078Sgjelinek return (Z_INVALID_DOCUMENT);
7152078Sgjelinek
7162078Sgjelinek /* delete any comments such as inherited Sun copyright / ident str */
7172078Sgjelinek stripcomments(rem_handle);
7182078Sgjelinek
7192078Sgjelinek rem_handle->zone_dh_newzone = B_TRUE;
7202078Sgjelinek rem_handle->zone_dh_sw_inv = B_TRUE;
7212078Sgjelinek
7222078Sgjelinek /*
7232078Sgjelinek * Now use the remote system handle to generate a local system handle
7242078Sgjelinek * with an identical zones configuration but no sw inventory.
7252078Sgjelinek */
7262078Sgjelinek if ((local_handle->zone_dh_doc = xmlCopyDoc(rem_handle->zone_dh_doc,
7272078Sgjelinek 1)) == NULL) {
7282078Sgjelinek return (Z_INVALID_DOCUMENT);
7292078Sgjelinek }
7302078Sgjelinek
7312078Sgjelinek /*
7322078Sgjelinek * We need to re-run xmlValidateDocument on local_handle to properly
7332078Sgjelinek * update the in-core representation of the configuration.
7342078Sgjelinek */
7352078Sgjelinek if ((cvp = xmlNewValidCtxt()) == NULL)
7362078Sgjelinek return (Z_NOMEM);
7372078Sgjelinek cvp->error = zonecfg_error_func;
7382078Sgjelinek cvp->warning = zonecfg_error_func;
7392078Sgjelinek valid = xmlValidateDocument(cvp, local_handle->zone_dh_doc);
7402078Sgjelinek xmlFreeValidCtxt(cvp);
7412078Sgjelinek if (valid == 0)
7422078Sgjelinek return (Z_INVALID_DOCUMENT);
7432078Sgjelinek
7442078Sgjelinek strip_sw_inv(local_handle);
7452078Sgjelinek
7462078Sgjelinek local_handle->zone_dh_newzone = B_TRUE;
7472078Sgjelinek local_handle->zone_dh_sw_inv = B_FALSE;
7482078Sgjelinek
7492078Sgjelinek return (Z_OK);
7502078Sgjelinek }
7512078Sgjelinek
752565Sdp static boolean_t
is_renaming(zone_dochandle_t handle)753565Sdp is_renaming(zone_dochandle_t handle)
754565Sdp {
755565Sdp if (handle->zone_dh_newzone)
756565Sdp return (B_FALSE);
757565Sdp if (strlen(handle->zone_dh_delete_name) > 0)
758565Sdp return (B_TRUE);
759565Sdp return (B_FALSE);
760565Sdp }
761565Sdp
762565Sdp static boolean_t
is_new(zone_dochandle_t handle)763565Sdp is_new(zone_dochandle_t handle)
764565Sdp {
765565Sdp return (handle->zone_dh_newzone || handle->zone_dh_snapshot);
766565Sdp }
767565Sdp
768565Sdp static boolean_t
is_snapshot(zone_dochandle_t handle)769565Sdp is_snapshot(zone_dochandle_t handle)
770565Sdp {
771565Sdp return (handle->zone_dh_snapshot);
772565Sdp }
773565Sdp
774565Sdp /*
775565Sdp * It would be great to be able to use libc's ctype(3c) macros, but we
776565Sdp * can't, as they are locale sensitive, and it would break our limited thread
777565Sdp * safety if this routine had to change the app locale on the fly.
778565Sdp */
779565Sdp int
zonecfg_validate_zonename(const char * zone)780766Scarlsonj zonecfg_validate_zonename(const char *zone)
781565Sdp {
782565Sdp int i;
783565Sdp
784565Sdp if (strcmp(zone, GLOBAL_ZONENAME) == 0)
785565Sdp return (Z_BOGUS_ZONE_NAME);
786565Sdp
787565Sdp if (strlen(zone) >= ZONENAME_MAX)
788565Sdp return (Z_BOGUS_ZONE_NAME);
789565Sdp
790565Sdp if (!((zone[0] >= 'a' && zone[0] <= 'z') ||
791565Sdp (zone[0] >= 'A' && zone[0] <= 'Z') ||
792565Sdp (zone[0] >= '0' && zone[0] <= '9')))
793565Sdp return (Z_BOGUS_ZONE_NAME);
794565Sdp
795565Sdp for (i = 1; zone[i] != '\0'; i++) {
796565Sdp if (!((zone[i] >= 'a' && zone[i] <= 'z') ||
797565Sdp (zone[i] >= 'A' && zone[i] <= 'Z') ||
798565Sdp (zone[i] >= '0' && zone[i] <= '9') ||
799565Sdp (zone[i] == '-') || (zone[i] == '_') || (zone[i] == '.')))
800565Sdp return (Z_BOGUS_ZONE_NAME);
801565Sdp }
802565Sdp
803565Sdp return (Z_OK);
804565Sdp }
805565Sdp
806565Sdp /*
807565Sdp * Changing the zone name requires us to track both the old and new
808565Sdp * name of the zone until commit time.
809565Sdp */
810565Sdp int
zonecfg_get_name(zone_dochandle_t handle,char * name,size_t namesize)8110Sstevel@tonic-gate zonecfg_get_name(zone_dochandle_t handle, char *name, size_t namesize)
8120Sstevel@tonic-gate {
813228Sdp return (getrootattr(handle, DTD_ATTR_NAME, name, namesize));
814228Sdp }
815228Sdp
81612578SGlenn.Faden@Sun.COM static int
insert_admins(zone_dochandle_t handle,char * zonename)81712578SGlenn.Faden@Sun.COM insert_admins(zone_dochandle_t handle, char *zonename)
81812578SGlenn.Faden@Sun.COM {
81912578SGlenn.Faden@Sun.COM int err;
82012578SGlenn.Faden@Sun.COM struct zone_admintab admintab;
82112578SGlenn.Faden@Sun.COM
82212578SGlenn.Faden@Sun.COM if ((err = zonecfg_setadminent(handle)) != Z_OK) {
82312578SGlenn.Faden@Sun.COM return (err);
82412578SGlenn.Faden@Sun.COM }
82512578SGlenn.Faden@Sun.COM while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
82612578SGlenn.Faden@Sun.COM err = zonecfg_insert_userauths(handle,
82712578SGlenn.Faden@Sun.COM admintab.zone_admin_user, zonename);
82812578SGlenn.Faden@Sun.COM if (err != Z_OK) {
82912578SGlenn.Faden@Sun.COM (void) zonecfg_endadminent(handle);
83012578SGlenn.Faden@Sun.COM return (err);
83112578SGlenn.Faden@Sun.COM }
83212578SGlenn.Faden@Sun.COM }
83312578SGlenn.Faden@Sun.COM (void) zonecfg_endadminent(handle);
83412578SGlenn.Faden@Sun.COM return (Z_OK);
83512578SGlenn.Faden@Sun.COM }
83612578SGlenn.Faden@Sun.COM
837228Sdp int
zonecfg_set_name(zone_dochandle_t handle,char * name)838228Sdp zonecfg_set_name(zone_dochandle_t handle, char *name)
839228Sdp {
840565Sdp zone_state_t state;
841565Sdp char curname[ZONENAME_MAX], old_delname[ZONENAME_MAX];
842565Sdp int err;
843565Sdp
844565Sdp if ((err = getrootattr(handle, DTD_ATTR_NAME, curname,
845565Sdp sizeof (curname))) != Z_OK)
846565Sdp return (err);
847565Sdp
848565Sdp if (strcmp(name, curname) == 0)
849565Sdp return (Z_OK);
850565Sdp
851565Sdp /*
852565Sdp * Switching zone names to one beginning with SUNW is not permitted.
853565Sdp */
854565Sdp if (strncmp(name, "SUNW", 4) == 0)
855565Sdp return (Z_BOGUS_ZONE_NAME);
856565Sdp
857565Sdp if ((err = zonecfg_validate_zonename(name)) != Z_OK)
858565Sdp return (err);
859565Sdp
860565Sdp /*
861565Sdp * Setting the name back to the original name (effectively a revert of
862565Sdp * the name) is fine. But if we carry on, we'll falsely identify the
863565Sdp * name as "in use," so special case here.
864565Sdp */
865565Sdp if (strcmp(name, handle->zone_dh_delete_name) == 0) {
866565Sdp err = setrootattr(handle, DTD_ATTR_NAME, name);
867565Sdp handle->zone_dh_delete_name[0] = '\0';
868565Sdp return (err);
869565Sdp }
870565Sdp
871565Sdp /* Check to see if new name chosen is already in use */
872565Sdp if (zone_get_state(name, &state) != Z_NO_ZONE)
873565Sdp return (Z_NAME_IN_USE);
874565Sdp
875565Sdp /*
876565Sdp * If this isn't already "new" or in a renaming transition, then
877565Sdp * we're initiating a rename here; so stash the "delete name"
878565Sdp * (i.e. the name of the zone we'll be removing) for the rename.
879565Sdp */
880565Sdp (void) strlcpy(old_delname, handle->zone_dh_delete_name,
881565Sdp sizeof (old_delname));
882565Sdp if (!is_new(handle) && !is_renaming(handle)) {
883565Sdp /*
884565Sdp * Name change is allowed only when the zone we're altering
885565Sdp * is not ready or running.
886565Sdp */
887565Sdp err = zone_get_state(curname, &state);
888565Sdp if (err == Z_OK) {
889565Sdp if (state > ZONE_STATE_INSTALLED)
890565Sdp return (Z_BAD_ZONE_STATE);
891565Sdp } else if (err != Z_NO_ZONE) {
892565Sdp return (err);
893565Sdp }
894565Sdp
895565Sdp (void) strlcpy(handle->zone_dh_delete_name, curname,
896565Sdp sizeof (handle->zone_dh_delete_name));
897565Sdp assert(is_renaming(handle));
898565Sdp } else if (is_renaming(handle)) {
899565Sdp err = zone_get_state(handle->zone_dh_delete_name, &state);
900565Sdp if (err == Z_OK) {
901565Sdp if (state > ZONE_STATE_INSTALLED)
902565Sdp return (Z_BAD_ZONE_STATE);
903565Sdp } else if (err != Z_NO_ZONE) {
904565Sdp return (err);
905565Sdp }
906565Sdp }
907565Sdp
908565Sdp if ((err = setrootattr(handle, DTD_ATTR_NAME, name)) != Z_OK) {
909565Sdp /*
910565Sdp * Restore the deletename to whatever it was at the
911565Sdp * top of the routine, since we've had a failure.
912565Sdp */
913565Sdp (void) strlcpy(handle->zone_dh_delete_name, old_delname,
914565Sdp sizeof (handle->zone_dh_delete_name));
915565Sdp return (err);
916565Sdp }
917565Sdp
91812578SGlenn.Faden@Sun.COM /*
91912578SGlenn.Faden@Sun.COM * Record the old admins from the old zonename
92012578SGlenn.Faden@Sun.COM * so that they can be deleted when the operation is committed.
92112578SGlenn.Faden@Sun.COM */
92212578SGlenn.Faden@Sun.COM if ((err = insert_admins(handle, curname)) != Z_OK)
92312578SGlenn.Faden@Sun.COM return (err);
92412578SGlenn.Faden@Sun.COM else
92512578SGlenn.Faden@Sun.COM return (Z_OK);
926228Sdp }
927228Sdp
928228Sdp int
zonecfg_get_zonepath(zone_dochandle_t handle,char * path,size_t pathsize)929228Sdp zonecfg_get_zonepath(zone_dochandle_t handle, char *path, size_t pathsize)
930228Sdp {
931766Scarlsonj size_t len;
932766Scarlsonj
933766Scarlsonj if ((len = strlcpy(path, zonecfg_root, pathsize)) >= pathsize)
934766Scarlsonj return (Z_TOO_BIG);
935766Scarlsonj return (getrootattr(handle, DTD_ATTR_ZONEPATH, path + len,
936766Scarlsonj pathsize - len));
937228Sdp }
938228Sdp
939228Sdp int
zonecfg_set_zonepath(zone_dochandle_t handle,char * zonepath)940228Sdp zonecfg_set_zonepath(zone_dochandle_t handle, char *zonepath)
941228Sdp {
9422303Scarlsonj size_t len;
94312715SSusan.Kamm-Worrell@Sun.COM char *modpath, *copy_mp, *curr_mp; /* modified path ptrs */
94412715SSusan.Kamm-Worrell@Sun.COM char last_copied;
94512715SSusan.Kamm-Worrell@Sun.COM int ret;
94612715SSusan.Kamm-Worrell@Sun.COM
94712715SSusan.Kamm-Worrell@Sun.COM /*
94812715SSusan.Kamm-Worrell@Sun.COM * Collapse multiple contiguous slashes and remove trailing slash.
94912715SSusan.Kamm-Worrell@Sun.COM */
95012715SSusan.Kamm-Worrell@Sun.COM modpath = strdup(zonepath);
95112715SSusan.Kamm-Worrell@Sun.COM if (modpath == NULL)
95212715SSusan.Kamm-Worrell@Sun.COM return (Z_NOMEM);
95312715SSusan.Kamm-Worrell@Sun.COM last_copied = '\0';
95412715SSusan.Kamm-Worrell@Sun.COM for (copy_mp = curr_mp = modpath; *curr_mp != '\0'; curr_mp++) {
95512715SSusan.Kamm-Worrell@Sun.COM if (*curr_mp != '/' || last_copied != '/') {
95612715SSusan.Kamm-Worrell@Sun.COM last_copied = *copy_mp = *curr_mp;
95712715SSusan.Kamm-Worrell@Sun.COM copy_mp++;
95812715SSusan.Kamm-Worrell@Sun.COM }
95912715SSusan.Kamm-Worrell@Sun.COM }
96012715SSusan.Kamm-Worrell@Sun.COM if (last_copied == '/')
96112715SSusan.Kamm-Worrell@Sun.COM copy_mp--;
96212715SSusan.Kamm-Worrell@Sun.COM *copy_mp = '\0';
9632303Scarlsonj
9642303Scarlsonj /*
9652303Scarlsonj * The user deals in absolute paths in the running global zone, but the
9662303Scarlsonj * internal configuration files deal with boot environment relative
9672303Scarlsonj * paths. Strip out the alternate root when specified.
9682303Scarlsonj */
9692303Scarlsonj len = strlen(zonecfg_root);
97012715SSusan.Kamm-Worrell@Sun.COM if (strncmp(modpath, zonecfg_root, len) != 0 || modpath[len] != '/') {
97112715SSusan.Kamm-Worrell@Sun.COM free(modpath);
9722303Scarlsonj return (Z_BAD_PROPERTY);
97312715SSusan.Kamm-Worrell@Sun.COM }
97412715SSusan.Kamm-Worrell@Sun.COM curr_mp = modpath + len;
97512715SSusan.Kamm-Worrell@Sun.COM ret = setrootattr(handle, DTD_ATTR_ZONEPATH, curr_mp);
97612715SSusan.Kamm-Worrell@Sun.COM free(modpath);
97712715SSusan.Kamm-Worrell@Sun.COM return (ret);
978228Sdp }
979228Sdp
98010943SEdward.Pilatowicz@Sun.COM static int
i_zonecfg_get_brand(zone_dochandle_t handle,char * brand,size_t brandsize,boolean_t default_query)98110943SEdward.Pilatowicz@Sun.COM i_zonecfg_get_brand(zone_dochandle_t handle, char *brand, size_t brandsize,
98210943SEdward.Pilatowicz@Sun.COM boolean_t default_query)
9832712Snn35248 {
9842712Snn35248 int ret, sz;
9852712Snn35248
9862712Snn35248 ret = getrootattr(handle, DTD_ATTR_BRAND, brand, brandsize);
9872712Snn35248
98810943SEdward.Pilatowicz@Sun.COM /*
98910943SEdward.Pilatowicz@Sun.COM * If the lookup failed, or succeeded in finding a non-null brand
99010943SEdward.Pilatowicz@Sun.COM * string then return.
99110943SEdward.Pilatowicz@Sun.COM */
99210943SEdward.Pilatowicz@Sun.COM if (ret != Z_OK || brand[0] != '\0')
99310943SEdward.Pilatowicz@Sun.COM return (ret);
99410943SEdward.Pilatowicz@Sun.COM
99510943SEdward.Pilatowicz@Sun.COM if (!default_query) {
99610943SEdward.Pilatowicz@Sun.COM /* If the zone has no brand, it is the default brand. */
99710953SEdward.Pilatowicz@Sun.COM return (zonecfg_default_brand(brand, brandsize));
99810943SEdward.Pilatowicz@Sun.COM }
99910943SEdward.Pilatowicz@Sun.COM
100010943SEdward.Pilatowicz@Sun.COM /* if SUNWdefault didn't specify a brand, fallback to "native" */
100110943SEdward.Pilatowicz@Sun.COM sz = strlcpy(brand, NATIVE_BRAND_NAME, brandsize);
100210943SEdward.Pilatowicz@Sun.COM if (sz >= brandsize)
100310943SEdward.Pilatowicz@Sun.COM return (Z_TOO_BIG);
100410943SEdward.Pilatowicz@Sun.COM return (Z_OK);
100510943SEdward.Pilatowicz@Sun.COM }
100610943SEdward.Pilatowicz@Sun.COM
100710943SEdward.Pilatowicz@Sun.COM int
zonecfg_get_brand(zone_dochandle_t handle,char * brand,size_t brandsize)100810943SEdward.Pilatowicz@Sun.COM zonecfg_get_brand(zone_dochandle_t handle, char *brand, size_t brandsize)
100910943SEdward.Pilatowicz@Sun.COM {
101010943SEdward.Pilatowicz@Sun.COM return (i_zonecfg_get_brand(handle, brand, brandsize, B_FALSE));
10112712Snn35248 }
10122712Snn35248
10132712Snn35248 int
zonecfg_set_brand(zone_dochandle_t handle,char * brand)10142712Snn35248 zonecfg_set_brand(zone_dochandle_t handle, char *brand)
10152712Snn35248 {
10162712Snn35248 return (setrootattr(handle, DTD_ATTR_BRAND, brand));
10172712Snn35248 }
10182712Snn35248
10192712Snn35248 int
zonecfg_get_autoboot(zone_dochandle_t handle,boolean_t * autoboot)1020228Sdp zonecfg_get_autoboot(zone_dochandle_t handle, boolean_t *autoboot)
1021228Sdp {
1022228Sdp char autobootstr[DTD_ENTITY_BOOL_LEN];
1023228Sdp int ret;
1024228Sdp
1025228Sdp if ((ret = getrootattr(handle, DTD_ATTR_AUTOBOOT, autobootstr,
1026228Sdp sizeof (autobootstr))) != Z_OK)
1027228Sdp return (ret);
1028228Sdp
1029228Sdp if (strcmp(autobootstr, DTD_ENTITY_TRUE) == 0)
1030228Sdp *autoboot = B_TRUE;
1031228Sdp else if (strcmp(autobootstr, DTD_ENTITY_FALSE) == 0)
1032228Sdp *autoboot = B_FALSE;
1033228Sdp else
1034228Sdp ret = Z_BAD_PROPERTY;
1035228Sdp return (ret);
1036228Sdp }
1037228Sdp
1038228Sdp int
zonecfg_set_autoboot(zone_dochandle_t handle,boolean_t autoboot)1039228Sdp zonecfg_set_autoboot(zone_dochandle_t handle, boolean_t autoboot)
1040228Sdp {
1041228Sdp return (setrootattr(handle, DTD_ATTR_AUTOBOOT,
1042228Sdp autoboot ? DTD_ENTITY_TRUE : DTD_ENTITY_FALSE));
1043228Sdp }
1044228Sdp
1045228Sdp int
zonecfg_get_pool(zone_dochandle_t handle,char * pool,size_t poolsize)1046228Sdp zonecfg_get_pool(zone_dochandle_t handle, char *pool, size_t poolsize)
1047228Sdp {
1048228Sdp return (getrootattr(handle, DTD_ATTR_POOL, pool, poolsize));
1049228Sdp }
1050228Sdp
1051228Sdp int
zonecfg_set_pool(zone_dochandle_t handle,char * pool)1052228Sdp zonecfg_set_pool(zone_dochandle_t handle, char *pool)
1053228Sdp {
1054228Sdp return (setrootattr(handle, DTD_ATTR_POOL, pool));
1055228Sdp }
1056228Sdp
10571645Scomay int
zonecfg_get_limitpriv(zone_dochandle_t handle,char ** limitpriv)10581645Scomay zonecfg_get_limitpriv(zone_dochandle_t handle, char **limitpriv)
10591645Scomay {
10601645Scomay return (get_alloc_rootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv));
10611645Scomay }
10621645Scomay
10631645Scomay int
zonecfg_set_limitpriv(zone_dochandle_t handle,char * limitpriv)10642267Sdp zonecfg_set_limitpriv(zone_dochandle_t handle, char *limitpriv)
10652267Sdp {
10662267Sdp return (setrootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv));
10672267Sdp }
10682267Sdp
10692267Sdp int
zonecfg_get_bootargs(zone_dochandle_t handle,char * bargs,size_t bargssize)10702267Sdp zonecfg_get_bootargs(zone_dochandle_t handle, char *bargs, size_t bargssize)
10712267Sdp {
10722267Sdp return (getrootattr(handle, DTD_ATTR_BOOTARGS, bargs, bargssize));
10732267Sdp }
10742267Sdp
10752267Sdp int
zonecfg_set_bootargs(zone_dochandle_t handle,char * bargs)10762267Sdp zonecfg_set_bootargs(zone_dochandle_t handle, char *bargs)
10772267Sdp {
10782267Sdp return (setrootattr(handle, DTD_ATTR_BOOTARGS, bargs));
10791645Scomay }
10801645Scomay
10813247Sgjelinek int
zonecfg_get_sched_class(zone_dochandle_t handle,char * sched,size_t schedsize)10823247Sgjelinek zonecfg_get_sched_class(zone_dochandle_t handle, char *sched, size_t schedsize)
10833247Sgjelinek {
10843247Sgjelinek return (getrootattr(handle, DTD_ATTR_SCHED, sched, schedsize));
10853247Sgjelinek }
10863247Sgjelinek
10873247Sgjelinek int
zonecfg_set_sched(zone_dochandle_t handle,char * sched)10883247Sgjelinek zonecfg_set_sched(zone_dochandle_t handle, char *sched)
10893247Sgjelinek {
10903247Sgjelinek return (setrootattr(handle, DTD_ATTR_SCHED, sched));
10913247Sgjelinek }
10923247Sgjelinek
1093228Sdp /*
1094228Sdp * /etc/zones/index caches a vital piece of information which is also
1095228Sdp * in the <zonename>.xml file: the path to the zone. This is for performance,
1096228Sdp * since we need to walk all zonepath's in order to be able to detect conflicts
1097228Sdp * (see crosscheck_zonepaths() in the zoneadm command).
1098565Sdp *
1099565Sdp * An additional complexity is that when doing a rename, we'd like the entire
1100565Sdp * index update operation (rename, and potential state changes) to be atomic.
1101565Sdp * In general, the operation of this function should succeed or fail as
1102565Sdp * a unit.
1103228Sdp */
1104228Sdp int
zonecfg_refresh_index_file(zone_dochandle_t handle)1105228Sdp zonecfg_refresh_index_file(zone_dochandle_t handle)
1106228Sdp {
1107228Sdp char name[ZONENAME_MAX], zonepath[MAXPATHLEN];
1108228Sdp struct zoneent ze;
1109228Sdp int err;
1110565Sdp int opcode;
1111565Sdp char *zn;
1112565Sdp
1113565Sdp bzero(&ze, sizeof (ze));
1114565Sdp ze.zone_state = -1; /* Preserve existing state in index */
1115228Sdp
1116228Sdp if ((err = zonecfg_get_name(handle, name, sizeof (name))) != Z_OK)
1117228Sdp return (err);
1118565Sdp (void) strlcpy(ze.zone_name, name, sizeof (ze.zone_name));
1119565Sdp
1120228Sdp if ((err = zonecfg_get_zonepath(handle, zonepath,
1121228Sdp sizeof (zonepath))) != Z_OK)
1122228Sdp return (err);
11232303Scarlsonj (void) strlcpy(ze.zone_path, zonepath + strlen(zonecfg_root),
11242303Scarlsonj sizeof (ze.zone_path));
1125565Sdp
1126565Sdp if (is_renaming(handle)) {
1127565Sdp opcode = PZE_MODIFY;
1128565Sdp (void) strlcpy(ze.zone_name, handle->zone_dh_delete_name,
1129565Sdp sizeof (ze.zone_name));
1130565Sdp (void) strlcpy(ze.zone_newname, name, sizeof (ze.zone_newname));
1131565Sdp } else if (is_new(handle)) {
1132565Sdp FILE *cookie;
1133565Sdp /*
1134565Sdp * Be tolerant of the zone already existing in the index file,
1135565Sdp * since we might be forcibly overwriting an existing
1136565Sdp * configuration with a new one (for example 'create -F'
1137565Sdp * in zonecfg).
1138565Sdp */
1139565Sdp opcode = PZE_ADD;
1140565Sdp cookie = setzoneent();
1141565Sdp while ((zn = getzoneent(cookie)) != NULL) {
1142565Sdp if (strcmp(zn, name) == 0) {
1143565Sdp opcode = PZE_MODIFY;
1144565Sdp free(zn);
1145565Sdp break;
1146565Sdp }
1147565Sdp free(zn);
1148565Sdp }
1149565Sdp endzoneent(cookie);
1150565Sdp ze.zone_state = ZONE_STATE_CONFIGURED;
1151565Sdp } else {
1152565Sdp opcode = PZE_MODIFY;
1153565Sdp }
1154565Sdp
1155565Sdp if ((err = putzoneent(&ze, opcode)) != Z_OK)
1156565Sdp return (err);
1157565Sdp
1158565Sdp return (Z_OK);
11590Sstevel@tonic-gate }
11600Sstevel@tonic-gate
1161565Sdp /*
1162565Sdp * The goal of this routine is to cause the index file update and the
1163565Sdp * document save to happen as an atomic operation. We do the document
1164565Sdp * first, saving a backup copy using a hard link; if that succeeds, we go
1165565Sdp * on to the index. If that fails, we roll the document back into place.
1166565Sdp *
1167565Sdp * Strategy:
1168565Sdp *
1169565Sdp * New zone 'foo' configuration:
1170565Sdp * Create tmpfile (zonecfg.xxxxxx)
1171565Sdp * Write XML to tmpfile
1172565Sdp * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
1173565Sdp * Add entry to index file
1174565Sdp * If it fails, delete foo.xml, leaving nothing behind.
1175565Sdp *
1176565Sdp * Save existing zone 'foo':
1177565Sdp * Make backup of foo.xml -> .backup
1178565Sdp * Create tmpfile (zonecfg.xxxxxx)
1179565Sdp * Write XML to tmpfile
1180565Sdp * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
1181565Sdp * Modify index file as needed
1182565Sdp * If it fails, recover from .backup -> foo.xml
1183565Sdp *
1184565Sdp * Rename 'foo' to 'bar':
1185565Sdp * Create tmpfile (zonecfg.xxxxxx)
1186565Sdp * Write XML to tmpfile
1187565Sdp * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml)
1188565Sdp * Add entry for 'bar' to index file, Remove entry for 'foo' (refresh)
1189565Sdp * If it fails, delete bar.xml; foo.xml is left behind.
1190565Sdp */
11910Sstevel@tonic-gate static int
zonecfg_save_impl(zone_dochandle_t handle,char * filename)11920Sstevel@tonic-gate zonecfg_save_impl(zone_dochandle_t handle, char *filename)
11930Sstevel@tonic-gate {
11940Sstevel@tonic-gate char tmpfile[MAXPATHLEN];
1195565Sdp char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN];
11962712Snn35248 int tmpfd, err, valid;
11970Sstevel@tonic-gate xmlValidCtxt cvp = { NULL };
1198565Sdp boolean_t backup;
11990Sstevel@tonic-gate
12000Sstevel@tonic-gate (void) strlcpy(tmpfile, filename, sizeof (tmpfile));
12010Sstevel@tonic-gate (void) dirname(tmpfile);
12020Sstevel@tonic-gate (void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile));
12030Sstevel@tonic-gate
12040Sstevel@tonic-gate tmpfd = mkstemp(tmpfile);
12050Sstevel@tonic-gate if (tmpfd == -1) {
12060Sstevel@tonic-gate (void) unlink(tmpfile);
12070Sstevel@tonic-gate return (Z_TEMP_FILE);
12080Sstevel@tonic-gate }
12090Sstevel@tonic-gate (void) close(tmpfd);
12100Sstevel@tonic-gate
12110Sstevel@tonic-gate cvp.error = zonecfg_error_func;
12120Sstevel@tonic-gate cvp.warning = zonecfg_error_func;
12130Sstevel@tonic-gate
1214565Sdp /*
12152712Snn35248 * We do a final validation of the document. Since the library has
12162712Snn35248 * malfunctioned if it fails to validate, we follow-up with an
12172712Snn35248 * assert() that the doc is valid.
1218565Sdp */
12192712Snn35248 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
12202712Snn35248 assert(valid != 0);
12210Sstevel@tonic-gate
12220Sstevel@tonic-gate if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0)
12230Sstevel@tonic-gate goto err;
1224565Sdp
12250Sstevel@tonic-gate (void) chmod(tmpfile, 0644);
12260Sstevel@tonic-gate
1227565Sdp /*
1228565Sdp * In the event we are doing a standard save, hard link a copy of the
1229565Sdp * original file in .backup.<pid>.filename so we can restore it if
1230565Sdp * something goes wrong.
1231565Sdp */
1232565Sdp if (!is_new(handle) && !is_renaming(handle)) {
1233565Sdp backup = B_TRUE;
1234565Sdp
1235565Sdp (void) strlcpy(bakdir, filename, sizeof (bakdir));
1236565Sdp (void) strlcpy(bakbase, filename, sizeof (bakbase));
1237565Sdp (void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s",
1238565Sdp dirname(bakdir), getpid(), basename(bakbase));
1239565Sdp
1240565Sdp if (link(filename, bakfile) == -1) {
1241565Sdp err = errno;
1242565Sdp (void) unlink(tmpfile);
1243565Sdp if (errno == EACCES)
1244565Sdp return (Z_ACCES);
1245565Sdp return (Z_MISC_FS);
1246565Sdp }
1247565Sdp }
1248565Sdp
1249565Sdp /*
1250565Sdp * Move the new document over top of the old.
1251565Sdp * i.e.: zonecfg.XXXXXX -> myzone.xml
1252565Sdp */
12530Sstevel@tonic-gate if (rename(tmpfile, filename) == -1) {
1254565Sdp err = errno;
12550Sstevel@tonic-gate (void) unlink(tmpfile);
1256565Sdp if (backup)
1257565Sdp (void) unlink(bakfile);
1258565Sdp if (err == EACCES)
12590Sstevel@tonic-gate return (Z_ACCES);
12600Sstevel@tonic-gate return (Z_MISC_FS);
12610Sstevel@tonic-gate }
1262228Sdp
1263565Sdp /*
1264565Sdp * If this is a snapshot, we're done-- don't add an index entry.
1265565Sdp */
1266565Sdp if (is_snapshot(handle))
1267565Sdp return (Z_OK);
1268565Sdp
1269565Sdp /* now update the index file to reflect whatever we just did */
1270565Sdp if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) {
1271565Sdp if (backup) {
1272565Sdp /*
1273565Sdp * Try to restore from our backup.
1274565Sdp */
1275565Sdp (void) unlink(filename);
1276565Sdp (void) rename(bakfile, filename);
1277565Sdp } else {
1278565Sdp /*
1279565Sdp * Either the zone is new, in which case we can delete
1280565Sdp * new.xml, or we're doing a rename, so ditto.
1281565Sdp */
1282565Sdp assert(is_new(handle) || is_renaming(handle));
1283565Sdp (void) unlink(filename);
1284565Sdp }
1285565Sdp return (Z_UPDATING_INDEX);
1286565Sdp }
1287565Sdp
1288565Sdp if (backup)
1289565Sdp (void) unlink(bakfile);
1290565Sdp
1291565Sdp return (Z_OK);
12920Sstevel@tonic-gate
12930Sstevel@tonic-gate err:
12940Sstevel@tonic-gate (void) unlink(tmpfile);
12950Sstevel@tonic-gate return (Z_SAVING_FILE);
12960Sstevel@tonic-gate }
12970Sstevel@tonic-gate
12980Sstevel@tonic-gate int
zonecfg_save(zone_dochandle_t handle)12990Sstevel@tonic-gate zonecfg_save(zone_dochandle_t handle)
13000Sstevel@tonic-gate {
1301565Sdp char zname[ZONENAME_MAX], path[MAXPATHLEN];
1302565Sdp char delpath[MAXPATHLEN];
1303565Sdp int err = Z_SAVING_FILE;
1304565Sdp
1305565Sdp if (zonecfg_check_handle(handle) != Z_OK)
1306565Sdp return (Z_BAD_HANDLE);
1307565Sdp
1308565Sdp /*
13091507Sgjelinek * We don't support saving snapshots or a tree containing a sw
13101507Sgjelinek * inventory at this time.
1311565Sdp */
13121507Sgjelinek if (handle->zone_dh_snapshot || handle->zone_dh_sw_inv)
1313565Sdp return (Z_INVAL);
1314565Sdp
1315565Sdp if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK)
13160Sstevel@tonic-gate return (err);
1317565Sdp
1318766Scarlsonj if (!config_file_path(zname, path))
1319766Scarlsonj return (Z_MISC_FS);
1320565Sdp
1321565Sdp addcomment(handle, "\n DO NOT EDIT THIS "
1322565Sdp "FILE. Use zonecfg(1M) instead.\n");
1323565Sdp
132412578SGlenn.Faden@Sun.COM /*
132512578SGlenn.Faden@Sun.COM * Update user_attr first so that it will be older
132612578SGlenn.Faden@Sun.COM * than the config file.
132712578SGlenn.Faden@Sun.COM */
132812578SGlenn.Faden@Sun.COM (void) zonecfg_authorize_users(handle, zname);
1329565Sdp err = zonecfg_save_impl(handle, path);
1330565Sdp
1331565Sdp stripcomments(handle);
1332565Sdp
1333565Sdp if (err != Z_OK)
1334565Sdp return (err);
1335565Sdp
1336565Sdp handle->zone_dh_newzone = B_FALSE;
1337565Sdp
1338565Sdp if (is_renaming(handle)) {
1339766Scarlsonj if (config_file_path(handle->zone_dh_delete_name, delpath))
1340766Scarlsonj (void) unlink(delpath);
1341565Sdp handle->zone_dh_delete_name[0] = '\0';
1342565Sdp }
1343565Sdp
1344565Sdp return (Z_OK);
13450Sstevel@tonic-gate }
13460Sstevel@tonic-gate
13471507Sgjelinek int
zonecfg_verify_save(zone_dochandle_t handle,char * filename)13482712Snn35248 zonecfg_verify_save(zone_dochandle_t handle, char *filename)
13492712Snn35248 {
13502712Snn35248 int valid;
13512712Snn35248
13522712Snn35248 xmlValidCtxt cvp = { NULL };
13532712Snn35248
13542712Snn35248 if (zonecfg_check_handle(handle) != Z_OK)
13552712Snn35248 return (Z_BAD_HANDLE);
13562712Snn35248
13572712Snn35248 cvp.error = zonecfg_error_func;
13582712Snn35248 cvp.warning = zonecfg_error_func;
13592712Snn35248
13602712Snn35248 /*
13612712Snn35248 * We do a final validation of the document. Since the library has
13622712Snn35248 * malfunctioned if it fails to validate, we follow-up with an
13632712Snn35248 * assert() that the doc is valid.
13642712Snn35248 */
13652712Snn35248 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
13662712Snn35248 assert(valid != 0);
13672712Snn35248
13682712Snn35248 if (xmlSaveFormatFile(filename, handle->zone_dh_doc, 1) <= 0)
13692712Snn35248 return (Z_SAVING_FILE);
13702712Snn35248
13712712Snn35248 return (Z_OK);
13722712Snn35248 }
13732712Snn35248
13742712Snn35248 int
zonecfg_detach_save(zone_dochandle_t handle,uint_t flags)13752078Sgjelinek zonecfg_detach_save(zone_dochandle_t handle, uint_t flags)
13761507Sgjelinek {
13771507Sgjelinek char zname[ZONENAME_MAX];
13781507Sgjelinek char path[MAXPATHLEN];
13791507Sgjelinek char migpath[MAXPATHLEN];
13801507Sgjelinek xmlValidCtxt cvp = { NULL };
13811507Sgjelinek int err = Z_SAVING_FILE;
13822712Snn35248 int valid;
13831507Sgjelinek
13841507Sgjelinek if (zonecfg_check_handle(handle) != Z_OK)
13851507Sgjelinek return (Z_BAD_HANDLE);
13861507Sgjelinek
13872078Sgjelinek if (flags & ZONE_DRY_RUN) {
13882078Sgjelinek (void) strlcpy(migpath, "-", sizeof (migpath));
13892078Sgjelinek } else {
13902078Sgjelinek if ((err = zonecfg_get_name(handle, zname, sizeof (zname)))
13912078Sgjelinek != Z_OK)
13922078Sgjelinek return (err);
13932078Sgjelinek
13942078Sgjelinek if ((err = zone_get_zonepath(zname, path, sizeof (path)))
13952078Sgjelinek != Z_OK)
13962078Sgjelinek return (err);
13972078Sgjelinek
13987257Sgjelinek if (snprintf(migpath, sizeof (migpath), "%s/%s", path,
13997257Sgjelinek ZONE_DETACHED) >= sizeof (migpath))
14002078Sgjelinek return (Z_NOMEM);
14012078Sgjelinek }
14021507Sgjelinek
14031507Sgjelinek if ((err = operation_prep(handle)) != Z_OK)
14041507Sgjelinek return (err);
14051507Sgjelinek
14061507Sgjelinek addcomment(handle, "\n DO NOT EDIT THIS FILE. "
14071507Sgjelinek "Use zonecfg(1M) and zoneadm(1M) attach.\n");
14081507Sgjelinek
14091507Sgjelinek cvp.error = zonecfg_error_func;
14101507Sgjelinek cvp.warning = zonecfg_error_func;
14111507Sgjelinek
14121507Sgjelinek /*
14132712Snn35248 * We do a final validation of the document. Since the library has
14142712Snn35248 * malfunctioned if it fails to validate, we follow-up with an
14152712Snn35248 * assert() that the doc is valid.
14161507Sgjelinek */
14172712Snn35248 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
14182712Snn35248 assert(valid != 0);
14191507Sgjelinek
14201507Sgjelinek if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0)
14211507Sgjelinek return (Z_SAVING_FILE);
14221507Sgjelinek
14232078Sgjelinek if (!(flags & ZONE_DRY_RUN))
14242078Sgjelinek (void) chmod(migpath, 0644);
14251507Sgjelinek
14261507Sgjelinek stripcomments(handle);
14271507Sgjelinek
14281507Sgjelinek handle->zone_dh_newzone = B_FALSE;
14291507Sgjelinek
14301507Sgjelinek return (Z_OK);
14311507Sgjelinek }
14321507Sgjelinek
14331507Sgjelinek boolean_t
zonecfg_detached(const char * path)14341507Sgjelinek zonecfg_detached(const char *path)
14351507Sgjelinek {
14361507Sgjelinek char migpath[MAXPATHLEN];
14371507Sgjelinek struct stat buf;
14381507Sgjelinek
14397257Sgjelinek if (snprintf(migpath, sizeof (migpath), "%s/%s", path, ZONE_DETACHED) >=
14401507Sgjelinek sizeof (migpath))
14411507Sgjelinek return (B_FALSE);
14421507Sgjelinek
14431507Sgjelinek if (stat(migpath, &buf) != -1)
14441507Sgjelinek return (B_TRUE);
14451507Sgjelinek
14461507Sgjelinek return (B_FALSE);
14471507Sgjelinek }
14481507Sgjelinek
14491507Sgjelinek void
zonecfg_rm_detached(zone_dochandle_t handle,boolean_t forced)14501507Sgjelinek zonecfg_rm_detached(zone_dochandle_t handle, boolean_t forced)
14511507Sgjelinek {
14521507Sgjelinek char zname[ZONENAME_MAX];
14531507Sgjelinek char path[MAXPATHLEN];
14541507Sgjelinek char detached[MAXPATHLEN];
14551507Sgjelinek char attached[MAXPATHLEN];
14561507Sgjelinek
14571507Sgjelinek if (zonecfg_check_handle(handle) != Z_OK)
14581507Sgjelinek return;
14591507Sgjelinek
14601507Sgjelinek if (zonecfg_get_name(handle, zname, sizeof (zname)) != Z_OK)
14611507Sgjelinek return;
14621507Sgjelinek
14631507Sgjelinek if (zone_get_zonepath(zname, path, sizeof (path)) != Z_OK)
14641507Sgjelinek return;
14651507Sgjelinek
14667257Sgjelinek (void) snprintf(detached, sizeof (detached), "%s/%s", path,
14677257Sgjelinek ZONE_DETACHED);
14681507Sgjelinek (void) snprintf(attached, sizeof (attached), "%s/%s", path,
14691507Sgjelinek ATTACH_FORCED);
14701507Sgjelinek
14711507Sgjelinek if (forced) {
14721507Sgjelinek (void) rename(detached, attached);
14731507Sgjelinek } else {
14741507Sgjelinek (void) unlink(attached);
14751507Sgjelinek (void) unlink(detached);
14761507Sgjelinek }
14771507Sgjelinek }
14781507Sgjelinek
14790Sstevel@tonic-gate /*
14800Sstevel@tonic-gate * Special case: if access(2) fails with ENOENT, then try again using
14810Sstevel@tonic-gate * ZONE_CONFIG_ROOT instead of config_file_path(zonename). This is how we
14820Sstevel@tonic-gate * work around the case of a config file which has not been created yet:
14830Sstevel@tonic-gate * the user will need access to the directory so use that as a heuristic.
14840Sstevel@tonic-gate */
14850Sstevel@tonic-gate
14860Sstevel@tonic-gate int
zonecfg_access(const char * zonename,int amode)14870Sstevel@tonic-gate zonecfg_access(const char *zonename, int amode)
14880Sstevel@tonic-gate {
14890Sstevel@tonic-gate char path[MAXPATHLEN];
14900Sstevel@tonic-gate
1491766Scarlsonj if (!config_file_path(zonename, path))
1492766Scarlsonj return (Z_INVAL);
14930Sstevel@tonic-gate if (access(path, amode) == 0)
14940Sstevel@tonic-gate return (Z_OK);
1495766Scarlsonj if (errno == ENOENT) {
1496766Scarlsonj if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1497766Scarlsonj ZONE_CONFIG_ROOT) >= sizeof (path))
1498766Scarlsonj return (Z_INVAL);
1499766Scarlsonj if (access(path, amode) == 0)
1500766Scarlsonj return (Z_OK);
1501766Scarlsonj }
15020Sstevel@tonic-gate if (errno == EACCES)
15030Sstevel@tonic-gate return (Z_ACCES);
15040Sstevel@tonic-gate if (errno == EINVAL)
15050Sstevel@tonic-gate return (Z_INVAL);
15060Sstevel@tonic-gate return (Z_MISC_FS);
15070Sstevel@tonic-gate }
15080Sstevel@tonic-gate
15090Sstevel@tonic-gate int
zonecfg_create_snapshot(const char * zonename)1510766Scarlsonj zonecfg_create_snapshot(const char *zonename)
15110Sstevel@tonic-gate {
15120Sstevel@tonic-gate zone_dochandle_t handle;
15130Sstevel@tonic-gate char path[MAXPATHLEN], zonepath[MAXPATHLEN], rpath[MAXPATHLEN];
15140Sstevel@tonic-gate int error = Z_OK, res;
15150Sstevel@tonic-gate
15160Sstevel@tonic-gate if ((handle = zonecfg_init_handle()) == NULL) {
15170Sstevel@tonic-gate return (Z_NOMEM);
15180Sstevel@tonic-gate }
15190Sstevel@tonic-gate
1520565Sdp handle->zone_dh_newzone = B_TRUE;
1521565Sdp handle->zone_dh_snapshot = B_TRUE;
1522565Sdp
15230Sstevel@tonic-gate if ((error = zonecfg_get_handle(zonename, handle)) != Z_OK)
15240Sstevel@tonic-gate goto out;
15250Sstevel@tonic-gate if ((error = operation_prep(handle)) != Z_OK)
15260Sstevel@tonic-gate goto out;
15270Sstevel@tonic-gate error = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath));
15280Sstevel@tonic-gate if (error != Z_OK)
15290Sstevel@tonic-gate goto out;
15300Sstevel@tonic-gate if ((res = resolvepath(zonepath, rpath, sizeof (rpath))) == -1) {
15310Sstevel@tonic-gate error = Z_RESOLVED_PATH;
15320Sstevel@tonic-gate goto out;
15330Sstevel@tonic-gate }
15340Sstevel@tonic-gate /*
15350Sstevel@tonic-gate * If the resolved path is not the same as the original path, then
15360Sstevel@tonic-gate * save the resolved path in the snapshot, thus preventing any
15370Sstevel@tonic-gate * potential problems down the line when zoneadmd goes to unmount
15380Sstevel@tonic-gate * file systems and depends on initial string matches with resolved
15390Sstevel@tonic-gate * paths.
15400Sstevel@tonic-gate */
15410Sstevel@tonic-gate rpath[res] = '\0';
15420Sstevel@tonic-gate if (strcmp(zonepath, rpath) != 0) {
15430Sstevel@tonic-gate if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK)
15440Sstevel@tonic-gate goto out;
15450Sstevel@tonic-gate }
1546766Scarlsonj if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1547766Scarlsonj ZONE_SNAPSHOT_ROOT) >= sizeof (path)) {
15480Sstevel@tonic-gate error = Z_MISC_FS;
15490Sstevel@tonic-gate goto out;
15500Sstevel@tonic-gate }
1551766Scarlsonj if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) {
1552766Scarlsonj error = Z_MISC_FS;
1553766Scarlsonj goto out;
1554766Scarlsonj }
1555766Scarlsonj
1556766Scarlsonj if (!snap_file_path(zonename, path)) {
1557766Scarlsonj error = Z_MISC_FS;
1558766Scarlsonj goto out;
1559766Scarlsonj }
1560565Sdp
1561565Sdp addcomment(handle, "\n DO NOT EDIT THIS FILE. "
1562565Sdp "It is a snapshot of running zone state.\n");
1563565Sdp
15640Sstevel@tonic-gate error = zonecfg_save_impl(handle, path);
15650Sstevel@tonic-gate
1566565Sdp stripcomments(handle);
1567565Sdp
15680Sstevel@tonic-gate out:
15690Sstevel@tonic-gate zonecfg_fini_handle(handle);
15700Sstevel@tonic-gate return (error);
15710Sstevel@tonic-gate }
15720Sstevel@tonic-gate
15733448Sdh155122 int
zonecfg_get_iptype(zone_dochandle_t handle,zone_iptype_t * iptypep)15743448Sdh155122 zonecfg_get_iptype(zone_dochandle_t handle, zone_iptype_t *iptypep)
15753448Sdh155122 {
15763448Sdh155122 char property[10]; /* 10 is big enough for "shared"/"exclusive" */
15773448Sdh155122 int err;
15783448Sdh155122
15793448Sdh155122 err = getrootattr(handle, DTD_ATTR_IPTYPE, property, sizeof (property));
15803448Sdh155122 if (err == Z_BAD_PROPERTY) {
15813448Sdh155122 /* Return default value */
15823448Sdh155122 *iptypep = ZS_SHARED;
15833448Sdh155122 return (Z_OK);
15843448Sdh155122 } else if (err != Z_OK) {
15853448Sdh155122 return (err);
15863448Sdh155122 }
15873448Sdh155122
15883448Sdh155122 if (strlen(property) == 0 ||
15893448Sdh155122 strcmp(property, "shared") == 0)
15903448Sdh155122 *iptypep = ZS_SHARED;
15913448Sdh155122 else if (strcmp(property, "exclusive") == 0)
15923448Sdh155122 *iptypep = ZS_EXCLUSIVE;
15933448Sdh155122 else
15943448Sdh155122 return (Z_INVAL);
15953448Sdh155122
15963448Sdh155122 return (Z_OK);
15973448Sdh155122 }
15983448Sdh155122
15993448Sdh155122 int
zonecfg_set_iptype(zone_dochandle_t handle,zone_iptype_t iptype)16003448Sdh155122 zonecfg_set_iptype(zone_dochandle_t handle, zone_iptype_t iptype)
16013448Sdh155122 {
16023448Sdh155122 xmlNodePtr cur;
16033448Sdh155122
16043448Sdh155122 if (handle == NULL)
16053448Sdh155122 return (Z_INVAL);
16063448Sdh155122
16073448Sdh155122 cur = xmlDocGetRootElement(handle->zone_dh_doc);
16083448Sdh155122 if (cur == NULL) {
16093448Sdh155122 return (Z_EMPTY_DOCUMENT);
16103448Sdh155122 }
16113448Sdh155122
16123448Sdh155122 if (xmlStrcmp(cur->name, DTD_ELEM_ZONE) != 0) {
16133448Sdh155122 return (Z_WRONG_DOC_TYPE);
16143448Sdh155122 }
16153448Sdh155122 switch (iptype) {
16163448Sdh155122 case ZS_SHARED:
16173448Sdh155122 /*
16183448Sdh155122 * Since "shared" is the default, we don't write it to the
16193448Sdh155122 * configuration file, so that it's easier to migrate those
16203448Sdh155122 * zones elsewhere, eg., to systems which are not IP-Instances
16213448Sdh155122 * aware.
16223448Sdh155122 * xmlUnsetProp only fails when the attribute doesn't exist,
16233448Sdh155122 * which we don't care.
16243448Sdh155122 */
16253448Sdh155122 (void) xmlUnsetProp(cur, DTD_ATTR_IPTYPE);
16263448Sdh155122 break;
16273448Sdh155122 case ZS_EXCLUSIVE:
16283448Sdh155122 if (xmlSetProp(cur, DTD_ATTR_IPTYPE,
16293448Sdh155122 (const xmlChar *) "exclusive") == NULL)
16303448Sdh155122 return (Z_INVAL);
16313448Sdh155122 break;
16323448Sdh155122 }
16333448Sdh155122 return (Z_OK);
16343448Sdh155122 }
16353448Sdh155122
16360Sstevel@tonic-gate static int
newprop(xmlNodePtr node,const xmlChar * attrname,char * src)1637228Sdp newprop(xmlNodePtr node, const xmlChar *attrname, char *src)
16380Sstevel@tonic-gate {
16390Sstevel@tonic-gate xmlAttrPtr newattr;
16400Sstevel@tonic-gate
16410Sstevel@tonic-gate newattr = xmlNewProp(node, attrname, (xmlChar *)src);
16420Sstevel@tonic-gate if (newattr == NULL) {
16430Sstevel@tonic-gate xmlUnlinkNode(node);
16440Sstevel@tonic-gate xmlFreeNode(node);
16450Sstevel@tonic-gate return (Z_BAD_PROPERTY);
16460Sstevel@tonic-gate }
16470Sstevel@tonic-gate return (Z_OK);
16480Sstevel@tonic-gate }
16490Sstevel@tonic-gate
16500Sstevel@tonic-gate static int
zonecfg_add_filesystem_core(zone_dochandle_t handle,struct zone_fstab * tabptr)16510Sstevel@tonic-gate zonecfg_add_filesystem_core(zone_dochandle_t handle, struct zone_fstab *tabptr)
16520Sstevel@tonic-gate {
16530Sstevel@tonic-gate xmlNodePtr newnode, cur = handle->zone_dh_cur, options_node;
16540Sstevel@tonic-gate zone_fsopt_t *ptr;
16550Sstevel@tonic-gate int err;
16560Sstevel@tonic-gate
16570Sstevel@tonic-gate newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_FS, NULL);
1658228Sdp if ((err = newprop(newnode, DTD_ATTR_SPECIAL,
16590Sstevel@tonic-gate tabptr->zone_fs_special)) != Z_OK)
16600Sstevel@tonic-gate return (err);
16610Sstevel@tonic-gate if (tabptr->zone_fs_raw[0] != '\0' &&
1662228Sdp (err = newprop(newnode, DTD_ATTR_RAW, tabptr->zone_fs_raw)) != Z_OK)
16630Sstevel@tonic-gate return (err);
1664228Sdp if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK)
16650Sstevel@tonic-gate return (err);
1666228Sdp if ((err = newprop(newnode, DTD_ATTR_TYPE,
16670Sstevel@tonic-gate tabptr->zone_fs_type)) != Z_OK)
16680Sstevel@tonic-gate return (err);
16690Sstevel@tonic-gate if (tabptr->zone_fs_options != NULL) {
16700Sstevel@tonic-gate for (ptr = tabptr->zone_fs_options; ptr != NULL;
16710Sstevel@tonic-gate ptr = ptr->zone_fsopt_next) {
16720Sstevel@tonic-gate options_node = xmlNewTextChild(newnode, NULL,
16730Sstevel@tonic-gate DTD_ELEM_FSOPTION, NULL);
1674228Sdp if ((err = newprop(options_node, DTD_ATTR_NAME,
16750Sstevel@tonic-gate ptr->zone_fsopt_opt)) != Z_OK)
16760Sstevel@tonic-gate return (err);
16770Sstevel@tonic-gate }
16780Sstevel@tonic-gate }
16790Sstevel@tonic-gate return (Z_OK);
16800Sstevel@tonic-gate }
16810Sstevel@tonic-gate
16820Sstevel@tonic-gate int
zonecfg_add_filesystem(zone_dochandle_t handle,struct zone_fstab * tabptr)16830Sstevel@tonic-gate zonecfg_add_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
16840Sstevel@tonic-gate {
16850Sstevel@tonic-gate int err;
16860Sstevel@tonic-gate
16870Sstevel@tonic-gate if (tabptr == NULL)
16880Sstevel@tonic-gate return (Z_INVAL);
16890Sstevel@tonic-gate
16900Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK)
16910Sstevel@tonic-gate return (err);
16920Sstevel@tonic-gate
16930Sstevel@tonic-gate if ((err = zonecfg_add_filesystem_core(handle, tabptr)) != Z_OK)
16940Sstevel@tonic-gate return (err);
16950Sstevel@tonic-gate
16960Sstevel@tonic-gate return (Z_OK);
16970Sstevel@tonic-gate }
16980Sstevel@tonic-gate
16990Sstevel@tonic-gate int
zonecfg_add_fs_option(struct zone_fstab * tabptr,char * option)17000Sstevel@tonic-gate zonecfg_add_fs_option(struct zone_fstab *tabptr, char *option)
17010Sstevel@tonic-gate {
17020Sstevel@tonic-gate zone_fsopt_t *last, *old, *new;
17030Sstevel@tonic-gate
17040Sstevel@tonic-gate last = tabptr->zone_fs_options;
17050Sstevel@tonic-gate for (old = last; old != NULL; old = old->zone_fsopt_next)
17060Sstevel@tonic-gate last = old; /* walk to the end of the list */
17070Sstevel@tonic-gate new = (zone_fsopt_t *)malloc(sizeof (zone_fsopt_t));
17080Sstevel@tonic-gate if (new == NULL)
17090Sstevel@tonic-gate return (Z_NOMEM);
17100Sstevel@tonic-gate (void) strlcpy(new->zone_fsopt_opt, option,
17110Sstevel@tonic-gate sizeof (new->zone_fsopt_opt));
17120Sstevel@tonic-gate new->zone_fsopt_next = NULL;
17130Sstevel@tonic-gate if (last == NULL)
17140Sstevel@tonic-gate tabptr->zone_fs_options = new;
17150Sstevel@tonic-gate else
17160Sstevel@tonic-gate last->zone_fsopt_next = new;
17170Sstevel@tonic-gate return (Z_OK);
17180Sstevel@tonic-gate }
17190Sstevel@tonic-gate
17200Sstevel@tonic-gate int
zonecfg_remove_fs_option(struct zone_fstab * tabptr,char * option)17210Sstevel@tonic-gate zonecfg_remove_fs_option(struct zone_fstab *tabptr, char *option)
17220Sstevel@tonic-gate {
17230Sstevel@tonic-gate zone_fsopt_t *last, *this, *next;
17240Sstevel@tonic-gate
17250Sstevel@tonic-gate last = tabptr->zone_fs_options;
17260Sstevel@tonic-gate for (this = last; this != NULL; this = this->zone_fsopt_next) {
17270Sstevel@tonic-gate if (strcmp(this->zone_fsopt_opt, option) == 0) {
17280Sstevel@tonic-gate next = this->zone_fsopt_next;
17290Sstevel@tonic-gate if (this == tabptr->zone_fs_options)
17300Sstevel@tonic-gate tabptr->zone_fs_options = next;
17310Sstevel@tonic-gate else
17320Sstevel@tonic-gate last->zone_fsopt_next = next;
17330Sstevel@tonic-gate free(this);
17340Sstevel@tonic-gate return (Z_OK);
17350Sstevel@tonic-gate } else
17360Sstevel@tonic-gate last = this;
17370Sstevel@tonic-gate }
17380Sstevel@tonic-gate return (Z_NO_PROPERTY_ID);
17390Sstevel@tonic-gate }
17400Sstevel@tonic-gate
17410Sstevel@tonic-gate void
zonecfg_free_fs_option_list(zone_fsopt_t * list)17420Sstevel@tonic-gate zonecfg_free_fs_option_list(zone_fsopt_t *list)
17430Sstevel@tonic-gate {
17440Sstevel@tonic-gate zone_fsopt_t *this, *next;
17450Sstevel@tonic-gate
17460Sstevel@tonic-gate for (this = list; this != NULL; this = next) {
17470Sstevel@tonic-gate next = this->zone_fsopt_next;
17480Sstevel@tonic-gate free(this);
17490Sstevel@tonic-gate }
17500Sstevel@tonic-gate }
17510Sstevel@tonic-gate
17520Sstevel@tonic-gate void
zonecfg_free_rctl_value_list(struct zone_rctlvaltab * valtab)17530Sstevel@tonic-gate zonecfg_free_rctl_value_list(struct zone_rctlvaltab *valtab)
17540Sstevel@tonic-gate {
17550Sstevel@tonic-gate if (valtab == NULL)
17560Sstevel@tonic-gate return;
17570Sstevel@tonic-gate zonecfg_free_rctl_value_list(valtab->zone_rctlval_next);
17580Sstevel@tonic-gate free(valtab);
17590Sstevel@tonic-gate }
17600Sstevel@tonic-gate
17610Sstevel@tonic-gate static boolean_t
match_prop(xmlNodePtr cur,const xmlChar * attr,char * user_prop)17620Sstevel@tonic-gate match_prop(xmlNodePtr cur, const xmlChar *attr, char *user_prop)
17630Sstevel@tonic-gate {
17640Sstevel@tonic-gate xmlChar *gotten_prop;
17650Sstevel@tonic-gate int prop_result;
17660Sstevel@tonic-gate
17670Sstevel@tonic-gate gotten_prop = xmlGetProp(cur, attr);
17680Sstevel@tonic-gate if (gotten_prop == NULL) /* shouldn't happen */
17690Sstevel@tonic-gate return (B_FALSE);
17700Sstevel@tonic-gate prop_result = xmlStrcmp(gotten_prop, (const xmlChar *) user_prop);
17710Sstevel@tonic-gate xmlFree(gotten_prop);
17720Sstevel@tonic-gate return ((prop_result == 0));
17730Sstevel@tonic-gate }
17740Sstevel@tonic-gate
17750Sstevel@tonic-gate static int
zonecfg_delete_filesystem_core(zone_dochandle_t handle,struct zone_fstab * tabptr)17760Sstevel@tonic-gate zonecfg_delete_filesystem_core(zone_dochandle_t handle,
17770Sstevel@tonic-gate struct zone_fstab *tabptr)
17780Sstevel@tonic-gate {
17790Sstevel@tonic-gate xmlNodePtr cur = handle->zone_dh_cur;
17800Sstevel@tonic-gate boolean_t dir_match, spec_match, raw_match, type_match;
17810Sstevel@tonic-gate
17820Sstevel@tonic-gate for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
17830Sstevel@tonic-gate if (xmlStrcmp(cur->name, DTD_ELEM_FS))
17840Sstevel@tonic-gate continue;
17850Sstevel@tonic-gate dir_match = match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir);
17860Sstevel@tonic-gate spec_match = match_prop(cur, DTD_ATTR_SPECIAL,
17870Sstevel@tonic-gate tabptr->zone_fs_special);
17880Sstevel@tonic-gate raw_match = match_prop(cur, DTD_ATTR_RAW,
17890Sstevel@tonic-gate tabptr->zone_fs_raw);
17900Sstevel@tonic-gate type_match = match_prop(cur, DTD_ATTR_TYPE,
17910Sstevel@tonic-gate tabptr->zone_fs_type);
17920Sstevel@tonic-gate if (dir_match && spec_match && raw_match && type_match) {
17930Sstevel@tonic-gate xmlUnlinkNode(cur);
17940Sstevel@tonic-gate xmlFreeNode(cur);
17950Sstevel@tonic-gate return (Z_OK);
17960Sstevel@tonic-gate }
17970Sstevel@tonic-gate }
17980Sstevel@tonic-gate return (Z_NO_RESOURCE_ID);
17990Sstevel@tonic-gate }
18000Sstevel@tonic-gate
18010Sstevel@tonic-gate int
zonecfg_delete_filesystem(zone_dochandle_t handle,struct zone_fstab * tabptr)18020Sstevel@tonic-gate zonecfg_delete_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
18030Sstevel@tonic-gate {
18040Sstevel@tonic-gate int err;
18050Sstevel@tonic-gate
18060Sstevel@tonic-gate if (tabptr == NULL)
18070Sstevel@tonic-gate return (Z_INVAL);
18080Sstevel@tonic-gate
18090Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK)
18100Sstevel@tonic-gate return (err);
18110Sstevel@tonic-gate
18120Sstevel@tonic-gate if ((err = zonecfg_delete_filesystem_core(handle, tabptr)) != Z_OK)
18130Sstevel@tonic-gate return (err);
18140Sstevel@tonic-gate
18150Sstevel@tonic-gate return (Z_OK);
18160Sstevel@tonic-gate }
18170Sstevel@tonic-gate
18180Sstevel@tonic-gate int
zonecfg_modify_filesystem(zone_dochandle_t handle,struct zone_fstab * oldtabptr,struct zone_fstab * newtabptr)18190Sstevel@tonic-gate zonecfg_modify_filesystem(
18200Sstevel@tonic-gate zone_dochandle_t handle,
18210Sstevel@tonic-gate struct zone_fstab *oldtabptr,
18220Sstevel@tonic-gate struct zone_fstab *newtabptr)
18230Sstevel@tonic-gate {
18240Sstevel@tonic-gate int err;
18250Sstevel@tonic-gate
18260Sstevel@tonic-gate if (oldtabptr == NULL || newtabptr == NULL)
18270Sstevel@tonic-gate return (Z_INVAL);
18280Sstevel@tonic-gate
18290Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK)
18300Sstevel@tonic-gate return (err);
18310Sstevel@tonic-gate
18320Sstevel@tonic-gate if ((err = zonecfg_delete_filesystem_core(handle, oldtabptr)) != Z_OK)
18330Sstevel@tonic-gate return (err);
18340Sstevel@tonic-gate
18350Sstevel@tonic-gate if ((err = zonecfg_add_filesystem_core(handle, newtabptr)) != Z_OK)
18360Sstevel@tonic-gate return (err);
18370Sstevel@tonic-gate
18380Sstevel@tonic-gate return (Z_OK);
18390Sstevel@tonic-gate }
18400Sstevel@tonic-gate
18410Sstevel@tonic-gate int
zonecfg_lookup_filesystem(zone_dochandle_t handle,struct zone_fstab * tabptr)18420Sstevel@tonic-gate zonecfg_lookup_filesystem(
18430Sstevel@tonic-gate zone_dochandle_t handle,
18440Sstevel@tonic-gate struct zone_fstab *tabptr)
18450Sstevel@tonic-gate {
18460Sstevel@tonic-gate xmlNodePtr cur, options, firstmatch;
18470Sstevel@tonic-gate int err;
18480Sstevel@tonic-gate char dirname[MAXPATHLEN], special[MAXPATHLEN], raw[MAXPATHLEN];
18490Sstevel@tonic-gate char type[FSTYPSZ];
18500Sstevel@tonic-gate char options_str[MAX_MNTOPT_STR];
18510Sstevel@tonic-gate
18520Sstevel@tonic-gate if (tabptr == NULL)
18530Sstevel@tonic-gate return (Z_INVAL);
18540Sstevel@tonic-gate
18550Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK)
18560Sstevel@tonic-gate return (err);
18570Sstevel@tonic-gate
18580Sstevel@tonic-gate /*
18590Sstevel@tonic-gate * Walk the list of children looking for matches on any properties
18600Sstevel@tonic-gate * specified in the fstab parameter. If more than one resource
18610Sstevel@tonic-gate * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return
18620Sstevel@tonic-gate * Z_NO_RESOURCE_ID.
18630Sstevel@tonic-gate */
18640Sstevel@tonic-gate cur = handle->zone_dh_cur;
18650Sstevel@tonic-gate firstmatch = NULL;
18660Sstevel@tonic-gate for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
18670Sstevel@tonic-gate if (xmlStrcmp(cur->name, DTD_ELEM_FS))
18680Sstevel@tonic-gate continue;
18690Sstevel@tonic-gate if (strlen(tabptr->zone_fs_dir) > 0) {
18700Sstevel@tonic-gate if ((fetchprop(cur, DTD_ATTR_DIR, dirname,
18710Sstevel@tonic-gate sizeof (dirname)) == Z_OK) &&
18720Sstevel@tonic-gate (strcmp(tabptr->zone_fs_dir, dirname) == 0)) {
18730Sstevel@tonic-gate if (firstmatch == NULL)
18740Sstevel@tonic-gate firstmatch = cur;
18750Sstevel@tonic-gate else
18760Sstevel@tonic-gate return (Z_INSUFFICIENT_SPEC);
18770Sstevel@tonic-gate }
18780Sstevel@tonic-gate }
18790Sstevel@tonic-gate if (strlen(tabptr->zone_fs_special) > 0) {
18800Sstevel@tonic-gate if ((fetchprop(cur, DTD_ATTR_SPECIAL, special,
18810Sstevel@tonic-gate sizeof (special)) == Z_OK)) {
18820Sstevel@tonic-gate if (strcmp(tabptr->zone_fs_special,
18830Sstevel@tonic-gate special) == 0) {
18840Sstevel@tonic-gate if (firstmatch == NULL)
18850Sstevel@tonic-gate firstmatch = cur;
18860Sstevel@tonic-gate else if (firstmatch != cur)
18870Sstevel@tonic-gate return (Z_INSUFFICIENT_SPEC);
18880Sstevel@tonic-gate } else {
18890Sstevel@tonic-gate /*
18900Sstevel@tonic-gate * If another property matched but this
18910Sstevel@tonic-gate * one doesn't then reset firstmatch.
18920Sstevel@tonic-gate */
18930Sstevel@tonic-gate if (firstmatch == cur)
18940Sstevel@tonic-gate firstmatch = NULL;
18950Sstevel@tonic-gate }
18960Sstevel@tonic-gate }
18970Sstevel@tonic-gate }
18980Sstevel@tonic-gate if (strlen(tabptr->zone_fs_raw) > 0) {
18990Sstevel@tonic-gate if ((fetchprop(cur, DTD_ATTR_RAW, raw,
19000Sstevel@tonic-gate sizeof (raw)) == Z_OK)) {
19010Sstevel@tonic-gate if (strcmp(tabptr->zone_fs_raw, raw) == 0) {
19020Sstevel@tonic-gate if (firstmatch == NULL)
19030Sstevel@tonic-gate firstmatch = cur;
19040Sstevel@tonic-gate else if (firstmatch != cur)
19050Sstevel@tonic-gate return (Z_INSUFFICIENT_SPEC);
19060Sstevel@tonic-gate } else {
19070Sstevel@tonic-gate /*
19080Sstevel@tonic-gate * If another property matched but this
19090Sstevel@tonic-gate * one doesn't then reset firstmatch.
19100Sstevel@tonic-gate */
19110Sstevel@tonic-gate if (firstmatch == cur)
19120Sstevel@tonic-gate firstmatch = NULL;
19130Sstevel@tonic-gate }
19140Sstevel@tonic-gate }
19150Sstevel@tonic-gate }
19160Sstevel@tonic-gate if (strlen(tabptr->zone_fs_type) > 0) {
19170Sstevel@tonic-gate if ((fetchprop(cur, DTD_ATTR_TYPE, type,
19180Sstevel@tonic-gate sizeof (type)) == Z_OK)) {
19190Sstevel@tonic-gate if (strcmp(tabptr->zone_fs_type, type) == 0) {
19200Sstevel@tonic-gate if (firstmatch == NULL)
19210Sstevel@tonic-gate firstmatch = cur;
19220Sstevel@tonic-gate else if (firstmatch != cur)
19230Sstevel@tonic-gate return (Z_INSUFFICIENT_SPEC);
19240Sstevel@tonic-gate } else {
19250Sstevel@tonic-gate /*
19260Sstevel@tonic-gate * If another property matched but this
19270Sstevel@tonic-gate * one doesn't then reset firstmatch.
19280Sstevel@tonic-gate */
19290Sstevel@tonic-gate if (firstmatch == cur)
19300Sstevel@tonic-gate firstmatch = NULL;
19310Sstevel@tonic-gate }
19320Sstevel@tonic-gate }
19330Sstevel@tonic-gate }
19340Sstevel@tonic-gate }
19350Sstevel@tonic-gate
19360Sstevel@tonic-gate if (firstmatch == NULL)
19370Sstevel@tonic-gate return (Z_NO_RESOURCE_ID);
19380Sstevel@tonic-gate
19390Sstevel@tonic-gate cur = firstmatch;
19400Sstevel@tonic-gate
19410Sstevel@tonic-gate if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
19420Sstevel@tonic-gate sizeof (tabptr->zone_fs_dir))) != Z_OK)
19430Sstevel@tonic-gate return (err);
19440Sstevel@tonic-gate
19450Sstevel@tonic-gate if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
19460Sstevel@tonic-gate sizeof (tabptr->zone_fs_special))) != Z_OK)
19470Sstevel@tonic-gate return (err);
19480Sstevel@tonic-gate
19490Sstevel@tonic-gate if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
19500Sstevel@tonic-gate sizeof (tabptr->zone_fs_raw))) != Z_OK)
19510Sstevel@tonic-gate return (err);
19520Sstevel@tonic-gate
19530Sstevel@tonic-gate if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
19540Sstevel@tonic-gate sizeof (tabptr->zone_fs_type))) != Z_OK)
19550Sstevel@tonic-gate return (err);
19560Sstevel@tonic-gate
19570Sstevel@tonic-gate /* options are optional */
19580Sstevel@tonic-gate tabptr->zone_fs_options = NULL;
19590Sstevel@tonic-gate for (options = cur->xmlChildrenNode; options != NULL;
19600Sstevel@tonic-gate options = options->next) {
19610Sstevel@tonic-gate if ((fetchprop(options, DTD_ATTR_NAME, options_str,
19620Sstevel@tonic-gate sizeof (options_str)) != Z_OK))
19630Sstevel@tonic-gate break;
19640Sstevel@tonic-gate if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
19650Sstevel@tonic-gate break;
19660Sstevel@tonic-gate }
19670Sstevel@tonic-gate return (Z_OK);
19680Sstevel@tonic-gate }
19690Sstevel@tonic-gate
19700Sstevel@tonic-gate /*
19710Sstevel@tonic-gate * Compare two IP addresses in string form. Allow for the possibility that
19720Sstevel@tonic-gate * one might have "/<prefix-length>" at the end: allow a match on just the
19730Sstevel@tonic-gate * IP address (or host name) part.
19740Sstevel@tonic-gate */
19750Sstevel@tonic-gate
19760Sstevel@tonic-gate boolean_t
zonecfg_same_net_address(char * a1,char * a2)19770Sstevel@tonic-gate zonecfg_same_net_address(char *a1, char *a2)
19780Sstevel@tonic-gate {
19790Sstevel@tonic-gate char *slashp, *slashp1, *slashp2;
19800Sstevel@tonic-gate int result;
19810Sstevel@tonic-gate
19820Sstevel@tonic-gate if (strcmp(a1, a2) == 0)
19830Sstevel@tonic-gate return (B_TRUE);
19840Sstevel@tonic-gate
19850Sstevel@tonic-gate /*
19860Sstevel@tonic-gate * If neither has a slash or both do, they need to match to be
19870Sstevel@tonic-gate * considered the same, but they did not match above, so fail.
19880Sstevel@tonic-gate */
19890Sstevel@tonic-gate slashp1 = strchr(a1, '/');
19900Sstevel@tonic-gate slashp2 = strchr(a2, '/');
19910Sstevel@tonic-gate if ((slashp1 == NULL && slashp2 == NULL) ||
19920Sstevel@tonic-gate (slashp1 != NULL && slashp2 != NULL))
19930Sstevel@tonic-gate return (B_FALSE);
19940Sstevel@tonic-gate
19950Sstevel@tonic-gate /*
19960Sstevel@tonic-gate * Only one had a slash: pick that one, zero out the slash, compare
19970Sstevel@tonic-gate * the "address only" strings, restore the slash, and return the
19980Sstevel@tonic-gate * result of the comparison.
19990Sstevel@tonic-gate */
20000Sstevel@tonic-gate slashp = (slashp1 == NULL) ? slashp2 : slashp1;
20010Sstevel@tonic-gate *slashp = '\0';
20020Sstevel@tonic-gate result = strcmp(a1, a2);
20030Sstevel@tonic-gate *slashp = '/';
20040Sstevel@tonic-gate return ((result == 0));
20050Sstevel@tonic-gate }
20060Sstevel@tonic-gate
20070Sstevel@tonic-gate int
zonecfg_valid_net_address(char * address,struct lifreq * lifr)20080Sstevel@tonic-gate zonecfg_valid_net_address(char *address, struct lifreq *lifr)
20090Sstevel@tonic-gate {
20100Sstevel@tonic-gate struct sockaddr_in *sin4;
20110Sstevel@tonic-gate struct sockaddr_in6 *sin6;
20120Sstevel@tonic-gate struct addrinfo hints, *result;
20130Sstevel@tonic-gate char *slashp = strchr(address, '/');
20140Sstevel@tonic-gate
20150Sstevel@tonic-gate bzero(lifr, sizeof (struct lifreq));
20160Sstevel@tonic-gate sin4 = (struct sockaddr_in *)&lifr->lifr_addr;
20170Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)&lifr->lifr_addr;
20180Sstevel@tonic-gate if (slashp != NULL)
20190Sstevel@tonic-gate *slashp = '\0';
20200Sstevel@tonic-gate if (inet_pton(AF_INET, address, &sin4->sin_addr) == 1) {
20210Sstevel@tonic-gate sin4->sin_family = AF_INET;
20220Sstevel@tonic-gate } else if (inet_pton(AF_INET6, address, &sin6->sin6_addr) == 1) {
20230Sstevel@tonic-gate if (slashp == NULL)
20240Sstevel@tonic-gate return (Z_IPV6_ADDR_PREFIX_LEN);
20250Sstevel@tonic-gate sin6->sin6_family = AF_INET6;
20260Sstevel@tonic-gate } else {
20270Sstevel@tonic-gate /* "address" may be a host name */
20280Sstevel@tonic-gate (void) memset(&hints, 0, sizeof (hints));
20290Sstevel@tonic-gate hints.ai_family = PF_INET;
20300Sstevel@tonic-gate if (getaddrinfo(address, NULL, &hints, &result) != 0)
20310Sstevel@tonic-gate return (Z_BOGUS_ADDRESS);
20320Sstevel@tonic-gate sin4->sin_family = result->ai_family;
2033228Sdp
20340Sstevel@tonic-gate (void) memcpy(&sin4->sin_addr,
20350Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
20360Sstevel@tonic-gate &((struct sockaddr_in *)result->ai_addr)->sin_addr,
20370Sstevel@tonic-gate sizeof (struct in_addr));
2038228Sdp
20390Sstevel@tonic-gate freeaddrinfo(result);
20400Sstevel@tonic-gate }
20410Sstevel@tonic-gate return (Z_OK);
20420Sstevel@tonic-gate }
20430Sstevel@tonic-gate
20443448Sdh155122 boolean_t
zonecfg_ifname_exists(sa_family_t af,char * ifname)20453448Sdh155122 zonecfg_ifname_exists(sa_family_t af, char *ifname)
20463448Sdh155122 {
20473448Sdh155122 struct lifreq lifr;
20483448Sdh155122 int so;
20493448Sdh155122 int save_errno;
20503448Sdh155122
20513448Sdh155122 (void) memset(&lifr, 0, sizeof (lifr));
20523448Sdh155122 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
20533448Sdh155122 lifr.lifr_addr.ss_family = af;
20543448Sdh155122 if ((so = socket(af, SOCK_DGRAM, 0)) < 0) {
20553448Sdh155122 /* Odd - can't tell if the ifname exists */
20563448Sdh155122 return (B_FALSE);
20573448Sdh155122 }
20583448Sdh155122 if (ioctl(so, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
20593448Sdh155122 save_errno = errno;
20603448Sdh155122 (void) close(so);
20613448Sdh155122 errno = save_errno;
20623448Sdh155122 return (B_FALSE);
20633448Sdh155122 }
20643448Sdh155122 (void) close(so);
20653448Sdh155122 return (B_TRUE);
20663448Sdh155122 }
20673448Sdh155122
20687267Sjv227347 /*
206911435SJordan.Vaughan@Sun.com * Determines whether there is a net resource with the physical interface, IP
207011435SJordan.Vaughan@Sun.com * address, and default router specified by 'tabptr' in the zone configuration
207111435SJordan.Vaughan@Sun.com * to which 'handle' refers. 'tabptr' must have an interface, an address, a
207211435SJordan.Vaughan@Sun.com * default router, or a combination of the three. This function returns Z_OK
207311435SJordan.Vaughan@Sun.com * iff there is exactly one net resource matching the query specified by
207411435SJordan.Vaughan@Sun.com * 'tabptr'. The function returns Z_INSUFFICIENT_SPEC if there are multiple
207511435SJordan.Vaughan@Sun.com * matches or 'tabptr' does not specify a physical interface, address, or
207611435SJordan.Vaughan@Sun.com * default router. The function returns Z_NO_RESOURCE_ID if are no matches.
20777267Sjv227347 *
20787267Sjv227347 * Errors might also be returned if the entry that exactly matches the
20797267Sjv227347 * query lacks critical network resource information.
20807267Sjv227347 *
208111435SJordan.Vaughan@Sun.com * If there is a single match, then the matching entry's physical interface, IP
208211435SJordan.Vaughan@Sun.com * address, and default router information are stored in 'tabptr'.
20837267Sjv227347 */
20840Sstevel@tonic-gate int
zonecfg_lookup_nwif(zone_dochandle_t handle,struct zone_nwiftab * tabptr)20850Sstevel@tonic-gate zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
20860Sstevel@tonic-gate {
20877267Sjv227347 xmlNodePtr cur;
20887267Sjv227347 xmlNodePtr firstmatch;
20890Sstevel@tonic-gate int err;
20907267Sjv227347 char address[INET6_ADDRSTRLEN];
20917267Sjv227347 char physical[LIFNAMSIZ];
20927267Sjv227347 size_t addrspec; /* nonzero if tabptr has IP addr */
20937267Sjv227347 size_t physspec; /* nonzero if tabptr has interface */
209411435SJordan.Vaughan@Sun.com size_t defrouterspec; /* nonzero if tabptr has def. router */
209512748SSowmini.Varadhan@oracle.COM size_t allowed_addrspec;
209612748SSowmini.Varadhan@oracle.COM zone_iptype_t iptype;
20970Sstevel@tonic-gate
20980Sstevel@tonic-gate if (tabptr == NULL)
20990Sstevel@tonic-gate return (Z_INVAL);
21000Sstevel@tonic-gate
21017267Sjv227347 /*
210211435SJordan.Vaughan@Sun.com * Determine the fields that will be searched. There must be at least
210311435SJordan.Vaughan@Sun.com * one.
210411435SJordan.Vaughan@Sun.com *
210511435SJordan.Vaughan@Sun.com * zone_nwif_address, zone_nwif_physical, and zone_nwif_defrouter are
210611435SJordan.Vaughan@Sun.com * arrays, so no NULL checks are necessary.
21077267Sjv227347 */
21087267Sjv227347 addrspec = strlen(tabptr->zone_nwif_address);
21097267Sjv227347 physspec = strlen(tabptr->zone_nwif_physical);
211011435SJordan.Vaughan@Sun.com defrouterspec = strlen(tabptr->zone_nwif_defrouter);
211112748SSowmini.Varadhan@oracle.COM allowed_addrspec = strlen(tabptr->zone_nwif_allowed_address);
211212748SSowmini.Varadhan@oracle.COM if (addrspec != 0 && allowed_addrspec != 0)
211312748SSowmini.Varadhan@oracle.COM return (Z_INVAL); /* can't specify both */
211412748SSowmini.Varadhan@oracle.COM if (addrspec == 0 && physspec == 0 && defrouterspec == 0 &&
211512748SSowmini.Varadhan@oracle.COM allowed_addrspec == 0)
211611435SJordan.Vaughan@Sun.com return (Z_INSUFFICIENT_SPEC);
21177267Sjv227347
21180Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK)
21190Sstevel@tonic-gate return (err);
21200Sstevel@tonic-gate
212112748SSowmini.Varadhan@oracle.COM if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK)
212212748SSowmini.Varadhan@oracle.COM return (err);
212311435SJordan.Vaughan@Sun.com /*
212411435SJordan.Vaughan@Sun.com * Iterate over the configuration's elements and look for net elements
212511435SJordan.Vaughan@Sun.com * that match the query.
212611435SJordan.Vaughan@Sun.com */
21277267Sjv227347 firstmatch = NULL;
21280Sstevel@tonic-gate cur = handle->zone_dh_cur;
21290Sstevel@tonic-gate for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
21307267Sjv227347 /* Skip non-net elements */
21310Sstevel@tonic-gate if (xmlStrcmp(cur->name, DTD_ELEM_NET))
21320Sstevel@tonic-gate continue;
21337267Sjv227347
21347267Sjv227347 /*
213511435SJordan.Vaughan@Sun.com * If any relevant fields don't match the query, then skip
213611435SJordan.Vaughan@Sun.com * the current net element.
21377267Sjv227347 */
213811435SJordan.Vaughan@Sun.com if (physspec != 0 && (fetchprop(cur, DTD_ATTR_PHYSICAL,
213911435SJordan.Vaughan@Sun.com physical, sizeof (physical)) != Z_OK ||
214011435SJordan.Vaughan@Sun.com strcmp(tabptr->zone_nwif_physical, physical) != 0))
214111435SJordan.Vaughan@Sun.com continue;
214212748SSowmini.Varadhan@oracle.COM if (iptype == ZS_SHARED && addrspec != 0 &&
214312748SSowmini.Varadhan@oracle.COM (fetchprop(cur, DTD_ATTR_ADDRESS, address,
214411435SJordan.Vaughan@Sun.com sizeof (address)) != Z_OK ||
214511435SJordan.Vaughan@Sun.com !zonecfg_same_net_address(tabptr->zone_nwif_address,
214611435SJordan.Vaughan@Sun.com address)))
214711435SJordan.Vaughan@Sun.com continue;
214812748SSowmini.Varadhan@oracle.COM if (iptype == ZS_EXCLUSIVE && allowed_addrspec != 0 &&
214912748SSowmini.Varadhan@oracle.COM (fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS, address,
215012748SSowmini.Varadhan@oracle.COM sizeof (address)) != Z_OK ||
215112748SSowmini.Varadhan@oracle.COM !zonecfg_same_net_address(tabptr->zone_nwif_allowed_address,
215212748SSowmini.Varadhan@oracle.COM address)))
215312748SSowmini.Varadhan@oracle.COM continue;
215411435SJordan.Vaughan@Sun.com if (defrouterspec != 0 && (fetchprop(cur, DTD_ATTR_DEFROUTER,
215511435SJordan.Vaughan@Sun.com address, sizeof (address)) != Z_OK ||
215611435SJordan.Vaughan@Sun.com !zonecfg_same_net_address(tabptr->zone_nwif_defrouter,
215711435SJordan.Vaughan@Sun.com address)))
215811435SJordan.Vaughan@Sun.com continue;
215911435SJordan.Vaughan@Sun.com
216011435SJordan.Vaughan@Sun.com /*
216111435SJordan.Vaughan@Sun.com * The current net element matches the query. Select it if
216211435SJordan.Vaughan@Sun.com * it's the first match; otherwise, abort the search.
216311435SJordan.Vaughan@Sun.com */
216411435SJordan.Vaughan@Sun.com if (firstmatch == NULL)
216511435SJordan.Vaughan@Sun.com firstmatch = cur;
216611435SJordan.Vaughan@Sun.com else
216711435SJordan.Vaughan@Sun.com return (Z_INSUFFICIENT_SPEC);
21680Sstevel@tonic-gate }
21690Sstevel@tonic-gate if (firstmatch == NULL)
21700Sstevel@tonic-gate return (Z_NO_RESOURCE_ID);
21710Sstevel@tonic-gate
21720Sstevel@tonic-gate cur = firstmatch;
21730Sstevel@tonic-gate
21740Sstevel@tonic-gate if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
21750Sstevel@tonic-gate sizeof (tabptr->zone_nwif_physical))) != Z_OK)
21760Sstevel@tonic-gate return (err);
21770Sstevel@tonic-gate
217812748SSowmini.Varadhan@oracle.COM if (iptype == ZS_SHARED &&
217912748SSowmini.Varadhan@oracle.COM (err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
21800Sstevel@tonic-gate sizeof (tabptr->zone_nwif_address))) != Z_OK)
21810Sstevel@tonic-gate return (err);
21820Sstevel@tonic-gate
218312748SSowmini.Varadhan@oracle.COM if (iptype == ZS_EXCLUSIVE &&
218412748SSowmini.Varadhan@oracle.COM (err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
218512748SSowmini.Varadhan@oracle.COM tabptr->zone_nwif_allowed_address,
218612748SSowmini.Varadhan@oracle.COM sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK)
218712748SSowmini.Varadhan@oracle.COM return (err);
218812748SSowmini.Varadhan@oracle.COM
21896076Sgfaden if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
21906076Sgfaden tabptr->zone_nwif_defrouter,
21916076Sgfaden sizeof (tabptr->zone_nwif_defrouter))) != Z_OK)
21926076Sgfaden return (err);
21936076Sgfaden
21940Sstevel@tonic-gate return (Z_OK);
21950Sstevel@tonic-gate }
21960Sstevel@tonic-gate
21970Sstevel@tonic-gate static int
zonecfg_add_nwif_core(zone_dochandle_t handle,struct zone_nwiftab * tabptr)21980Sstevel@tonic-gate zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
21990Sstevel@tonic-gate {
22000Sstevel@tonic-gate xmlNodePtr newnode, cur = handle->zone_dh_cur;
22010Sstevel@tonic-gate int err;
22020Sstevel@tonic-gate
22030Sstevel@tonic-gate newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL);
220412748SSowmini.Varadhan@oracle.COM if (strlen(tabptr->zone_nwif_address) > 0 &&
220512748SSowmini.Varadhan@oracle.COM (err = newprop(newnode, DTD_ATTR_ADDRESS,
22060Sstevel@tonic-gate tabptr->zone_nwif_address)) != Z_OK)
22070Sstevel@tonic-gate return (err);
220812748SSowmini.Varadhan@oracle.COM if (strlen(tabptr->zone_nwif_allowed_address) > 0 &&
220912748SSowmini.Varadhan@oracle.COM (err = newprop(newnode, DTD_ATTR_ALLOWED_ADDRESS,
221012748SSowmini.Varadhan@oracle.COM tabptr->zone_nwif_allowed_address)) != Z_OK)
221112748SSowmini.Varadhan@oracle.COM return (err);
2212228Sdp if ((err = newprop(newnode, DTD_ATTR_PHYSICAL,
22130Sstevel@tonic-gate tabptr->zone_nwif_physical)) != Z_OK)
22140Sstevel@tonic-gate return (err);
22156738Sjparcel /*
22166738Sjparcel * Do not add this property when it is not set, for backwards
22176738Sjparcel * compatibility and because it is optional.
22186738Sjparcel */
22196738Sjparcel if ((strlen(tabptr->zone_nwif_defrouter) > 0) &&
22206738Sjparcel ((err = newprop(newnode, DTD_ATTR_DEFROUTER,
22216738Sjparcel tabptr->zone_nwif_defrouter)) != Z_OK))
22226076Sgfaden return (err);
22230Sstevel@tonic-gate return (Z_OK);
22240Sstevel@tonic-gate }
22250Sstevel@tonic-gate
22260Sstevel@tonic-gate int
zonecfg_add_nwif(zone_dochandle_t handle,struct zone_nwiftab * tabptr)22270Sstevel@tonic-gate zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
22280Sstevel@tonic-gate {
22290Sstevel@tonic-gate int err;
22300Sstevel@tonic-gate
22310Sstevel@tonic-gate if (tabptr == NULL)
22320Sstevel@tonic-gate return (Z_INVAL);
22330Sstevel@tonic-gate
22340Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK)
22350Sstevel@tonic-gate return (err);
22360Sstevel@tonic-gate
22370Sstevel@tonic-gate if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK)
22380Sstevel@tonic-gate return (err);
22390Sstevel@tonic-gate
22400Sstevel@tonic-gate return (Z_OK);
22410Sstevel@tonic-gate }
22420Sstevel@tonic-gate
22430Sstevel@tonic-gate static int
zonecfg_delete_nwif_core(zone_dochandle_t handle,struct zone_nwiftab * tabptr)22440Sstevel@tonic-gate zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
22450Sstevel@tonic-gate {
22460Sstevel@tonic-gate xmlNodePtr cur = handle->zone_dh_cur;
224712748SSowmini.Varadhan@oracle.COM boolean_t addr_match, phys_match, allowed_addr_match;
22480Sstevel@tonic-gate
22490Sstevel@tonic-gate for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
22500Sstevel@tonic-gate if (xmlStrcmp(cur->name, DTD_ELEM_NET))
22510Sstevel@tonic-gate continue;
22520Sstevel@tonic-gate
22530Sstevel@tonic-gate addr_match = match_prop(cur, DTD_ATTR_ADDRESS,
22540Sstevel@tonic-gate tabptr->zone_nwif_address);
225512748SSowmini.Varadhan@oracle.COM allowed_addr_match = match_prop(cur, DTD_ATTR_ALLOWED_ADDRESS,
225612748SSowmini.Varadhan@oracle.COM tabptr->zone_nwif_allowed_address);
22570Sstevel@tonic-gate phys_match = match_prop(cur, DTD_ATTR_PHYSICAL,
22580Sstevel@tonic-gate tabptr->zone_nwif_physical);
22590Sstevel@tonic-gate
226012748SSowmini.Varadhan@oracle.COM if ((addr_match || allowed_addr_match) && phys_match) {
22610Sstevel@tonic-gate xmlUnlinkNode(cur);
22620Sstevel@tonic-gate xmlFreeNode(cur);
22630Sstevel@tonic-gate return (Z_OK);
22640Sstevel@tonic-gate }
22650Sstevel@tonic-gate }
22660Sstevel@tonic-gate return (Z_NO_RESOURCE_ID);
22670Sstevel@tonic-gate }
22680Sstevel@tonic-gate
22690Sstevel@tonic-gate int
zonecfg_delete_nwif(zone_dochandle_t handle,struct zone_nwiftab * tabptr)22700Sstevel@tonic-gate zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
22710Sstevel@tonic-gate {
22720Sstevel@tonic-gate int err;
22730Sstevel@tonic-gate
22740Sstevel@tonic-gate if (tabptr == NULL)
22750Sstevel@tonic-gate return (Z_INVAL);
22760Sstevel@tonic-gate
22770Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK)
22780Sstevel@tonic-gate return (err);
22790Sstevel@tonic-gate
22800Sstevel@tonic-gate if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK)
22810Sstevel@tonic-gate return (err);
22820Sstevel@tonic-gate
22830Sstevel@tonic-gate return (Z_OK);
22840Sstevel@tonic-gate }
22850Sstevel@tonic-gate
22860Sstevel@tonic-gate int
zonecfg_modify_nwif(zone_dochandle_t handle,struct zone_nwiftab * oldtabptr,struct zone_nwiftab * newtabptr)22870Sstevel@tonic-gate zonecfg_modify_nwif(
22880Sstevel@tonic-gate zone_dochandle_t handle,
22890Sstevel@tonic-gate struct zone_nwiftab *oldtabptr,
22900Sstevel@tonic-gate struct zone_nwiftab *newtabptr)
22910Sstevel@tonic-gate {
22920Sstevel@tonic-gate int err;
22930Sstevel@tonic-gate
22940Sstevel@tonic-gate if (oldtabptr == NULL || newtabptr == NULL)
22950Sstevel@tonic-gate return (Z_INVAL);
22960Sstevel@tonic-gate
22970Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK)
22980Sstevel@tonic-gate return (err);
22990Sstevel@tonic-gate
23000Sstevel@tonic-gate if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK)
23010Sstevel@tonic-gate return (err);
23020Sstevel@tonic-gate
23030Sstevel@tonic-gate if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK)
23040Sstevel@tonic-gate return (err);
23050Sstevel@tonic-gate
23060Sstevel@tonic-gate return (Z_OK);
23070Sstevel@tonic-gate }
23080Sstevel@tonic-gate
23098662SJordan.Vaughan@Sun.com /*
231012633Sjohn.levon@sun.com * Must be a comma-separated list of alpha-numeric file system names.
231112633Sjohn.levon@sun.com */
231212633Sjohn.levon@sun.com static int
zonecfg_valid_fs_allowed(const char * fsallowedp)231312633Sjohn.levon@sun.com zonecfg_valid_fs_allowed(const char *fsallowedp)
231412633Sjohn.levon@sun.com {
231512633Sjohn.levon@sun.com char tmp[ZONE_FS_ALLOWED_MAX];
231612633Sjohn.levon@sun.com char *cp = tmp;
231712633Sjohn.levon@sun.com char *p;
231812633Sjohn.levon@sun.com
231912633Sjohn.levon@sun.com if (strlen(fsallowedp) > ZONE_FS_ALLOWED_MAX)
232012633Sjohn.levon@sun.com return (Z_TOO_BIG);
232112633Sjohn.levon@sun.com
232212633Sjohn.levon@sun.com (void) strlcpy(tmp, fsallowedp, sizeof (tmp));
232312633Sjohn.levon@sun.com
232412633Sjohn.levon@sun.com while (*cp != '\0') {
232512633Sjohn.levon@sun.com p = cp;
232612633Sjohn.levon@sun.com while (*p != '\0' && *p != ',') {
232712633Sjohn.levon@sun.com if (!isalnum(*p))
232812633Sjohn.levon@sun.com return (Z_INVALID_PROPERTY);
232912633Sjohn.levon@sun.com p++;
233012633Sjohn.levon@sun.com }
233112633Sjohn.levon@sun.com
233212633Sjohn.levon@sun.com if (*p == ',') {
233312633Sjohn.levon@sun.com if (p == cp)
233412633Sjohn.levon@sun.com return (Z_INVALID_PROPERTY);
233512633Sjohn.levon@sun.com
233612633Sjohn.levon@sun.com p++;
233712633Sjohn.levon@sun.com
233812633Sjohn.levon@sun.com if (*p == '\0')
233912633Sjohn.levon@sun.com return (Z_INVALID_PROPERTY);
234012633Sjohn.levon@sun.com }
234112633Sjohn.levon@sun.com
234212633Sjohn.levon@sun.com cp = p;
234312633Sjohn.levon@sun.com }
234412633Sjohn.levon@sun.com
234512633Sjohn.levon@sun.com return (Z_OK);
234612633Sjohn.levon@sun.com }
234712633Sjohn.levon@sun.com
234812633Sjohn.levon@sun.com int
zonecfg_get_fs_allowed(zone_dochandle_t handle,char * bufp,size_t buflen)234912633Sjohn.levon@sun.com zonecfg_get_fs_allowed(zone_dochandle_t handle, char *bufp, size_t buflen)
235012633Sjohn.levon@sun.com {
235112633Sjohn.levon@sun.com int err;
235212633Sjohn.levon@sun.com
235312633Sjohn.levon@sun.com if ((err = getrootattr(handle, DTD_ATTR_FS_ALLOWED,
235412633Sjohn.levon@sun.com bufp, buflen)) != Z_OK)
235512633Sjohn.levon@sun.com return (err);
235612633Sjohn.levon@sun.com if (bufp[0] == '\0')
235712633Sjohn.levon@sun.com return (Z_BAD_PROPERTY);
235812633Sjohn.levon@sun.com return (zonecfg_valid_fs_allowed(bufp));
235912633Sjohn.levon@sun.com }
236012633Sjohn.levon@sun.com
236112633Sjohn.levon@sun.com int
zonecfg_set_fs_allowed(zone_dochandle_t handle,const char * bufp)236212633Sjohn.levon@sun.com zonecfg_set_fs_allowed(zone_dochandle_t handle, const char *bufp)
236312633Sjohn.levon@sun.com {
236412633Sjohn.levon@sun.com int err;
236512633Sjohn.levon@sun.com
236612633Sjohn.levon@sun.com if (bufp == NULL || (err = zonecfg_valid_fs_allowed(bufp)) == Z_OK)
236712633Sjohn.levon@sun.com return (setrootattr(handle, DTD_ATTR_FS_ALLOWED, bufp));
236812633Sjohn.levon@sun.com return (err);
236912633Sjohn.levon@sun.com }
237012633Sjohn.levon@sun.com
237112633Sjohn.levon@sun.com /*
237212633Sjohn.levon@sun.com * Determines if the specified string is a valid hostid string. This function
237312633Sjohn.levon@sun.com * returns Z_OK if the string is a valid hostid string. It returns Z_INVAL if
237412633Sjohn.levon@sun.com * 'hostidp' is NULL, Z_TOO_BIG if 'hostidp' refers to a string buffer
237512633Sjohn.levon@sun.com * containing a hex string with more than 8 digits, and Z_INVALID_PROPERTY if
237612633Sjohn.levon@sun.com * the string has an invalid format.
237712633Sjohn.levon@sun.com */
237812633Sjohn.levon@sun.com static int
zonecfg_valid_hostid(const char * hostidp)237912633Sjohn.levon@sun.com zonecfg_valid_hostid(const char *hostidp)
238012633Sjohn.levon@sun.com {
238112633Sjohn.levon@sun.com char *currentp;
238212633Sjohn.levon@sun.com u_longlong_t hostidval;
238312633Sjohn.levon@sun.com size_t len;
238412633Sjohn.levon@sun.com
238512633Sjohn.levon@sun.com if (hostidp == NULL)
238612633Sjohn.levon@sun.com return (Z_INVAL);
238712633Sjohn.levon@sun.com
238812633Sjohn.levon@sun.com /* Empty strings and strings with whitespace are invalid. */
238912633Sjohn.levon@sun.com if (*hostidp == '\0')
239012633Sjohn.levon@sun.com return (Z_INVALID_PROPERTY);
239112633Sjohn.levon@sun.com for (currentp = (char *)hostidp; *currentp != '\0'; ++currentp) {
239212633Sjohn.levon@sun.com if (isspace(*currentp))
239312633Sjohn.levon@sun.com return (Z_INVALID_PROPERTY);
239412633Sjohn.levon@sun.com }
239512633Sjohn.levon@sun.com len = (size_t)(currentp - hostidp);
239612633Sjohn.levon@sun.com
239712633Sjohn.levon@sun.com /*
239812633Sjohn.levon@sun.com * The caller might pass a hostid that is larger than the maximum
239912633Sjohn.levon@sun.com * unsigned 32-bit integral value. Check for this! Also, make sure
240012633Sjohn.levon@sun.com * that the whole string is converted (this helps us find illegal
240112633Sjohn.levon@sun.com * characters) and that the whole string fits within a buffer of size
240212633Sjohn.levon@sun.com * HW_HOSTID_LEN.
240312633Sjohn.levon@sun.com */
240412633Sjohn.levon@sun.com currentp = (char *)hostidp;
240512633Sjohn.levon@sun.com if (strncmp(hostidp, "0x", 2) == 0 || strncmp(hostidp, "0X", 2) == 0)
240612633Sjohn.levon@sun.com currentp += 2;
240712633Sjohn.levon@sun.com hostidval = strtoull(currentp, ¤tp, 16);
240812633Sjohn.levon@sun.com if ((size_t)(currentp - hostidp) >= HW_HOSTID_LEN)
240912633Sjohn.levon@sun.com return (Z_TOO_BIG);
241012633Sjohn.levon@sun.com if (hostidval > UINT_MAX || hostidval == HW_INVALID_HOSTID ||
241112633Sjohn.levon@sun.com currentp != hostidp + len)
241212633Sjohn.levon@sun.com return (Z_INVALID_PROPERTY);
241312633Sjohn.levon@sun.com return (Z_OK);
241412633Sjohn.levon@sun.com }
241512633Sjohn.levon@sun.com
241612633Sjohn.levon@sun.com /*
24178662SJordan.Vaughan@Sun.com * Gets the zone hostid string stored in the specified zone configuration
24188662SJordan.Vaughan@Sun.com * document. This function returns Z_OK on success. Z_BAD_PROPERTY is returned
24198662SJordan.Vaughan@Sun.com * if the config file doesn't specify a hostid or if the hostid is blank.
24208662SJordan.Vaughan@Sun.com *
24218662SJordan.Vaughan@Sun.com * Note that buflen should be at least HW_HOSTID_LEN.
24228662SJordan.Vaughan@Sun.com */
24238662SJordan.Vaughan@Sun.com int
zonecfg_get_hostid(zone_dochandle_t handle,char * bufp,size_t buflen)24248662SJordan.Vaughan@Sun.com zonecfg_get_hostid(zone_dochandle_t handle, char *bufp, size_t buflen)
24258662SJordan.Vaughan@Sun.com {
24268662SJordan.Vaughan@Sun.com int err;
24278662SJordan.Vaughan@Sun.com
24288662SJordan.Vaughan@Sun.com if ((err = getrootattr(handle, DTD_ATTR_HOSTID, bufp, buflen)) != Z_OK)
24298662SJordan.Vaughan@Sun.com return (err);
24308662SJordan.Vaughan@Sun.com if (bufp[0] == '\0')
24318662SJordan.Vaughan@Sun.com return (Z_BAD_PROPERTY);
243212633Sjohn.levon@sun.com return (zonecfg_valid_hostid(bufp));
24338662SJordan.Vaughan@Sun.com }
24348662SJordan.Vaughan@Sun.com
24358662SJordan.Vaughan@Sun.com /*
24368662SJordan.Vaughan@Sun.com * Sets the hostid string in the specified zone config document to the given
24378662SJordan.Vaughan@Sun.com * string value. If 'hostidp' is NULL, then the config document's hostid
24388662SJordan.Vaughan@Sun.com * attribute is cleared. Non-NULL hostids are validated. This function returns
24398662SJordan.Vaughan@Sun.com * Z_OK on success. Any other return value indicates failure.
24408662SJordan.Vaughan@Sun.com */
24418662SJordan.Vaughan@Sun.com int
zonecfg_set_hostid(zone_dochandle_t handle,const char * hostidp)24428662SJordan.Vaughan@Sun.com zonecfg_set_hostid(zone_dochandle_t handle, const char *hostidp)
24438662SJordan.Vaughan@Sun.com {
24448662SJordan.Vaughan@Sun.com int err;
24458662SJordan.Vaughan@Sun.com
24468662SJordan.Vaughan@Sun.com /*
24478662SJordan.Vaughan@Sun.com * A NULL hostid string is interpreted as a request to clear the
24488662SJordan.Vaughan@Sun.com * hostid.
24498662SJordan.Vaughan@Sun.com */
24508662SJordan.Vaughan@Sun.com if (hostidp == NULL || (err = zonecfg_valid_hostid(hostidp)) == Z_OK)
24518662SJordan.Vaughan@Sun.com return (setrootattr(handle, DTD_ATTR_HOSTID, hostidp));
24528662SJordan.Vaughan@Sun.com return (err);
24538662SJordan.Vaughan@Sun.com }
24548662SJordan.Vaughan@Sun.com
24550Sstevel@tonic-gate int
zonecfg_lookup_dev(zone_dochandle_t handle,struct zone_devtab * tabptr)24560Sstevel@tonic-gate zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
24570Sstevel@tonic-gate {
24580Sstevel@tonic-gate xmlNodePtr cur, firstmatch;
24590Sstevel@tonic-gate int err;
24600Sstevel@tonic-gate char match[MAXPATHLEN];
24610Sstevel@tonic-gate
24620Sstevel@tonic-gate if (tabptr == NULL)
24630Sstevel@tonic-gate return (Z_INVAL);
24640Sstevel@tonic-gate
24650Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK)
24660Sstevel@tonic-gate return (err);
24670Sstevel@tonic-gate
24680Sstevel@tonic-gate cur = handle->zone_dh_cur;
24690Sstevel@tonic-gate firstmatch = NULL;
24700Sstevel@tonic-gate for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
24710Sstevel@tonic-gate if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
24720Sstevel@tonic-gate continue;
24730Sstevel@tonic-gate if (strlen(tabptr->zone_dev_match) == 0)
24740Sstevel@tonic-gate continue;
24750Sstevel@tonic-gate
24760Sstevel@tonic-gate if ((fetchprop(cur, DTD_ATTR_MATCH, match,
24770Sstevel@tonic-gate sizeof (match)) == Z_OK)) {
24780Sstevel@tonic-gate if (strcmp(tabptr->zone_dev_match,
24790Sstevel@tonic-gate match) == 0) {
24800Sstevel@tonic-gate if (firstmatch == NULL)
24810Sstevel@tonic-gate firstmatch = cur;
24820Sstevel@tonic-gate else if (firstmatch != cur)
24830Sstevel@tonic-gate return (Z_INSUFFICIENT_SPEC);
24840Sstevel@tonic-gate } else {
24850Sstevel@tonic-gate /*
24860Sstevel@tonic-gate * If another property matched but this
24870Sstevel@tonic-gate * one doesn't then reset firstmatch.
24880Sstevel@tonic-gate */
24890Sstevel@tonic-gate if (firstmatch == cur)
24900Sstevel@tonic-gate firstmatch = NULL;
24910Sstevel@tonic-gate }
24920Sstevel@tonic-gate }
24930Sstevel@tonic-gate }
24940Sstevel@tonic-gate if (firstmatch == NULL)
24950Sstevel@tonic-gate return (Z_NO_RESOURCE_ID);
24960Sstevel@tonic-gate
24970Sstevel@tonic-gate cur = firstmatch;
24980Sstevel@tonic-gate
24990Sstevel@tonic-gate if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
25000Sstevel@tonic-gate sizeof (tabptr->zone_dev_match))) != Z_OK)
25010Sstevel@tonic-gate return (err);
25020Sstevel@tonic-gate
25030Sstevel@tonic-gate return (Z_OK);
25040Sstevel@tonic-gate }
25050Sstevel@tonic-gate
25060Sstevel@tonic-gate static int
zonecfg_add_dev_core(zone_dochandle_t handle,struct zone_devtab * tabptr)25070Sstevel@tonic-gate zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
25080Sstevel@tonic-gate {
25090Sstevel@tonic-gate xmlNodePtr newnode, cur = handle->zone_dh_cur;
25100Sstevel@tonic-gate int err;
25110Sstevel@tonic-gate
25120Sstevel@tonic-gate newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL);
25130Sstevel@tonic-gate
2514228Sdp if ((err = newprop(newnode, DTD_ATTR_MATCH,
25150Sstevel@tonic-gate tabptr->zone_dev_match)) != Z_OK)
25160Sstevel@tonic-gate return (err);
25170Sstevel@tonic-gate
25180Sstevel@tonic-gate return (Z_OK);
25190Sstevel@tonic-gate }
25200Sstevel@tonic-gate
25210Sstevel@tonic-gate int
zonecfg_add_dev(zone_dochandle_t handle,struct zone_devtab * tabptr)25220Sstevel@tonic-gate zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
25230Sstevel@tonic-gate {
25240Sstevel@tonic-gate int err;
25250Sstevel@tonic-gate
25260Sstevel@tonic-gate if (tabptr == NULL)
25270Sstevel@tonic-gate return (Z_INVAL);
25280Sstevel@tonic-gate
25290Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK)
25300Sstevel@tonic-gate return (err);
25310Sstevel@tonic-gate
25320Sstevel@tonic-gate if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK)
25330Sstevel@tonic-gate return (err);
25340Sstevel@tonic-gate
25350Sstevel@tonic-gate return (Z_OK);
25360Sstevel@tonic-gate }
25370Sstevel@tonic-gate
25380Sstevel@tonic-gate static int
zonecfg_delete_dev_core(zone_dochandle_t handle,struct zone_devtab * tabptr)25390Sstevel@tonic-gate zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
25400Sstevel@tonic-gate {
25412621Sllai1 xmlNodePtr cur = handle->zone_dh_cur;
25420Sstevel@tonic-gate int match_match;
25430Sstevel@tonic-gate
25440Sstevel@tonic-gate for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
25450Sstevel@tonic-gate if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
25460Sstevel@tonic-gate continue;
25470Sstevel@tonic-gate
25480Sstevel@tonic-gate match_match = match_prop(cur, DTD_ATTR_MATCH,
25490Sstevel@tonic-gate tabptr->zone_dev_match);
25500Sstevel@tonic-gate
25510Sstevel@tonic-gate if (match_match) {
25520Sstevel@tonic-gate xmlUnlinkNode(cur);
25530Sstevel@tonic-gate xmlFreeNode(cur);
25540Sstevel@tonic-gate return (Z_OK);
25550Sstevel@tonic-gate }
25560Sstevel@tonic-gate }
25570Sstevel@tonic-gate return (Z_NO_RESOURCE_ID);
25580Sstevel@tonic-gate }
25590Sstevel@tonic-gate
25600Sstevel@tonic-gate int
zonecfg_delete_dev(zone_dochandle_t handle,struct zone_devtab * tabptr)25610Sstevel@tonic-gate zonecfg_delete_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
25620Sstevel@tonic-gate {
25630Sstevel@tonic-gate int err;
25640Sstevel@tonic-gate
25650Sstevel@tonic-gate if (tabptr == NULL)
25660Sstevel@tonic-gate return (Z_INVAL);
25670Sstevel@tonic-gate
25680Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK)
25690Sstevel@tonic-gate return (err);
25700Sstevel@tonic-gate
25710Sstevel@tonic-gate if ((err = zonecfg_delete_dev_core(handle, tabptr)) != Z_OK)
25720Sstevel@tonic-gate return (err);
25730Sstevel@tonic-gate
25740Sstevel@tonic-gate return (Z_OK);
25750Sstevel@tonic-gate }
25760Sstevel@tonic-gate
25770Sstevel@tonic-gate int
zonecfg_modify_dev(zone_dochandle_t handle,struct zone_devtab * oldtabptr,struct zone_devtab * newtabptr)25780Sstevel@tonic-gate zonecfg_modify_dev(
25790Sstevel@tonic-gate zone_dochandle_t handle,
25800Sstevel@tonic-gate struct zone_devtab *oldtabptr,
25810Sstevel@tonic-gate struct zone_devtab *newtabptr)
25820Sstevel@tonic-gate {
25830Sstevel@tonic-gate int err;
25840Sstevel@tonic-gate
25850Sstevel@tonic-gate if (oldtabptr == NULL || newtabptr == NULL)
25860Sstevel@tonic-gate return (Z_INVAL);
25870Sstevel@tonic-gate
25880Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK)
25890Sstevel@tonic-gate return (err);
25900Sstevel@tonic-gate
25910Sstevel@tonic-gate if ((err = zonecfg_delete_dev_core(handle, oldtabptr)) != Z_OK)
25920Sstevel@tonic-gate return (err);
25930Sstevel@tonic-gate
25940Sstevel@tonic-gate if ((err = zonecfg_add_dev_core(handle, newtabptr)) != Z_OK)
25950Sstevel@tonic-gate return (err);
25960Sstevel@tonic-gate
25970Sstevel@tonic-gate return (Z_OK);
25980Sstevel@tonic-gate }
25990Sstevel@tonic-gate
260012578SGlenn.Faden@Sun.COM static int
zonecfg_add_auth_core(zone_dochandle_t handle,struct zone_admintab * tabptr,char * zonename)260112578SGlenn.Faden@Sun.COM zonecfg_add_auth_core(zone_dochandle_t handle, struct zone_admintab *tabptr,
260212578SGlenn.Faden@Sun.COM char *zonename)
260312578SGlenn.Faden@Sun.COM {
260412578SGlenn.Faden@Sun.COM xmlNodePtr newnode, cur = handle->zone_dh_cur;
260512578SGlenn.Faden@Sun.COM int err;
260612578SGlenn.Faden@Sun.COM
260712578SGlenn.Faden@Sun.COM newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ADMIN, NULL);
260812578SGlenn.Faden@Sun.COM err = newprop(newnode, DTD_ATTR_USER, tabptr->zone_admin_user);
260912578SGlenn.Faden@Sun.COM if (err != Z_OK)
261012578SGlenn.Faden@Sun.COM return (err);
261112578SGlenn.Faden@Sun.COM err = newprop(newnode, DTD_ATTR_AUTHS, tabptr->zone_admin_auths);
261212578SGlenn.Faden@Sun.COM if (err != Z_OK)
261312578SGlenn.Faden@Sun.COM return (err);
261412578SGlenn.Faden@Sun.COM if ((err = zonecfg_remove_userauths(
261512578SGlenn.Faden@Sun.COM handle, tabptr->zone_admin_user, zonename, B_FALSE)) != Z_OK)
261612578SGlenn.Faden@Sun.COM return (err);
261712578SGlenn.Faden@Sun.COM return (Z_OK);
261812578SGlenn.Faden@Sun.COM }
261912578SGlenn.Faden@Sun.COM
262012578SGlenn.Faden@Sun.COM int
zonecfg_add_admin(zone_dochandle_t handle,struct zone_admintab * tabptr,char * zonename)262112578SGlenn.Faden@Sun.COM zonecfg_add_admin(zone_dochandle_t handle, struct zone_admintab *tabptr,
262212578SGlenn.Faden@Sun.COM char *zonename)
262312578SGlenn.Faden@Sun.COM {
262412578SGlenn.Faden@Sun.COM int err;
262512578SGlenn.Faden@Sun.COM
262612578SGlenn.Faden@Sun.COM if (tabptr == NULL)
262712578SGlenn.Faden@Sun.COM return (Z_INVAL);
262812578SGlenn.Faden@Sun.COM
262912578SGlenn.Faden@Sun.COM if ((err = operation_prep(handle)) != Z_OK)
263012578SGlenn.Faden@Sun.COM return (err);
263112578SGlenn.Faden@Sun.COM
263212578SGlenn.Faden@Sun.COM if ((err = zonecfg_add_auth_core(handle, tabptr,
263312578SGlenn.Faden@Sun.COM zonename)) != Z_OK)
263412578SGlenn.Faden@Sun.COM return (err);
263512578SGlenn.Faden@Sun.COM
263612578SGlenn.Faden@Sun.COM return (Z_OK);
263712578SGlenn.Faden@Sun.COM }
263812578SGlenn.Faden@Sun.COM static int
zonecfg_delete_auth_core(zone_dochandle_t handle,struct zone_admintab * tabptr,char * zonename)263912578SGlenn.Faden@Sun.COM zonecfg_delete_auth_core(zone_dochandle_t handle, struct zone_admintab *tabptr,
264012578SGlenn.Faden@Sun.COM char *zonename)
264112578SGlenn.Faden@Sun.COM {
264212578SGlenn.Faden@Sun.COM xmlNodePtr cur = handle->zone_dh_cur;
264312578SGlenn.Faden@Sun.COM boolean_t auth_match;
264412578SGlenn.Faden@Sun.COM int err;
264512578SGlenn.Faden@Sun.COM
264612578SGlenn.Faden@Sun.COM for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
264712578SGlenn.Faden@Sun.COM if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
264812578SGlenn.Faden@Sun.COM continue;
264912578SGlenn.Faden@Sun.COM auth_match = match_prop(cur, DTD_ATTR_USER,
265012578SGlenn.Faden@Sun.COM tabptr->zone_admin_user);
265112578SGlenn.Faden@Sun.COM if (auth_match) {
265212578SGlenn.Faden@Sun.COM if ((err = zonecfg_insert_userauths(
265312578SGlenn.Faden@Sun.COM handle, tabptr->zone_admin_user,
265412578SGlenn.Faden@Sun.COM zonename)) != Z_OK)
265512578SGlenn.Faden@Sun.COM return (err);
265612578SGlenn.Faden@Sun.COM xmlUnlinkNode(cur);
265712578SGlenn.Faden@Sun.COM xmlFreeNode(cur);
265812578SGlenn.Faden@Sun.COM return (Z_OK);
265912578SGlenn.Faden@Sun.COM }
266012578SGlenn.Faden@Sun.COM }
266112578SGlenn.Faden@Sun.COM return (Z_NO_RESOURCE_ID);
266212578SGlenn.Faden@Sun.COM }
266312578SGlenn.Faden@Sun.COM
266412578SGlenn.Faden@Sun.COM int
zonecfg_delete_admin(zone_dochandle_t handle,struct zone_admintab * tabptr,char * zonename)266512578SGlenn.Faden@Sun.COM zonecfg_delete_admin(zone_dochandle_t handle, struct zone_admintab *tabptr,
266612578SGlenn.Faden@Sun.COM char *zonename)
266712578SGlenn.Faden@Sun.COM {
266812578SGlenn.Faden@Sun.COM int err;
266912578SGlenn.Faden@Sun.COM
267012578SGlenn.Faden@Sun.COM if (tabptr == NULL)
267112578SGlenn.Faden@Sun.COM return (Z_INVAL);
267212578SGlenn.Faden@Sun.COM
267312578SGlenn.Faden@Sun.COM if ((err = operation_prep(handle)) != Z_OK)
267412578SGlenn.Faden@Sun.COM return (err);
267512578SGlenn.Faden@Sun.COM
267612578SGlenn.Faden@Sun.COM if ((err = zonecfg_delete_auth_core(handle, tabptr, zonename)) != Z_OK)
267712578SGlenn.Faden@Sun.COM return (err);
267812578SGlenn.Faden@Sun.COM
267912578SGlenn.Faden@Sun.COM return (Z_OK);
268012578SGlenn.Faden@Sun.COM }
268112578SGlenn.Faden@Sun.COM
268212578SGlenn.Faden@Sun.COM int
zonecfg_modify_admin(zone_dochandle_t handle,struct zone_admintab * oldtabptr,struct zone_admintab * newtabptr,char * zonename)268312578SGlenn.Faden@Sun.COM zonecfg_modify_admin(zone_dochandle_t handle, struct zone_admintab *oldtabptr,
268412578SGlenn.Faden@Sun.COM struct zone_admintab *newtabptr, char *zonename)
268512578SGlenn.Faden@Sun.COM {
268612578SGlenn.Faden@Sun.COM int err;
268712578SGlenn.Faden@Sun.COM
268812578SGlenn.Faden@Sun.COM if (oldtabptr == NULL || newtabptr == NULL)
268912578SGlenn.Faden@Sun.COM return (Z_INVAL);
269012578SGlenn.Faden@Sun.COM
269112578SGlenn.Faden@Sun.COM if ((err = operation_prep(handle)) != Z_OK)
269212578SGlenn.Faden@Sun.COM return (err);
269312578SGlenn.Faden@Sun.COM
269412578SGlenn.Faden@Sun.COM if ((err = zonecfg_delete_auth_core(handle, oldtabptr, zonename))
269512578SGlenn.Faden@Sun.COM != Z_OK)
269612578SGlenn.Faden@Sun.COM return (err);
269712578SGlenn.Faden@Sun.COM
269812578SGlenn.Faden@Sun.COM if ((err = zonecfg_add_auth_core(handle, newtabptr,
269912578SGlenn.Faden@Sun.COM zonename)) != Z_OK)
270012578SGlenn.Faden@Sun.COM return (err);
270112578SGlenn.Faden@Sun.COM
270212578SGlenn.Faden@Sun.COM return (Z_OK);
270312578SGlenn.Faden@Sun.COM }
270412578SGlenn.Faden@Sun.COM
270512578SGlenn.Faden@Sun.COM int
zonecfg_lookup_admin(zone_dochandle_t handle,struct zone_admintab * tabptr)270612578SGlenn.Faden@Sun.COM zonecfg_lookup_admin(zone_dochandle_t handle, struct zone_admintab *tabptr)
270712578SGlenn.Faden@Sun.COM {
270812578SGlenn.Faden@Sun.COM xmlNodePtr cur, firstmatch;
270912578SGlenn.Faden@Sun.COM int err;
271012578SGlenn.Faden@Sun.COM char user[MAXUSERNAME];
271112578SGlenn.Faden@Sun.COM
271212578SGlenn.Faden@Sun.COM if (tabptr == NULL)
271312578SGlenn.Faden@Sun.COM return (Z_INVAL);
271412578SGlenn.Faden@Sun.COM
271512578SGlenn.Faden@Sun.COM if ((err = operation_prep(handle)) != Z_OK)
271612578SGlenn.Faden@Sun.COM return (err);
271712578SGlenn.Faden@Sun.COM
271812578SGlenn.Faden@Sun.COM cur = handle->zone_dh_cur;
271912578SGlenn.Faden@Sun.COM firstmatch = NULL;
272012578SGlenn.Faden@Sun.COM for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
272112578SGlenn.Faden@Sun.COM if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
272212578SGlenn.Faden@Sun.COM continue;
272312578SGlenn.Faden@Sun.COM if (strlen(tabptr->zone_admin_user) > 0) {
272412578SGlenn.Faden@Sun.COM if ((fetchprop(cur, DTD_ATTR_USER, user,
272512578SGlenn.Faden@Sun.COM sizeof (user)) == Z_OK) &&
272612578SGlenn.Faden@Sun.COM (strcmp(tabptr->zone_admin_user, user) == 0)) {
272712578SGlenn.Faden@Sun.COM if (firstmatch == NULL)
272812578SGlenn.Faden@Sun.COM firstmatch = cur;
272912578SGlenn.Faden@Sun.COM else
273012578SGlenn.Faden@Sun.COM return (Z_INSUFFICIENT_SPEC);
273112578SGlenn.Faden@Sun.COM }
273212578SGlenn.Faden@Sun.COM }
273312578SGlenn.Faden@Sun.COM }
273412578SGlenn.Faden@Sun.COM if (firstmatch == NULL)
273512578SGlenn.Faden@Sun.COM return (Z_NO_RESOURCE_ID);
273612578SGlenn.Faden@Sun.COM
273712578SGlenn.Faden@Sun.COM cur = firstmatch;
273812578SGlenn.Faden@Sun.COM
273912578SGlenn.Faden@Sun.COM if ((err = fetchprop(cur, DTD_ATTR_USER, tabptr->zone_admin_user,
274012578SGlenn.Faden@Sun.COM sizeof (tabptr->zone_admin_user))) != Z_OK)
274112578SGlenn.Faden@Sun.COM return (err);
274212578SGlenn.Faden@Sun.COM
274312578SGlenn.Faden@Sun.COM if ((err = fetchprop(cur, DTD_ATTR_AUTHS, tabptr->zone_admin_auths,
274412578SGlenn.Faden@Sun.COM sizeof (tabptr->zone_admin_auths))) != Z_OK)
274512578SGlenn.Faden@Sun.COM return (err);
274612578SGlenn.Faden@Sun.COM
274712578SGlenn.Faden@Sun.COM return (Z_OK);
274812578SGlenn.Faden@Sun.COM }
274912578SGlenn.Faden@Sun.COM
275012578SGlenn.Faden@Sun.COM
27517089Sgjelinek /* Lock to serialize all devwalks */
27521507Sgjelinek static pthread_mutex_t zonecfg_devwalk_lock = PTHREAD_MUTEX_INITIALIZER;
27531507Sgjelinek /*
27547089Sgjelinek * Global variables used to pass data from zonecfg_dev_manifest to the nftw
27551507Sgjelinek * call-back (zonecfg_devwalk_cb). g_devwalk_data is really the void*
27567089Sgjelinek * parameter and g_devwalk_cb is really the *cb parameter from
27577089Sgjelinek * zonecfg_dev_manifest.
27581507Sgjelinek */
27597089Sgjelinek typedef struct __g_devwalk_data *g_devwalk_data_t;
27607089Sgjelinek static g_devwalk_data_t g_devwalk_data;
27611507Sgjelinek static int (*g_devwalk_cb)(const char *, uid_t, gid_t, mode_t, const char *,
27621507Sgjelinek void *);
27631507Sgjelinek static size_t g_devwalk_skip_prefix;
27641507Sgjelinek
27651507Sgjelinek /*
27667089Sgjelinek * zonecfg_dev_manifest call-back function used during detach to generate the
27677089Sgjelinek * dev info in the manifest.
27687089Sgjelinek */
27697089Sgjelinek static int
get_detach_dev_entry(const char * name,uid_t uid,gid_t gid,mode_t mode,const char * acl,void * hdl)27707089Sgjelinek get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode,
27717089Sgjelinek const char *acl, void *hdl)
27727089Sgjelinek {
27737089Sgjelinek zone_dochandle_t handle = (zone_dochandle_t)hdl;
27747089Sgjelinek xmlNodePtr newnode;
27757089Sgjelinek xmlNodePtr cur;
27767089Sgjelinek int err;
27777089Sgjelinek char buf[128];
27787089Sgjelinek
27797089Sgjelinek if ((err = operation_prep(handle)) != Z_OK)
27807089Sgjelinek return (err);
27817089Sgjelinek
27827089Sgjelinek cur = handle->zone_dh_cur;
27837089Sgjelinek newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL);
27847089Sgjelinek if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK)
27857089Sgjelinek return (err);
27867089Sgjelinek (void) snprintf(buf, sizeof (buf), "%lu", uid);
27877089Sgjelinek if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK)
27887089Sgjelinek return (err);
27897089Sgjelinek (void) snprintf(buf, sizeof (buf), "%lu", gid);
27907089Sgjelinek if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK)
27917089Sgjelinek return (err);
27927089Sgjelinek (void) snprintf(buf, sizeof (buf), "%o", mode);
27937089Sgjelinek if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK)
27947089Sgjelinek return (err);
27957089Sgjelinek if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK)
27967089Sgjelinek return (err);
27977089Sgjelinek return (Z_OK);
27987089Sgjelinek }
27997089Sgjelinek
28007089Sgjelinek /*
28017089Sgjelinek * This is the nftw call-back function used by zonecfg_dev_manifest. It is
28027089Sgjelinek * responsible for calling the actual call-back.
28031507Sgjelinek */
28041507Sgjelinek /* ARGSUSED2 */
28051507Sgjelinek static int
zonecfg_devwalk_cb(const char * path,const struct stat * st,int f,struct FTW * ftw)28061507Sgjelinek zonecfg_devwalk_cb(const char *path, const struct stat *st, int f,
28071507Sgjelinek struct FTW *ftw)
28081507Sgjelinek {
28091507Sgjelinek acl_t *acl;
28101507Sgjelinek char *acl_txt = NULL;
28111507Sgjelinek
28121507Sgjelinek /* skip all but character and block devices */
28131507Sgjelinek if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode))
28141507Sgjelinek return (0);
28151507Sgjelinek
28161507Sgjelinek if ((acl_get(path, ACL_NO_TRIVIAL, &acl) == 0) &&
28171507Sgjelinek acl != NULL) {
28181507Sgjelinek acl_txt = acl_totext(acl, ACL_NORESOLVE);
28191507Sgjelinek acl_free(acl);
28201507Sgjelinek }
28211507Sgjelinek
28221507Sgjelinek if (strlen(path) <= g_devwalk_skip_prefix)
28231507Sgjelinek return (0);
28241507Sgjelinek
28251507Sgjelinek g_devwalk_cb(path + g_devwalk_skip_prefix, st->st_uid, st->st_gid,
28261507Sgjelinek st->st_mode & S_IAMB, acl_txt != NULL ? acl_txt : "",
28271507Sgjelinek g_devwalk_data);
28281507Sgjelinek free(acl_txt);
28291507Sgjelinek return (0);
28301507Sgjelinek }
28311507Sgjelinek
28321507Sgjelinek /*
28337089Sgjelinek * Walk the dev tree for the zone specified by hdl and call the
28347089Sgjelinek * get_detach_dev_entry call-back function for each entry in the tree. The
28357089Sgjelinek * call-back will be passed the name, uid, gid, mode, acl string and the
28367089Sgjelinek * handle input parameter for each dev entry.
28371507Sgjelinek *
28387089Sgjelinek * Data is passed to get_detach_dev_entry through the global variables
28391507Sgjelinek * g_devwalk_data, *g_devwalk_cb, and g_devwalk_skip_prefix. The
28407089Sgjelinek * zonecfg_devwalk_cb function will actually call get_detach_dev_entry.
28411507Sgjelinek */
28421507Sgjelinek int
zonecfg_dev_manifest(zone_dochandle_t hdl)28437089Sgjelinek zonecfg_dev_manifest(zone_dochandle_t hdl)
28441507Sgjelinek {
28451507Sgjelinek char path[MAXPATHLEN];
28461507Sgjelinek int ret;
28471507Sgjelinek
28481507Sgjelinek if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK)
28491507Sgjelinek return (ret);
28501507Sgjelinek
28511507Sgjelinek if (strlcat(path, "/dev", sizeof (path)) >= sizeof (path))
28521507Sgjelinek return (Z_TOO_BIG);
28531507Sgjelinek
28541507Sgjelinek /*
28557089Sgjelinek * We have to serialize all devwalks in the same process
28561507Sgjelinek * (which should be fine), since nftw() is so badly designed.
28571507Sgjelinek */
28581507Sgjelinek (void) pthread_mutex_lock(&zonecfg_devwalk_lock);
28591507Sgjelinek
28607089Sgjelinek g_devwalk_skip_prefix = strlen(path) + 1;
28617089Sgjelinek g_devwalk_data = (g_devwalk_data_t)hdl;
28627089Sgjelinek g_devwalk_cb = get_detach_dev_entry;
28631507Sgjelinek (void) nftw(path, zonecfg_devwalk_cb, 0, FTW_PHYS);
28641507Sgjelinek
28651507Sgjelinek (void) pthread_mutex_unlock(&zonecfg_devwalk_lock);
28661507Sgjelinek return (Z_OK);
28671507Sgjelinek }
28681507Sgjelinek
28691507Sgjelinek /*
28701507Sgjelinek * Update the owner, group, mode and acl on the specified dev (inpath) for
28711507Sgjelinek * the zone (hdl). This function can be used to fix up the dev tree after
28721507Sgjelinek * attaching a migrated zone.
28731507Sgjelinek */
28741507Sgjelinek int
zonecfg_devperms_apply(zone_dochandle_t hdl,const char * inpath,uid_t owner,gid_t group,mode_t mode,const char * acltxt)28751507Sgjelinek zonecfg_devperms_apply(zone_dochandle_t hdl, const char *inpath, uid_t owner,
28761507Sgjelinek gid_t group, mode_t mode, const char *acltxt)
28771507Sgjelinek {
28781507Sgjelinek int ret;
28791507Sgjelinek char path[MAXPATHLEN];
28801507Sgjelinek struct stat st;
28811507Sgjelinek acl_t *aclp;
28821507Sgjelinek
28831507Sgjelinek if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK)
28841507Sgjelinek return (ret);
28851507Sgjelinek
28861507Sgjelinek if (strlcat(path, "/dev/", sizeof (path)) >= sizeof (path))
28871507Sgjelinek return (Z_TOO_BIG);
28881507Sgjelinek if (strlcat(path, inpath, sizeof (path)) >= sizeof (path))
28891507Sgjelinek return (Z_TOO_BIG);
28901507Sgjelinek
28911507Sgjelinek if (stat(path, &st) == -1)
28921507Sgjelinek return (Z_INVAL);
28931507Sgjelinek
28941507Sgjelinek /* make sure we're only touching device nodes */
28951507Sgjelinek if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode))
28961507Sgjelinek return (Z_INVAL);
28971507Sgjelinek
28981507Sgjelinek if (chown(path, owner, group) == -1)
28991507Sgjelinek return (Z_SYSTEM);
29001507Sgjelinek
29011507Sgjelinek if (chmod(path, mode) == -1)
29021507Sgjelinek return (Z_SYSTEM);
29031507Sgjelinek
29041507Sgjelinek if ((acltxt == NULL) || (strcmp(acltxt, "") == 0))
29051507Sgjelinek return (Z_OK);
29061507Sgjelinek
29078057SJordan.Vaughan@Sun.com if (acl_fromtext(acltxt, &aclp) != 0) {
29088057SJordan.Vaughan@Sun.com errno = EINVAL;
29091507Sgjelinek return (Z_SYSTEM);
29108057SJordan.Vaughan@Sun.com }
29111507Sgjelinek
29121507Sgjelinek errno = 0;
29131507Sgjelinek if (acl_set(path, aclp) == -1) {
29141507Sgjelinek free(aclp);
29151507Sgjelinek return (Z_SYSTEM);
29161507Sgjelinek }
29171507Sgjelinek
29181507Sgjelinek free(aclp);
29191507Sgjelinek return (Z_OK);
29201507Sgjelinek }
29211507Sgjelinek
29220Sstevel@tonic-gate /*
29230Sstevel@tonic-gate * This function finds everything mounted under a zone's rootpath.
29240Sstevel@tonic-gate * This returns the number of mounts under rootpath, or -1 on error.
29250Sstevel@tonic-gate * callback is called once per mount found with the first argument
292611276SJordan.Vaughan@Sun.com * pointing to a mnttab structure containing the mount's information.
29270Sstevel@tonic-gate *
29280Sstevel@tonic-gate * If the callback function returns non-zero zonecfg_find_mounts
29290Sstevel@tonic-gate * aborts with an error.
29300Sstevel@tonic-gate */
29310Sstevel@tonic-gate int
zonecfg_find_mounts(char * rootpath,int (* callback)(const struct mnttab *,void *),void * priv)293211276SJordan.Vaughan@Sun.com zonecfg_find_mounts(char *rootpath, int (*callback)(const struct mnttab *,
293311276SJordan.Vaughan@Sun.com void *), void *priv) {
29340Sstevel@tonic-gate FILE *mnttab;
29350Sstevel@tonic-gate struct mnttab m;
29360Sstevel@tonic-gate size_t l;
29371607Sgjelinek int zfsl;
29380Sstevel@tonic-gate int rv = 0;
29391607Sgjelinek char zfs_path[MAXPATHLEN];
29400Sstevel@tonic-gate
29410Sstevel@tonic-gate assert(rootpath != NULL);
29420Sstevel@tonic-gate
29431607Sgjelinek if ((zfsl = snprintf(zfs_path, sizeof (zfs_path), "%s/.zfs/", rootpath))
29441607Sgjelinek >= sizeof (zfs_path))
29451607Sgjelinek return (-1);
29461607Sgjelinek
29470Sstevel@tonic-gate l = strlen(rootpath);
29480Sstevel@tonic-gate
29490Sstevel@tonic-gate mnttab = fopen("/etc/mnttab", "r");
29500Sstevel@tonic-gate
29510Sstevel@tonic-gate if (mnttab == NULL)
29520Sstevel@tonic-gate return (-1);
29530Sstevel@tonic-gate
29540Sstevel@tonic-gate if (ioctl(fileno(mnttab), MNTIOC_SHOWHIDDEN, NULL) < 0) {
29550Sstevel@tonic-gate rv = -1;
29560Sstevel@tonic-gate goto out;
29570Sstevel@tonic-gate }
29580Sstevel@tonic-gate
29590Sstevel@tonic-gate while (!getmntent(mnttab, &m)) {
29600Sstevel@tonic-gate if ((strncmp(rootpath, m.mnt_mountp, l) == 0) &&
29611607Sgjelinek (m.mnt_mountp[l] == '/') &&
29621607Sgjelinek (strncmp(zfs_path, m.mnt_mountp, zfsl) != 0)) {
29630Sstevel@tonic-gate rv++;
29640Sstevel@tonic-gate if (callback == NULL)
29650Sstevel@tonic-gate continue;
296611276SJordan.Vaughan@Sun.com if (callback(&m, priv)) {
29670Sstevel@tonic-gate rv = -1;
29680Sstevel@tonic-gate goto out;
29690Sstevel@tonic-gate
29700Sstevel@tonic-gate }
29710Sstevel@tonic-gate }
29720Sstevel@tonic-gate }
29730Sstevel@tonic-gate
29740Sstevel@tonic-gate out:
29750Sstevel@tonic-gate (void) fclose(mnttab);
29760Sstevel@tonic-gate return (rv);
29770Sstevel@tonic-gate }
29780Sstevel@tonic-gate
29790Sstevel@tonic-gate int
zonecfg_lookup_attr(zone_dochandle_t handle,struct zone_attrtab * tabptr)29800Sstevel@tonic-gate zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
29810Sstevel@tonic-gate {
29820Sstevel@tonic-gate xmlNodePtr cur, firstmatch;
29830Sstevel@tonic-gate int err;
29840Sstevel@tonic-gate char name[MAXNAMELEN], type[MAXNAMELEN], value[MAXNAMELEN];
29850Sstevel@tonic-gate
29860Sstevel@tonic-gate if (tabptr == NULL)
29870Sstevel@tonic-gate return (Z_INVAL);
29880Sstevel@tonic-gate
29890Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK)
29900Sstevel@tonic-gate return (err);
29910Sstevel@tonic-gate
29920Sstevel@tonic-gate cur = handle->zone_dh_cur;
29930Sstevel@tonic-gate firstmatch = NULL;
29940Sstevel@tonic-gate for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
29950Sstevel@tonic-gate if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
29960Sstevel@tonic-gate continue;
29970Sstevel@tonic-gate if (strlen(tabptr->zone_attr_name) > 0) {
29980Sstevel@tonic-gate if ((fetchprop(cur, DTD_ATTR_NAME, name,
29990Sstevel@tonic-gate sizeof (name)) == Z_OK) &&
30000Sstevel@tonic-gate (strcmp(tabptr->zone_attr_name, name) == 0)) {
30010Sstevel@tonic-gate if (firstmatch == NULL)
30020Sstevel@tonic-gate firstmatch = cur;
30030Sstevel@tonic-gate else
30040Sstevel@tonic-gate return (Z_INSUFFICIENT_SPEC);
30050Sstevel@tonic-gate }
30060Sstevel@tonic-gate }
30070Sstevel@tonic-gate if (strlen(tabptr->zone_attr_type) > 0) {
30080Sstevel@tonic-gate if ((fetchprop(cur, DTD_ATTR_TYPE, type,
30090Sstevel@tonic-gate sizeof (type)) == Z_OK)) {
30100Sstevel@tonic-gate if (strcmp(tabptr->zone_attr_type, type) == 0) {
30110Sstevel@tonic-gate if (firstmatch == NULL)
30120Sstevel@tonic-gate firstmatch = cur;
30130Sstevel@tonic-gate else if (firstmatch != cur)
30140Sstevel@tonic-gate return (Z_INSUFFICIENT_SPEC);
30150Sstevel@tonic-gate } else {
30160Sstevel@tonic-gate /*
30170Sstevel@tonic-gate * If another property matched but this
30180Sstevel@tonic-gate * one doesn't then reset firstmatch.
30190Sstevel@tonic-gate */
30200Sstevel@tonic-gate if (firstmatch == cur)
30210Sstevel@tonic-gate firstmatch = NULL;
30220Sstevel@tonic-gate }
30230Sstevel@tonic-gate }
30240Sstevel@tonic-gate }
30250Sstevel@tonic-gate if (strlen(tabptr->zone_attr_value) > 0) {
30260Sstevel@tonic-gate if ((fetchprop(cur, DTD_ATTR_VALUE, value,
30270Sstevel@tonic-gate sizeof (value)) == Z_OK)) {
30280Sstevel@tonic-gate if (strcmp(tabptr->zone_attr_value, value) ==
30290Sstevel@tonic-gate 0) {
30300Sstevel@tonic-gate if (firstmatch == NULL)
30310Sstevel@tonic-gate firstmatch = cur;
30320Sstevel@tonic-gate else if (firstmatch != cur)
30330Sstevel@tonic-gate return (Z_INSUFFICIENT_SPEC);
30340Sstevel@tonic-gate } else {
30350Sstevel@tonic-gate /*
30360Sstevel@tonic-gate * If another property matched but this
30370Sstevel@tonic-gate * one doesn't then reset firstmatch.
30380Sstevel@tonic-gate */
30390Sstevel@tonic-gate if (firstmatch == cur)
30400Sstevel@tonic-gate firstmatch = NULL;
30410Sstevel@tonic-gate }
30420Sstevel@tonic-gate }
30430Sstevel@tonic-gate }
30440Sstevel@tonic-gate }
30450Sstevel@tonic-gate if (firstmatch == NULL)
30460Sstevel@tonic-gate return (Z_NO_RESOURCE_ID);
30470Sstevel@tonic-gate
30480Sstevel@tonic-gate cur = firstmatch;
30490Sstevel@tonic-gate
30500Sstevel@tonic-gate if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
30510Sstevel@tonic-gate sizeof (tabptr->zone_attr_name))) != Z_OK)
30520Sstevel@tonic-gate return (err);
30530Sstevel@tonic-gate
30540Sstevel@tonic-gate if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
30550Sstevel@tonic-gate sizeof (tabptr->zone_attr_type))) != Z_OK)
30560Sstevel@tonic-gate return (err);
30570Sstevel@tonic-gate
30580Sstevel@tonic-gate if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
30590Sstevel@tonic-gate sizeof (tabptr->zone_attr_value))) != Z_OK)
30600Sstevel@tonic-gate return (err);
30610Sstevel@tonic-gate
30620Sstevel@tonic-gate return (Z_OK);
30630Sstevel@tonic-gate }
30640Sstevel@tonic-gate
30650Sstevel@tonic-gate static int
zonecfg_add_attr_core(zone_dochandle_t handle,struct zone_attrtab * tabptr)30660Sstevel@tonic-gate zonecfg_add_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
30670Sstevel@tonic-gate {
30680Sstevel@tonic-gate xmlNodePtr newnode, cur = handle->zone_dh_cur;
30690Sstevel@tonic-gate int err;
30700Sstevel@tonic-gate
30710Sstevel@tonic-gate newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ATTR, NULL);
3072228Sdp err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_attr_name);
30730Sstevel@tonic-gate if (err != Z_OK)
30740Sstevel@tonic-gate return (err);
3075228Sdp err = newprop(newnode, DTD_ATTR_TYPE, tabptr->zone_attr_type);
30760Sstevel@tonic-gate if (err != Z_OK)
30770Sstevel@tonic-gate return (err);
3078228Sdp err = newprop(newnode, DTD_ATTR_VALUE, tabptr->zone_attr_value);
30790Sstevel@tonic-gate if (err != Z_OK)
30800Sstevel@tonic-gate return (err);
30810Sstevel@tonic-gate return (Z_OK);
30820Sstevel@tonic-gate }
30830Sstevel@tonic-gate
30840Sstevel@tonic-gate int
zonecfg_add_attr(zone_dochandle_t handle,struct zone_attrtab * tabptr)30850Sstevel@tonic-gate zonecfg_add_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
30860Sstevel@tonic-gate {
30870Sstevel@tonic-gate int err;
30880Sstevel@tonic-gate
30890Sstevel@tonic-gate if (tabptr == NULL)
30900Sstevel@tonic-gate return (Z_INVAL);
30910Sstevel@tonic-gate
30920Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK)
30930Sstevel@tonic-gate return (err);
30940Sstevel@tonic-gate
30950Sstevel@tonic-gate if ((err = zonecfg_add_attr_core(handle, tabptr)) != Z_OK)
30960Sstevel@tonic-gate return (err);
30970Sstevel@tonic-gate
30980Sstevel@tonic-gate return (Z_OK);
30990Sstevel@tonic-gate }
31000Sstevel@tonic-gate
31010Sstevel@tonic-gate static int
zonecfg_delete_attr_core(zone_dochandle_t handle,struct zone_attrtab * tabptr)31020Sstevel@tonic-gate zonecfg_delete_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
31030Sstevel@tonic-gate {
31040Sstevel@tonic-gate xmlNodePtr cur = handle->zone_dh_cur;
31050Sstevel@tonic-gate int name_match, type_match, value_match;
31060Sstevel@tonic-gate
31070Sstevel@tonic-gate for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
31080Sstevel@tonic-gate if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
31090Sstevel@tonic-gate continue;
31100Sstevel@tonic-gate
31110Sstevel@tonic-gate name_match = match_prop(cur, DTD_ATTR_NAME,
31120Sstevel@tonic-gate tabptr->zone_attr_name);
31130Sstevel@tonic-gate type_match = match_prop(cur, DTD_ATTR_TYPE,
31140Sstevel@tonic-gate tabptr->zone_attr_type);
31150Sstevel@tonic-gate value_match = match_prop(cur, DTD_ATTR_VALUE,
31160Sstevel@tonic-gate tabptr->zone_attr_value);
31170Sstevel@tonic-gate
31180Sstevel@tonic-gate if (name_match && type_match && value_match) {
31190Sstevel@tonic-gate xmlUnlinkNode(cur);
31200Sstevel@tonic-gate xmlFreeNode(cur);
31210Sstevel@tonic-gate return (Z_OK);
31220Sstevel@tonic-gate }
31230Sstevel@tonic-gate }
31240Sstevel@tonic-gate return (Z_NO_RESOURCE_ID);
31250Sstevel@tonic-gate }
31260Sstevel@tonic-gate
31270Sstevel@tonic-gate int
zonecfg_delete_attr(zone_dochandle_t handle,struct zone_attrtab * tabptr)31280Sstevel@tonic-gate zonecfg_delete_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
31290Sstevel@tonic-gate {
31300Sstevel@tonic-gate int err;
31310Sstevel@tonic-gate
31320Sstevel@tonic-gate if (tabptr == NULL)
31330Sstevel@tonic-gate return (Z_INVAL);
31340Sstevel@tonic-gate
31350Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK)
31360Sstevel@tonic-gate return (err);
31370Sstevel@tonic-gate
31380Sstevel@tonic-gate if ((err = zonecfg_delete_attr_core(handle, tabptr)) != Z_OK)
31390Sstevel@tonic-gate return (err);
31400Sstevel@tonic-gate
31410Sstevel@tonic-gate return (Z_OK);
31420Sstevel@tonic-gate }
31430Sstevel@tonic-gate
31440Sstevel@tonic-gate int
zonecfg_modify_attr(zone_dochandle_t handle,struct zone_attrtab * oldtabptr,struct zone_attrtab * newtabptr)31450Sstevel@tonic-gate zonecfg_modify_attr(
31460Sstevel@tonic-gate zone_dochandle_t handle,
31470Sstevel@tonic-gate struct zone_attrtab *oldtabptr,
31480Sstevel@tonic-gate struct zone_attrtab *newtabptr)
31490Sstevel@tonic-gate {
31500Sstevel@tonic-gate int err;
31510Sstevel@tonic-gate
31520Sstevel@tonic-gate if (oldtabptr == NULL || newtabptr == NULL)
31530Sstevel@tonic-gate return (Z_INVAL);
31540Sstevel@tonic-gate
31550Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK)
31560Sstevel@tonic-gate return (err);
31570Sstevel@tonic-gate
31580Sstevel@tonic-gate if ((err = zonecfg_delete_attr_core(handle, oldtabptr)) != Z_OK)
31590Sstevel@tonic-gate return (err);
31600Sstevel@tonic-gate
31610Sstevel@tonic-gate if ((err = zonecfg_add_attr_core(handle, newtabptr)) != Z_OK)
31620Sstevel@tonic-gate return (err);
31630Sstevel@tonic-gate
31640Sstevel@tonic-gate return (Z_OK);
31650Sstevel@tonic-gate }
31660Sstevel@tonic-gate
31670Sstevel@tonic-gate int
zonecfg_get_attr_boolean(const struct zone_attrtab * attr,boolean_t * value)31680Sstevel@tonic-gate zonecfg_get_attr_boolean(const struct zone_attrtab *attr, boolean_t *value)
31690Sstevel@tonic-gate {
31700Sstevel@tonic-gate if (attr == NULL)
31710Sstevel@tonic-gate return (Z_INVAL);
31720Sstevel@tonic-gate
31730Sstevel@tonic-gate if (strcmp(attr->zone_attr_type, DTD_ENTITY_BOOLEAN) != 0)
31740Sstevel@tonic-gate return (Z_INVAL);
31750Sstevel@tonic-gate
31760Sstevel@tonic-gate if (strcmp(attr->zone_attr_value, DTD_ENTITY_TRUE) == 0) {
31770Sstevel@tonic-gate *value = B_TRUE;
31780Sstevel@tonic-gate return (Z_OK);
31790Sstevel@tonic-gate }
31800Sstevel@tonic-gate if (strcmp(attr->zone_attr_value, DTD_ENTITY_FALSE) == 0) {
31810Sstevel@tonic-gate *value = B_FALSE;
31820Sstevel@tonic-gate return (Z_OK);
31830Sstevel@tonic-gate }
31840Sstevel@tonic-gate return (Z_INVAL);
31850Sstevel@tonic-gate }
31860Sstevel@tonic-gate
31870Sstevel@tonic-gate int
zonecfg_get_attr_int(const struct zone_attrtab * attr,int64_t * value)31880Sstevel@tonic-gate zonecfg_get_attr_int(const struct zone_attrtab *attr, int64_t *value)
31890Sstevel@tonic-gate {
31900Sstevel@tonic-gate long long result;
31910Sstevel@tonic-gate char *endptr;
31920Sstevel@tonic-gate
31930Sstevel@tonic-gate if (attr == NULL)
31940Sstevel@tonic-gate return (Z_INVAL);
31950Sstevel@tonic-gate
31960Sstevel@tonic-gate if (strcmp(attr->zone_attr_type, DTD_ENTITY_INT) != 0)
31970Sstevel@tonic-gate return (Z_INVAL);
31980Sstevel@tonic-gate
31990Sstevel@tonic-gate errno = 0;
32000Sstevel@tonic-gate result = strtoll(attr->zone_attr_value, &endptr, 10);
32010Sstevel@tonic-gate if (errno != 0 || *endptr != '\0')
32020Sstevel@tonic-gate return (Z_INVAL);
32030Sstevel@tonic-gate *value = result;
32040Sstevel@tonic-gate return (Z_OK);
32050Sstevel@tonic-gate }
32060Sstevel@tonic-gate
32070Sstevel@tonic-gate int
zonecfg_get_attr_string(const struct zone_attrtab * attr,char * value,size_t val_sz)32080Sstevel@tonic-gate zonecfg_get_attr_string(const struct zone_attrtab *attr, char *value,
32090Sstevel@tonic-gate size_t val_sz)
32100Sstevel@tonic-gate {
32110Sstevel@tonic-gate if (attr == NULL)
32120Sstevel@tonic-gate return (Z_INVAL);
32130Sstevel@tonic-gate
32140Sstevel@tonic-gate if (strcmp(attr->zone_attr_type, DTD_ENTITY_STRING) != 0)
32150Sstevel@tonic-gate return (Z_INVAL);
32160Sstevel@tonic-gate
32170Sstevel@tonic-gate if (strlcpy(value, attr->zone_attr_value, val_sz) >= val_sz)
32180Sstevel@tonic-gate return (Z_TOO_BIG);
32190Sstevel@tonic-gate return (Z_OK);
32200Sstevel@tonic-gate }
32210Sstevel@tonic-gate
32220Sstevel@tonic-gate int
zonecfg_get_attr_uint(const struct zone_attrtab * attr,uint64_t * value)32230Sstevel@tonic-gate zonecfg_get_attr_uint(const struct zone_attrtab *attr, uint64_t *value)
32240Sstevel@tonic-gate {
32250Sstevel@tonic-gate unsigned long long result;
32260Sstevel@tonic-gate long long neg_result;
32270Sstevel@tonic-gate char *endptr;
32280Sstevel@tonic-gate
32290Sstevel@tonic-gate if (attr == NULL)
32300Sstevel@tonic-gate return (Z_INVAL);
32310Sstevel@tonic-gate
32320Sstevel@tonic-gate if (strcmp(attr->zone_attr_type, DTD_ENTITY_UINT) != 0)
32330Sstevel@tonic-gate return (Z_INVAL);
32340Sstevel@tonic-gate
32350Sstevel@tonic-gate errno = 0;
32360Sstevel@tonic-gate result = strtoull(attr->zone_attr_value, &endptr, 10);
32370Sstevel@tonic-gate if (errno != 0 || *endptr != '\0')
32380Sstevel@tonic-gate return (Z_INVAL);
32390Sstevel@tonic-gate errno = 0;
32400Sstevel@tonic-gate neg_result = strtoll(attr->zone_attr_value, &endptr, 10);
32410Sstevel@tonic-gate /*
32420Sstevel@tonic-gate * Incredibly, strtoull("<negative number>", ...) will not fail but
32430Sstevel@tonic-gate * return whatever (negative) number cast as a u_longlong_t, so we
32440Sstevel@tonic-gate * need to look for this here.
32450Sstevel@tonic-gate */
32460Sstevel@tonic-gate if (errno == 0 && neg_result < 0)
32470Sstevel@tonic-gate return (Z_INVAL);
32480Sstevel@tonic-gate *value = result;
32490Sstevel@tonic-gate return (Z_OK);
32500Sstevel@tonic-gate }
32510Sstevel@tonic-gate
32520Sstevel@tonic-gate int
zonecfg_lookup_rctl(zone_dochandle_t handle,struct zone_rctltab * tabptr)32530Sstevel@tonic-gate zonecfg_lookup_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
32540Sstevel@tonic-gate {
32550Sstevel@tonic-gate xmlNodePtr cur, val;
32560Sstevel@tonic-gate char savedname[MAXNAMELEN];
32570Sstevel@tonic-gate struct zone_rctlvaltab *valptr;
32580Sstevel@tonic-gate int err;
32590Sstevel@tonic-gate
32608057SJordan.Vaughan@Sun.com if (strlen(tabptr->zone_rctl_name) == 0)
32610Sstevel@tonic-gate return (Z_INVAL);
32620Sstevel@tonic-gate
32630Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK)
32640Sstevel@tonic-gate return (err);
32650Sstevel@tonic-gate
32660Sstevel@tonic-gate cur = handle->zone_dh_cur;
32670Sstevel@tonic-gate for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
32680Sstevel@tonic-gate if (xmlStrcmp(cur->name, DTD_ELEM_RCTL))
32690Sstevel@tonic-gate continue;
32700Sstevel@tonic-gate if ((fetchprop(cur, DTD_ATTR_NAME, savedname,
32710Sstevel@tonic-gate sizeof (savedname)) == Z_OK) &&
32720Sstevel@tonic-gate (strcmp(savedname, tabptr->zone_rctl_name) == 0)) {
32730Sstevel@tonic-gate tabptr->zone_rctl_valptr = NULL;
32740Sstevel@tonic-gate for (val = cur->xmlChildrenNode; val != NULL;
32750Sstevel@tonic-gate val = val->next) {
32760Sstevel@tonic-gate valptr = (struct zone_rctlvaltab *)malloc(
32770Sstevel@tonic-gate sizeof (struct zone_rctlvaltab));
32780Sstevel@tonic-gate if (valptr == NULL)
32790Sstevel@tonic-gate return (Z_NOMEM);
32800Sstevel@tonic-gate if ((fetchprop(val, DTD_ATTR_PRIV,
32810Sstevel@tonic-gate valptr->zone_rctlval_priv,
32820Sstevel@tonic-gate sizeof (valptr->zone_rctlval_priv)) !=
32830Sstevel@tonic-gate Z_OK))
32840Sstevel@tonic-gate break;
32850Sstevel@tonic-gate if ((fetchprop(val, DTD_ATTR_LIMIT,
32860Sstevel@tonic-gate valptr->zone_rctlval_limit,
32870Sstevel@tonic-gate sizeof (valptr->zone_rctlval_limit)) !=
32880Sstevel@tonic-gate Z_OK))
32890Sstevel@tonic-gate break;
32900Sstevel@tonic-gate if ((fetchprop(val, DTD_ATTR_ACTION,
32910Sstevel@tonic-gate valptr->zone_rctlval_action,
32920Sstevel@tonic-gate sizeof (valptr->zone_rctlval_action)) !=
32930Sstevel@tonic-gate Z_OK))
32940Sstevel@tonic-gate break;
32950Sstevel@tonic-gate if (zonecfg_add_rctl_value(tabptr, valptr) !=
32960Sstevel@tonic-gate Z_OK)
32970Sstevel@tonic-gate break;
32980Sstevel@tonic-gate }
32990Sstevel@tonic-gate return (Z_OK);
33000Sstevel@tonic-gate }
33010Sstevel@tonic-gate }
33020Sstevel@tonic-gate return (Z_NO_RESOURCE_ID);
33030Sstevel@tonic-gate }
33040Sstevel@tonic-gate
33050Sstevel@tonic-gate static int
zonecfg_add_rctl_core(zone_dochandle_t handle,struct zone_rctltab * tabptr)33060Sstevel@tonic-gate zonecfg_add_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr)
33070Sstevel@tonic-gate {
33080Sstevel@tonic-gate xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode;
33090Sstevel@tonic-gate struct zone_rctlvaltab *valptr;
33100Sstevel@tonic-gate int err;
33110Sstevel@tonic-gate
33120Sstevel@tonic-gate newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_RCTL, NULL);
3313228Sdp err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_rctl_name);
33140Sstevel@tonic-gate if (err != Z_OK)
33150Sstevel@tonic-gate return (err);
33160Sstevel@tonic-gate for (valptr = tabptr->zone_rctl_valptr; valptr != NULL;
33170Sstevel@tonic-gate valptr = valptr->zone_rctlval_next) {
33180Sstevel@tonic-gate valnode = xmlNewTextChild(newnode, NULL,
33190Sstevel@tonic-gate DTD_ELEM_RCTLVALUE, NULL);
3320228Sdp err = newprop(valnode, DTD_ATTR_PRIV,
33210Sstevel@tonic-gate valptr->zone_rctlval_priv);
33220Sstevel@tonic-gate if (err != Z_OK)
33230Sstevel@tonic-gate return (err);
3324228Sdp err = newprop(valnode, DTD_ATTR_LIMIT,
33250Sstevel@tonic-gate valptr->zone_rctlval_limit);
33260Sstevel@tonic-gate if (err != Z_OK)
33270Sstevel@tonic-gate return (err);
3328228Sdp err = newprop(valnode, DTD_ATTR_ACTION,
33290Sstevel@tonic-gate valptr->zone_rctlval_action);
33300Sstevel@tonic-gate if (err != Z_OK)
33310Sstevel@tonic-gate return (err);
33320Sstevel@tonic-gate }
33330Sstevel@tonic-gate return (Z_OK);
33340Sstevel@tonic-gate }
33350Sstevel@tonic-gate
33360Sstevel@tonic-gate int
zonecfg_add_rctl(zone_dochandle_t handle,struct zone_rctltab * tabptr)33370Sstevel@tonic-gate zonecfg_add_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
33380Sstevel@tonic-gate {
33390Sstevel@tonic-gate int err;
33400Sstevel@tonic-gate
33418057SJordan.Vaughan@Sun.com if (tabptr == NULL)
33420Sstevel@tonic-gate return (Z_INVAL);
33430Sstevel@tonic-gate
33440Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK)
33450Sstevel@tonic-gate return (err);
33460Sstevel@tonic-gate
33470Sstevel@tonic-gate if ((err = zonecfg_add_rctl_core(handle, tabptr)) != Z_OK)
33480Sstevel@tonic-gate return (err);
33490Sstevel@tonic-gate
33500Sstevel@tonic-gate return (Z_OK);
33510Sstevel@tonic-gate }
33520Sstevel@tonic-gate
33530Sstevel@tonic-gate static int
zonecfg_delete_rctl_core(zone_dochandle_t handle,struct zone_rctltab * tabptr)33540Sstevel@tonic-gate zonecfg_delete_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr)
33550Sstevel@tonic-gate {
33560Sstevel@tonic-gate xmlNodePtr cur = handle->zone_dh_cur;
33570Sstevel@tonic-gate xmlChar *savedname;
33580Sstevel@tonic-gate int name_result;
33590Sstevel@tonic-gate
33600Sstevel@tonic-gate for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
33610Sstevel@tonic-gate if (xmlStrcmp(cur->name, DTD_ELEM_RCTL))
33620Sstevel@tonic-gate continue;
33630Sstevel@tonic-gate
33640Sstevel@tonic-gate savedname = xmlGetProp(cur, DTD_ATTR_NAME);
33650Sstevel@tonic-gate if (savedname == NULL) /* shouldn't happen */
33660Sstevel@tonic-gate continue;
33670Sstevel@tonic-gate name_result = xmlStrcmp(savedname,
33680Sstevel@tonic-gate (const xmlChar *) tabptr->zone_rctl_name);
33690Sstevel@tonic-gate xmlFree(savedname);
33700Sstevel@tonic-gate
33710Sstevel@tonic-gate if (name_result == 0) {
33720Sstevel@tonic-gate xmlUnlinkNode(cur);
33730Sstevel@tonic-gate xmlFreeNode(cur);
33740Sstevel@tonic-gate return (Z_OK);
33750Sstevel@tonic-gate }
33760Sstevel@tonic-gate }
33770Sstevel@tonic-gate return (Z_NO_RESOURCE_ID);
33780Sstevel@tonic-gate }
33790Sstevel@tonic-gate
33800Sstevel@tonic-gate int
zonecfg_delete_rctl(zone_dochandle_t handle,struct zone_rctltab * tabptr)33810Sstevel@tonic-gate zonecfg_delete_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr)
33820Sstevel@tonic-gate {
33830Sstevel@tonic-gate int err;
33840Sstevel@tonic-gate
33858057SJordan.Vaughan@Sun.com if (tabptr == NULL)
33860Sstevel@tonic-gate return (Z_INVAL);
33870Sstevel@tonic-gate
33880Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK)
33890Sstevel@tonic-gate return (err);
33900Sstevel@tonic-gate
33910Sstevel@tonic-gate if ((err = zonecfg_delete_rctl_core(handle, tabptr)) != Z_OK)
33920Sstevel@tonic-gate return (err);
33930Sstevel@tonic-gate
33940Sstevel@tonic-gate return (Z_OK);
33950Sstevel@tonic-gate }
33960Sstevel@tonic-gate
33970Sstevel@tonic-gate int
zonecfg_modify_rctl(zone_dochandle_t handle,struct zone_rctltab * oldtabptr,struct zone_rctltab * newtabptr)33980Sstevel@tonic-gate zonecfg_modify_rctl(
33990Sstevel@tonic-gate zone_dochandle_t handle,
34000Sstevel@tonic-gate struct zone_rctltab *oldtabptr,
34010Sstevel@tonic-gate struct zone_rctltab *newtabptr)
34020Sstevel@tonic-gate {
34030Sstevel@tonic-gate int err;
34040Sstevel@tonic-gate
34058057SJordan.Vaughan@Sun.com if (oldtabptr == NULL || newtabptr == NULL)
34060Sstevel@tonic-gate return (Z_INVAL);
34070Sstevel@tonic-gate
34080Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK)
34090Sstevel@tonic-gate return (err);
34100Sstevel@tonic-gate
34110Sstevel@tonic-gate if ((err = zonecfg_delete_rctl_core(handle, oldtabptr)) != Z_OK)
34120Sstevel@tonic-gate return (err);
34130Sstevel@tonic-gate
34140Sstevel@tonic-gate if ((err = zonecfg_add_rctl_core(handle, newtabptr)) != Z_OK)
34150Sstevel@tonic-gate return (err);
34160Sstevel@tonic-gate
34170Sstevel@tonic-gate return (Z_OK);
34180Sstevel@tonic-gate }
34190Sstevel@tonic-gate
34200Sstevel@tonic-gate int
zonecfg_add_rctl_value(struct zone_rctltab * tabptr,struct zone_rctlvaltab * valtabptr)34210Sstevel@tonic-gate zonecfg_add_rctl_value(
34220Sstevel@tonic-gate struct zone_rctltab *tabptr,
34230Sstevel@tonic-gate struct zone_rctlvaltab *valtabptr)
34240Sstevel@tonic-gate {
34250Sstevel@tonic-gate struct zone_rctlvaltab *last, *old, *new;
34260Sstevel@tonic-gate rctlblk_t *rctlblk = alloca(rctlblk_size());
34270Sstevel@tonic-gate
34280Sstevel@tonic-gate last = tabptr->zone_rctl_valptr;
34290Sstevel@tonic-gate for (old = last; old != NULL; old = old->zone_rctlval_next)
34300Sstevel@tonic-gate last = old; /* walk to the end of the list */
34310Sstevel@tonic-gate new = valtabptr; /* alloc'd by caller */
34320Sstevel@tonic-gate new->zone_rctlval_next = NULL;
34330Sstevel@tonic-gate if (zonecfg_construct_rctlblk(valtabptr, rctlblk) != Z_OK)
34340Sstevel@tonic-gate return (Z_INVAL);
34350Sstevel@tonic-gate if (!zonecfg_valid_rctlblk(rctlblk))
34360Sstevel@tonic-gate return (Z_INVAL);
34370Sstevel@tonic-gate if (last == NULL)
34380Sstevel@tonic-gate tabptr->zone_rctl_valptr = new;
34390Sstevel@tonic-gate else
34400Sstevel@tonic-gate last->zone_rctlval_next = new;
34410Sstevel@tonic-gate return (Z_OK);
34420Sstevel@tonic-gate }
34430Sstevel@tonic-gate
34440Sstevel@tonic-gate int
zonecfg_remove_rctl_value(struct zone_rctltab * tabptr,struct zone_rctlvaltab * valtabptr)34450Sstevel@tonic-gate zonecfg_remove_rctl_value(
34460Sstevel@tonic-gate struct zone_rctltab *tabptr,
34470Sstevel@tonic-gate struct zone_rctlvaltab *valtabptr)
34480Sstevel@tonic-gate {
34490Sstevel@tonic-gate struct zone_rctlvaltab *last, *this, *next;
34500Sstevel@tonic-gate
34510Sstevel@tonic-gate last = tabptr->zone_rctl_valptr;
34520Sstevel@tonic-gate for (this = last; this != NULL; this = this->zone_rctlval_next) {
34530Sstevel@tonic-gate if (strcmp(this->zone_rctlval_priv,
34540Sstevel@tonic-gate valtabptr->zone_rctlval_priv) == 0 &&
34550Sstevel@tonic-gate strcmp(this->zone_rctlval_limit,
34560Sstevel@tonic-gate valtabptr->zone_rctlval_limit) == 0 &&
34570Sstevel@tonic-gate strcmp(this->zone_rctlval_action,
34580Sstevel@tonic-gate valtabptr->zone_rctlval_action) == 0) {
34590Sstevel@tonic-gate next = this->zone_rctlval_next;
34600Sstevel@tonic-gate if (this == tabptr->zone_rctl_valptr)
34610Sstevel@tonic-gate tabptr->zone_rctl_valptr = next;
34620Sstevel@tonic-gate else
34630Sstevel@tonic-gate last->zone_rctlval_next = next;
34640Sstevel@tonic-gate free(this);
34650Sstevel@tonic-gate return (Z_OK);
34660Sstevel@tonic-gate } else
34670Sstevel@tonic-gate last = this;
34680Sstevel@tonic-gate }
34690Sstevel@tonic-gate return (Z_NO_PROPERTY_ID);
34700Sstevel@tonic-gate }
34710Sstevel@tonic-gate
34727089Sgjelinek void
zonecfg_set_swinv(zone_dochandle_t handle)34737089Sgjelinek zonecfg_set_swinv(zone_dochandle_t handle)
34747089Sgjelinek {
34757089Sgjelinek handle->zone_dh_sw_inv = B_TRUE;
34767089Sgjelinek }
34777089Sgjelinek
34787089Sgjelinek /*
34797089Sgjelinek * Add the pkg to the sw inventory on the handle.
34807089Sgjelinek */
34817089Sgjelinek int
zonecfg_add_pkg(zone_dochandle_t handle,char * name,char * version)34827089Sgjelinek zonecfg_add_pkg(zone_dochandle_t handle, char *name, char *version)
34837089Sgjelinek {
34847089Sgjelinek xmlNodePtr newnode;
34857089Sgjelinek xmlNodePtr cur;
34867089Sgjelinek int err;
34877089Sgjelinek
34887089Sgjelinek if ((err = operation_prep(handle)) != Z_OK)
34897089Sgjelinek return (err);
34907089Sgjelinek
34917089Sgjelinek cur = handle->zone_dh_cur;
34927089Sgjelinek newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL);
34937089Sgjelinek if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK)
34947089Sgjelinek return (err);
34957089Sgjelinek if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK)
34967089Sgjelinek return (err);
34977089Sgjelinek return (Z_OK);
34987089Sgjelinek }
34997089Sgjelinek
35007089Sgjelinek int
zonecfg_add_patch(zone_dochandle_t handle,char * id,void ** pnode)35017089Sgjelinek zonecfg_add_patch(zone_dochandle_t handle, char *id, void **pnode)
35027089Sgjelinek {
35037089Sgjelinek xmlNodePtr node = (xmlNodePtr)*pnode;
35047089Sgjelinek xmlNodePtr cur;
35057089Sgjelinek int err;
35067089Sgjelinek
35077089Sgjelinek if ((err = operation_prep(handle)) != Z_OK)
35087089Sgjelinek return (err);
35097089Sgjelinek
35107089Sgjelinek cur = handle->zone_dh_cur;
35117089Sgjelinek node = xmlNewTextChild(cur, NULL, DTD_ELEM_PATCH, NULL);
35127089Sgjelinek if ((err = newprop(node, DTD_ATTR_ID, id)) != Z_OK)
35137089Sgjelinek return (err);
35147089Sgjelinek *pnode = (void *)node;
35157089Sgjelinek return (Z_OK);
35167089Sgjelinek }
35177089Sgjelinek
35187089Sgjelinek int
zonecfg_add_patch_obs(char * id,void * cur)35197089Sgjelinek zonecfg_add_patch_obs(char *id, void *cur)
35207089Sgjelinek {
35217089Sgjelinek xmlNodePtr node;
35227089Sgjelinek int err;
35237089Sgjelinek
35247089Sgjelinek node = xmlNewTextChild((xmlNodePtr)cur, NULL, DTD_ELEM_OBSOLETES, NULL);
35257089Sgjelinek if ((err = newprop(node, DTD_ATTR_ID, id)) != Z_OK)
35267089Sgjelinek return (err);
35277089Sgjelinek return (Z_OK);
35287089Sgjelinek }
35297089Sgjelinek
35300Sstevel@tonic-gate char *
zonecfg_strerror(int errnum)35310Sstevel@tonic-gate zonecfg_strerror(int errnum)
35320Sstevel@tonic-gate {
35330Sstevel@tonic-gate switch (errnum) {
35340Sstevel@tonic-gate case Z_OK:
35350Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "OK"));
35360Sstevel@tonic-gate case Z_EMPTY_DOCUMENT:
35370Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Empty document"));
35380Sstevel@tonic-gate case Z_WRONG_DOC_TYPE:
35390Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Wrong document type"));
35400Sstevel@tonic-gate case Z_BAD_PROPERTY:
35410Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Bad document property"));
35420Sstevel@tonic-gate case Z_TEMP_FILE:
35430Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN,
35440Sstevel@tonic-gate "Problem creating temporary file"));
35450Sstevel@tonic-gate case Z_SAVING_FILE:
35460Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Problem saving file"));
35470Sstevel@tonic-gate case Z_NO_ENTRY:
35480Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "No such entry"));
35490Sstevel@tonic-gate case Z_BOGUS_ZONE_NAME:
35500Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Bogus zone name"));
35510Sstevel@tonic-gate case Z_REQD_RESOURCE_MISSING:
35520Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Required resource missing"));
35530Sstevel@tonic-gate case Z_REQD_PROPERTY_MISSING:
35540Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Required property missing"));
35550Sstevel@tonic-gate case Z_BAD_HANDLE:
35560Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Bad handle"));
35570Sstevel@tonic-gate case Z_NOMEM:
35580Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Out of memory"));
35590Sstevel@tonic-gate case Z_INVAL:
35600Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Invalid argument"));
35610Sstevel@tonic-gate case Z_ACCES:
35620Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Permission denied"));
35630Sstevel@tonic-gate case Z_TOO_BIG:
35640Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Argument list too long"));
35650Sstevel@tonic-gate case Z_MISC_FS:
35660Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN,
35670Sstevel@tonic-gate "Miscellaneous file system error"));
35680Sstevel@tonic-gate case Z_NO_ZONE:
35690Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "No such zone configured"));
35700Sstevel@tonic-gate case Z_NO_RESOURCE_TYPE:
35710Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "No such resource type"));
35720Sstevel@tonic-gate case Z_NO_RESOURCE_ID:
35730Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "No such resource with that id"));
35740Sstevel@tonic-gate case Z_NO_PROPERTY_TYPE:
35750Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "No such property type"));
35760Sstevel@tonic-gate case Z_NO_PROPERTY_ID:
35770Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "No such property with that id"));
3578565Sdp case Z_BAD_ZONE_STATE:
35790Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN,
3580565Sdp "Zone state is invalid for the requested operation"));
35810Sstevel@tonic-gate case Z_INVALID_DOCUMENT:
35820Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Invalid document"));
3583565Sdp case Z_NAME_IN_USE:
3584565Sdp return (dgettext(TEXT_DOMAIN, "Zone name already in use"));
35850Sstevel@tonic-gate case Z_NO_SUCH_ID:
35860Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "No such zone ID"));
35870Sstevel@tonic-gate case Z_UPDATING_INDEX:
35880Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Problem updating index file"));
35890Sstevel@tonic-gate case Z_LOCKING_FILE:
35900Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Locking index file"));
35910Sstevel@tonic-gate case Z_UNLOCKING_FILE:
35920Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Unlocking index file"));
35930Sstevel@tonic-gate case Z_INSUFFICIENT_SPEC:
35940Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Insufficient specification"));
35950Sstevel@tonic-gate case Z_RESOLVED_PATH:
35960Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Resolved path mismatch"));
35970Sstevel@tonic-gate case Z_IPV6_ADDR_PREFIX_LEN:
35980Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN,
35990Sstevel@tonic-gate "IPv6 address missing required prefix length"));
36000Sstevel@tonic-gate case Z_BOGUS_ADDRESS:
36010Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN,
36020Sstevel@tonic-gate "Neither an IPv4 nor an IPv6 address nor a host name"));
36031645Scomay case Z_PRIV_PROHIBITED:
36041645Scomay return (dgettext(TEXT_DOMAIN,
36051645Scomay "Specified privilege is prohibited"));
36061645Scomay case Z_PRIV_REQUIRED:
36071645Scomay return (dgettext(TEXT_DOMAIN,
36081645Scomay "Required privilege is missing"));
36091645Scomay case Z_PRIV_UNKNOWN:
36101645Scomay return (dgettext(TEXT_DOMAIN,
36111645Scomay "Specified privilege is unknown"));
36122712Snn35248 case Z_BRAND_ERROR:
36132712Snn35248 return (dgettext(TEXT_DOMAIN,
36142712Snn35248 "Brand-specific error"));
36153247Sgjelinek case Z_INCOMPATIBLE:
36163247Sgjelinek return (dgettext(TEXT_DOMAIN, "Incompatible settings"));
36173247Sgjelinek case Z_ALIAS_DISALLOW:
36183247Sgjelinek return (dgettext(TEXT_DOMAIN,
36193247Sgjelinek "An incompatible rctl already exists for this property"));
36203247Sgjelinek case Z_CLEAR_DISALLOW:
36213247Sgjelinek return (dgettext(TEXT_DOMAIN,
36223247Sgjelinek "Clearing this property is not allowed"));
36233247Sgjelinek case Z_POOL:
36243247Sgjelinek return (dgettext(TEXT_DOMAIN, "libpool(3LIB) error"));
36253247Sgjelinek case Z_POOLS_NOT_ACTIVE:
36263247Sgjelinek return (dgettext(TEXT_DOMAIN, "Pools facility not active; "
36273247Sgjelinek "zone will not be bound to pool"));
36283247Sgjelinek case Z_POOL_ENABLE:
36293247Sgjelinek return (dgettext(TEXT_DOMAIN,
36303247Sgjelinek "Could not enable pools facility"));
36313247Sgjelinek case Z_NO_POOL:
36323247Sgjelinek return (dgettext(TEXT_DOMAIN,
36333247Sgjelinek "Pool not found; using default pool"));
36343247Sgjelinek case Z_POOL_CREATE:
36353247Sgjelinek return (dgettext(TEXT_DOMAIN,
36363247Sgjelinek "Could not create a temporary pool"));
36373247Sgjelinek case Z_POOL_BIND:
36383247Sgjelinek return (dgettext(TEXT_DOMAIN, "Could not bind zone to pool"));
363912633Sjohn.levon@sun.com case Z_INVALID_PROPERTY:
364012633Sjohn.levon@sun.com return (dgettext(TEXT_DOMAIN, "Specified property is invalid"));
36418057SJordan.Vaughan@Sun.com case Z_SYSTEM:
36428057SJordan.Vaughan@Sun.com return (strerror(errno));
36430Sstevel@tonic-gate default:
36440Sstevel@tonic-gate return (dgettext(TEXT_DOMAIN, "Unknown error"));
36450Sstevel@tonic-gate }
36460Sstevel@tonic-gate }
36470Sstevel@tonic-gate
36480Sstevel@tonic-gate /*
36490Sstevel@tonic-gate * Note that the zonecfg_setXent() and zonecfg_endXent() calls are all the
36500Sstevel@tonic-gate * same, as they just turn around and call zonecfg_setent() / zonecfg_endent().
36510Sstevel@tonic-gate */
36520Sstevel@tonic-gate
36530Sstevel@tonic-gate static int
zonecfg_setent(zone_dochandle_t handle)36540Sstevel@tonic-gate zonecfg_setent(zone_dochandle_t handle)
36550Sstevel@tonic-gate {
36560Sstevel@tonic-gate xmlNodePtr cur;
36570Sstevel@tonic-gate int err;
36580Sstevel@tonic-gate
36590Sstevel@tonic-gate if (handle == NULL)
36600Sstevel@tonic-gate return (Z_INVAL);
36610Sstevel@tonic-gate
36620Sstevel@tonic-gate if ((err = operation_prep(handle)) != Z_OK) {
36630Sstevel@tonic-gate handle->zone_dh_cur = NULL;
36640Sstevel@tonic-gate return (err);
36650Sstevel@tonic-gate }
36660Sstevel@tonic-gate cur = handle->zone_dh_cur;
36670Sstevel@tonic-gate cur = cur->xmlChildrenNode;
36680Sstevel@tonic-gate handle->zone_dh_cur = cur;
36690Sstevel@tonic-gate return (Z_OK);
36700Sstevel@tonic-gate }
36710Sstevel@tonic-gate
36720Sstevel@tonic-gate static int
zonecfg_endent(zone_dochandle_t handle)36730Sstevel@tonic-gate zonecfg_endent(zone_dochandle_t handle)
36740Sstevel@tonic-gate {
36750Sstevel@tonic-gate if (handle == NULL)
36760Sstevel@tonic-gate return (Z_INVAL);
36770Sstevel@tonic-gate
36780Sstevel@tonic-gate handle->zone_dh_cur = handle->zone_dh_top;
36790Sstevel@tonic-gate return (Z_OK);
36800Sstevel@tonic-gate }
36810Sstevel@tonic-gate
36823247Sgjelinek /*
36833247Sgjelinek * Do the work required to manipulate a process through libproc.
36843247Sgjelinek * If grab_process() returns no errors (0), then release_process()
36853247Sgjelinek * must eventually be called.
36863247Sgjelinek *
36873247Sgjelinek * Return values:
36883247Sgjelinek * 0 Successful creation of agent thread
36893247Sgjelinek * 1 Error grabbing
36903247Sgjelinek * 2 Error creating agent
36913247Sgjelinek */
36923247Sgjelinek static int
grab_process(pr_info_handle_t * p)36933247Sgjelinek grab_process(pr_info_handle_t *p)
36943247Sgjelinek {
36953247Sgjelinek int ret;
36963247Sgjelinek
36973247Sgjelinek if ((p->pr = Pgrab(p->pid, 0, &ret)) != NULL) {
36983247Sgjelinek
36993247Sgjelinek if (Psetflags(p->pr, PR_RLC) != 0) {
37003247Sgjelinek Prelease(p->pr, 0);
37013247Sgjelinek return (1);
37023247Sgjelinek }
37033247Sgjelinek if (Pcreate_agent(p->pr) == 0) {
37043247Sgjelinek return (0);
37053247Sgjelinek
37063247Sgjelinek } else {
37073247Sgjelinek Prelease(p->pr, 0);
37083247Sgjelinek return (2);
37093247Sgjelinek }
37103247Sgjelinek } else {
37113247Sgjelinek return (1);
37123247Sgjelinek }
37133247Sgjelinek }
37143247Sgjelinek
37153247Sgjelinek /*
37163247Sgjelinek * Release the specified process. This destroys the agent
37173247Sgjelinek * and releases the process. If the process is NULL, nothing
37183247Sgjelinek * is done. This function should only be called if grab_process()
37193247Sgjelinek * has previously been called and returned success.
37203247Sgjelinek *
37213247Sgjelinek * This function is Pgrab-safe.
37223247Sgjelinek */
37233247Sgjelinek static void
release_process(struct ps_prochandle * Pr)37243247Sgjelinek release_process(struct ps_prochandle *Pr)
37253247Sgjelinek {
37263247Sgjelinek if (Pr == NULL)
37273247Sgjelinek return;
37283247Sgjelinek
37293247Sgjelinek Pdestroy_agent(Pr);
37303247Sgjelinek Prelease(Pr, 0);
37313247Sgjelinek }
37323247Sgjelinek
37333247Sgjelinek static boolean_t
grab_zone_proc(char * zonename,pr_info_handle_t * p)37343247Sgjelinek grab_zone_proc(char *zonename, pr_info_handle_t *p)
37353247Sgjelinek {
37363247Sgjelinek DIR *dirp;
37373247Sgjelinek struct dirent *dentp;
37383247Sgjelinek zoneid_t zoneid;
37393247Sgjelinek int pid_self;
37403247Sgjelinek psinfo_t psinfo;
37413247Sgjelinek
37423247Sgjelinek if (zone_get_id(zonename, &zoneid) != 0)
37433247Sgjelinek return (B_FALSE);
37443247Sgjelinek
37453247Sgjelinek pid_self = getpid();
37463247Sgjelinek
37473247Sgjelinek if ((dirp = opendir("/proc")) == NULL)
37483247Sgjelinek return (B_FALSE);
37493247Sgjelinek
37503247Sgjelinek while (dentp = readdir(dirp)) {
37513247Sgjelinek p->pid = atoi(dentp->d_name);
37523247Sgjelinek
37533247Sgjelinek /* Skip self */
37543247Sgjelinek if (p->pid == pid_self)
37553247Sgjelinek continue;
37563247Sgjelinek
37573247Sgjelinek if (proc_get_psinfo(p->pid, &psinfo) != 0)
37583247Sgjelinek continue;
37593247Sgjelinek
37603247Sgjelinek if (psinfo.pr_zoneid != zoneid)
37613247Sgjelinek continue;
37623247Sgjelinek
37633247Sgjelinek /* attempt to grab process */
37643247Sgjelinek if (grab_process(p) != 0)
37653247Sgjelinek continue;
37663247Sgjelinek
37673247Sgjelinek if (pr_getzoneid(p->pr) != zoneid) {
37683247Sgjelinek release_process(p->pr);
37693247Sgjelinek continue;
37703247Sgjelinek }
37713247Sgjelinek
37723247Sgjelinek (void) closedir(dirp);
37733247Sgjelinek return (B_TRUE);
37743247Sgjelinek }
37753247Sgjelinek
37763247Sgjelinek (void) closedir(dirp);
37773247Sgjelinek return (B_FALSE);
37783247Sgjelinek }
37793247Sgjelinek
37803247Sgjelinek static boolean_t
get_priv_rctl(struct ps_prochandle * pr,char * name,rctlblk_t * rblk)37813247Sgjelinek get_priv_rctl(struct ps_prochandle *pr, char *name, rctlblk_t *rblk)
37823247Sgjelinek {
37833247Sgjelinek if (pr_getrctl(pr, name, NULL, rblk, RCTL_FIRST))
37843247Sgjelinek return (B_FALSE);
37853247Sgjelinek
37863247Sgjelinek if (rctlblk_get_privilege(rblk) == RCPRIV_PRIVILEGED)
37873247Sgjelinek return (B_TRUE);
37883247Sgjelinek
37893247Sgjelinek while (pr_getrctl(pr, name, rblk, rblk, RCTL_NEXT) == 0) {
37903247Sgjelinek if (rctlblk_get_privilege(rblk) == RCPRIV_PRIVILEGED)
37913247Sgjelinek return (B_TRUE);
37923247Sgjelinek }
37933247Sgjelinek
37943247Sgjelinek return (B_FALSE);
37953247Sgjelinek }
37963247Sgjelinek
37973247Sgjelinek /*
37983247Sgjelinek * Apply the current rctl settings to the specified, running zone.
37993247Sgjelinek */
38003247Sgjelinek int
zonecfg_apply_rctls(char * zone_name,zone_dochandle_t handle)38013247Sgjelinek zonecfg_apply_rctls(char *zone_name, zone_dochandle_t handle)
38023247Sgjelinek {
38033247Sgjelinek int err;
38043247Sgjelinek int res = Z_OK;
38053247Sgjelinek rctlblk_t *rblk;
38063247Sgjelinek pr_info_handle_t p;
38073247Sgjelinek struct zone_rctltab rctl;
38083247Sgjelinek
38093247Sgjelinek if ((err = zonecfg_setrctlent(handle)) != Z_OK)
38103247Sgjelinek return (err);
38113247Sgjelinek
38123247Sgjelinek if ((rblk = (rctlblk_t *)malloc(rctlblk_size())) == NULL) {
38133247Sgjelinek (void) zonecfg_endrctlent(handle);
38143247Sgjelinek return (Z_NOMEM);
38153247Sgjelinek }
38163247Sgjelinek
38173247Sgjelinek if (!grab_zone_proc(zone_name, &p)) {
38183247Sgjelinek (void) zonecfg_endrctlent(handle);
38193247Sgjelinek free(rblk);
38203247Sgjelinek return (Z_SYSTEM);
38213247Sgjelinek }
38223247Sgjelinek
38233247Sgjelinek while (zonecfg_getrctlent(handle, &rctl) == Z_OK) {
38243247Sgjelinek char *rname;
38253247Sgjelinek struct zone_rctlvaltab *valptr;
38263247Sgjelinek
38273247Sgjelinek rname = rctl.zone_rctl_name;
38283247Sgjelinek
38293247Sgjelinek /* first delete all current privileged settings for this rctl */
38303247Sgjelinek while (get_priv_rctl(p.pr, rname, rblk)) {
38313247Sgjelinek if (pr_setrctl(p.pr, rname, NULL, rblk, RCTL_DELETE) !=
38323247Sgjelinek 0) {
38333247Sgjelinek res = Z_SYSTEM;
38343247Sgjelinek goto done;
38353247Sgjelinek }
38363247Sgjelinek }
38373247Sgjelinek
38383247Sgjelinek /* now set each new value for the rctl */
38393247Sgjelinek for (valptr = rctl.zone_rctl_valptr; valptr != NULL;
38403247Sgjelinek valptr = valptr->zone_rctlval_next) {
38413247Sgjelinek if ((err = zonecfg_construct_rctlblk(valptr, rblk))
38423247Sgjelinek != Z_OK) {
38433247Sgjelinek res = errno = err;
38443247Sgjelinek goto done;
38453247Sgjelinek }
38463247Sgjelinek
38473247Sgjelinek if (pr_setrctl(p.pr, rname, NULL, rblk, RCTL_INSERT)) {
38483247Sgjelinek res = Z_SYSTEM;
38493247Sgjelinek goto done;
38503247Sgjelinek }
38513247Sgjelinek }
38523247Sgjelinek }
38533247Sgjelinek
38543247Sgjelinek done:
38553247Sgjelinek release_process(p.pr);
38563247Sgjelinek free(rblk);
38573247Sgjelinek (void) zonecfg_endrctlent(handle);
38583247Sgjelinek
38593247Sgjelinek return (res);
38603247Sgjelinek }
38613247Sgjelinek
38623247Sgjelinek static const xmlChar *
nm_to_dtd(char * nm)38633247Sgjelinek nm_to_dtd(char *nm)
38643247Sgjelinek {
38653247Sgjelinek if (strcmp(nm, "device") == 0)
38663247Sgjelinek return (DTD_ELEM_DEVICE);
38673247Sgjelinek if (strcmp(nm, "fs") == 0)
38683247Sgjelinek return (DTD_ELEM_FS);
38693247Sgjelinek if (strcmp(nm, "net") == 0)
38703247Sgjelinek return (DTD_ELEM_NET);
38713247Sgjelinek if (strcmp(nm, "attr") == 0)
38723247Sgjelinek return (DTD_ELEM_ATTR);
38733247Sgjelinek if (strcmp(nm, "rctl") == 0)
38743247Sgjelinek return (DTD_ELEM_RCTL);
38753247Sgjelinek if (strcmp(nm, "dataset") == 0)
38763247Sgjelinek return (DTD_ELEM_DATASET);
387712578SGlenn.Faden@Sun.COM if (strcmp(nm, "admin") == 0)
387812578SGlenn.Faden@Sun.COM return (DTD_ELEM_ADMIN);
38793247Sgjelinek
38803247Sgjelinek return (NULL);
38813247Sgjelinek }
38823247Sgjelinek
38833247Sgjelinek int
zonecfg_num_resources(zone_dochandle_t handle,char * rsrc)38843247Sgjelinek zonecfg_num_resources(zone_dochandle_t handle, char *rsrc)
38853247Sgjelinek {
38863247Sgjelinek int num = 0;
38873247Sgjelinek const xmlChar *dtd;
38883247Sgjelinek xmlNodePtr cur;
38893247Sgjelinek
38903247Sgjelinek if ((dtd = nm_to_dtd(rsrc)) == NULL)
38913247Sgjelinek return (num);
38923247Sgjelinek
38933247Sgjelinek if (zonecfg_setent(handle) != Z_OK)
38943247Sgjelinek return (num);
38953247Sgjelinek
38963247Sgjelinek for (cur = handle->zone_dh_cur; cur != NULL; cur = cur->next)
38973247Sgjelinek if (xmlStrcmp(cur->name, dtd) == 0)
38983247Sgjelinek num++;
38993247Sgjelinek
39003247Sgjelinek (void) zonecfg_endent(handle);
39013247Sgjelinek
39023247Sgjelinek return (num);
39033247Sgjelinek }
39043247Sgjelinek
39053247Sgjelinek int
zonecfg_del_all_resources(zone_dochandle_t handle,char * rsrc)39063247Sgjelinek zonecfg_del_all_resources(zone_dochandle_t handle, char *rsrc)
39073247Sgjelinek {
39083247Sgjelinek int err;
39093247Sgjelinek const xmlChar *dtd;
39103247Sgjelinek xmlNodePtr cur;
39113247Sgjelinek
39123247Sgjelinek if ((dtd = nm_to_dtd(rsrc)) == NULL)
39133247Sgjelinek return (Z_NO_RESOURCE_TYPE);
39143247Sgjelinek
39153247Sgjelinek if ((err = zonecfg_setent(handle)) != Z_OK)
39163247Sgjelinek return (err);
39173247Sgjelinek
39183247Sgjelinek cur = handle->zone_dh_cur;
39193247Sgjelinek while (cur != NULL) {
39203247Sgjelinek xmlNodePtr tmp;
39213247Sgjelinek
39223247Sgjelinek if (xmlStrcmp(cur->name, dtd)) {
39233247Sgjelinek cur = cur->next;
39243247Sgjelinek continue;
39253247Sgjelinek }
39263247Sgjelinek
39273247Sgjelinek tmp = cur->next;
39283247Sgjelinek xmlUnlinkNode(cur);
39293247Sgjelinek xmlFreeNode(cur);
39303247Sgjelinek cur = tmp;
39313247Sgjelinek }
39323247Sgjelinek
39333247Sgjelinek (void) zonecfg_endent(handle);
39343247Sgjelinek return (Z_OK);
39353247Sgjelinek }
39363247Sgjelinek
39373247Sgjelinek static boolean_t
valid_uint(char * s,uint64_t * n)39383247Sgjelinek valid_uint(char *s, uint64_t *n)
39393247Sgjelinek {
39403247Sgjelinek char *endp;
39413247Sgjelinek
39423247Sgjelinek /* strtoull accepts '-'?! so we want to flag that as an error */
39433247Sgjelinek if (strchr(s, '-') != NULL)
39443247Sgjelinek return (B_FALSE);
39453247Sgjelinek
39463247Sgjelinek errno = 0;
39473247Sgjelinek *n = strtoull(s, &endp, 10);
39483247Sgjelinek
39493247Sgjelinek if (errno != 0 || *endp != '\0')
39503247Sgjelinek return (B_FALSE);
39513247Sgjelinek return (B_TRUE);
39523247Sgjelinek }
39533247Sgjelinek
39543247Sgjelinek /*
39553247Sgjelinek * Convert a string representing a number (possibly a fraction) into an integer.
39563247Sgjelinek * The string can have a modifier (K, M, G or T). The modifiers are treated
39573247Sgjelinek * as powers of two (not 10).
39583247Sgjelinek */
39593247Sgjelinek int
zonecfg_str_to_bytes(char * str,uint64_t * bytes)39603247Sgjelinek zonecfg_str_to_bytes(char *str, uint64_t *bytes)
39613247Sgjelinek {
39623247Sgjelinek long double val;
39633247Sgjelinek char *unitp;
39643247Sgjelinek uint64_t scale;
39653247Sgjelinek
39663247Sgjelinek if ((val = strtold(str, &unitp)) < 0)
39673247Sgjelinek return (-1);
39683247Sgjelinek
39693247Sgjelinek /* remove any leading white space from units string */
39703247Sgjelinek while (isspace(*unitp) != 0)
39713247Sgjelinek ++unitp;
39723247Sgjelinek
39733247Sgjelinek /* if no units explicitly set, error */
39743247Sgjelinek if (unitp == NULL || *unitp == '\0') {
39753247Sgjelinek scale = 1;
39763247Sgjelinek } else {
39773247Sgjelinek int i;
39783247Sgjelinek char *units[] = {"K", "M", "G", "T", NULL};
39793247Sgjelinek
39803247Sgjelinek scale = 1024;
39813247Sgjelinek
39823247Sgjelinek /* update scale based on units */
39833247Sgjelinek for (i = 0; units[i] != NULL; i++) {
39843247Sgjelinek if (strcasecmp(unitp, units[i]) == 0)
39853247Sgjelinek break;
39863247Sgjelinek scale <<= 10;
39873247Sgjelinek }
39883247Sgjelinek
39893247Sgjelinek if (units[i] == NULL)
39903247Sgjelinek return (-1);
39913247Sgjelinek }
39923247Sgjelinek
39933247Sgjelinek *bytes = (uint64_t)(val * scale);
39943247Sgjelinek return (0);
39953247Sgjelinek }
39963247Sgjelinek
39973247Sgjelinek boolean_t
zonecfg_valid_ncpus(char * lowstr,char * highstr)39983247Sgjelinek zonecfg_valid_ncpus(char *lowstr, char *highstr)
39993247Sgjelinek {
40003247Sgjelinek uint64_t low, high;
40013247Sgjelinek
40023247Sgjelinek if (!valid_uint(lowstr, &low) || !valid_uint(highstr, &high) ||
40033247Sgjelinek low < 1 || low > high)
40043247Sgjelinek return (B_FALSE);
40053247Sgjelinek
40063247Sgjelinek return (B_TRUE);
40073247Sgjelinek }
40083247Sgjelinek
40093247Sgjelinek boolean_t
zonecfg_valid_importance(char * impstr)40103247Sgjelinek zonecfg_valid_importance(char *impstr)
40113247Sgjelinek {
40123247Sgjelinek uint64_t num;
40133247Sgjelinek
40143247Sgjelinek if (!valid_uint(impstr, &num))
40153247Sgjelinek return (B_FALSE);
40163247Sgjelinek
40173247Sgjelinek return (B_TRUE);
40183247Sgjelinek }
40193247Sgjelinek
40203247Sgjelinek boolean_t
zonecfg_valid_alias_limit(char * name,char * limitstr,uint64_t * limit)40213247Sgjelinek zonecfg_valid_alias_limit(char *name, char *limitstr, uint64_t *limit)
40223247Sgjelinek {
40233247Sgjelinek int i;
40243247Sgjelinek
40253247Sgjelinek for (i = 0; aliases[i].shortname != NULL; i++)
40263247Sgjelinek if (strcmp(name, aliases[i].shortname) == 0)
40273247Sgjelinek break;
40283247Sgjelinek
40293247Sgjelinek if (aliases[i].shortname == NULL)
40303247Sgjelinek return (B_FALSE);
40313247Sgjelinek
40323247Sgjelinek if (!valid_uint(limitstr, limit) || *limit < aliases[i].low_limit)
40333247Sgjelinek return (B_FALSE);
40343247Sgjelinek
40353247Sgjelinek return (B_TRUE);
40363247Sgjelinek }
40373247Sgjelinek
40383247Sgjelinek boolean_t
zonecfg_valid_memlimit(char * memstr,uint64_t * mem_val)40393247Sgjelinek zonecfg_valid_memlimit(char *memstr, uint64_t *mem_val)
40403247Sgjelinek {
40413247Sgjelinek if (zonecfg_str_to_bytes(memstr, mem_val) != 0)
40423247Sgjelinek return (B_FALSE);
40433247Sgjelinek
40443247Sgjelinek return (B_TRUE);
40453247Sgjelinek }
40463247Sgjelinek
40473247Sgjelinek static int
zerr_pool(char * pool_err,int err_size,int res)40483247Sgjelinek zerr_pool(char *pool_err, int err_size, int res)
40493247Sgjelinek {
40503247Sgjelinek (void) strlcpy(pool_err, pool_strerror(pool_error()), err_size);
40513247Sgjelinek return (res);
40523247Sgjelinek }
40533247Sgjelinek
40543247Sgjelinek static int
create_tmp_pset(char * pool_err,int err_size,pool_conf_t * pconf,pool_t * pool,char * name,int min,int max)40553247Sgjelinek create_tmp_pset(char *pool_err, int err_size, pool_conf_t *pconf, pool_t *pool,
40563247Sgjelinek char *name, int min, int max)
40573247Sgjelinek {
40583247Sgjelinek pool_resource_t *res;
40593247Sgjelinek pool_elem_t *elem;
40603247Sgjelinek pool_value_t *val;
40613247Sgjelinek
40623247Sgjelinek if ((res = pool_resource_create(pconf, "pset", name)) == NULL)
40633247Sgjelinek return (zerr_pool(pool_err, err_size, Z_POOL));
40643247Sgjelinek
40653247Sgjelinek if (pool_associate(pconf, pool, res) != PO_SUCCESS)
40663247Sgjelinek return (zerr_pool(pool_err, err_size, Z_POOL));
40673247Sgjelinek
40683247Sgjelinek if ((elem = pool_resource_to_elem(pconf, res)) == NULL)
40693247Sgjelinek return (zerr_pool(pool_err, err_size, Z_POOL));
40703247Sgjelinek
40713247Sgjelinek if ((val = pool_value_alloc()) == NULL)
40723247Sgjelinek return (zerr_pool(pool_err, err_size, Z_POOL));
40733247Sgjelinek
40743247Sgjelinek /* set the maximum number of cpus for the pset */
40753247Sgjelinek pool_value_set_uint64(val, (uint64_t)max);
40763247Sgjelinek
40773247Sgjelinek if (pool_put_property(pconf, elem, "pset.max", val) != PO_SUCCESS) {
40783247Sgjelinek pool_value_free(val);
40793247Sgjelinek return (zerr_pool(pool_err, err_size, Z_POOL));
40803247Sgjelinek }
40813247Sgjelinek
40823247Sgjelinek /* set the minimum number of cpus for the pset */
40833247Sgjelinek pool_value_set_uint64(val, (uint64_t)min);
40843247Sgjelinek
40853247Sgjelinek if (pool_put_property(pconf, elem, "pset.min", val) != PO_SUCCESS) {
40863247Sgjelinek pool_value_free(val);
40873247Sgjelinek return (zerr_pool(pool_err, err_size, Z_POOL));
40883247Sgjelinek }
40893247Sgjelinek
40903247Sgjelinek pool_value_free(val);
40913247Sgjelinek
40923247Sgjelinek return (Z_OK);
40933247Sgjelinek }
40943247Sgjelinek
40953247Sgjelinek static int
create_tmp_pool(char * pool_err,int err_size,pool_conf_t * pconf,char * name,struct zone_psettab * pset_tab)40963247Sgjelinek create_tmp_pool(char *pool_err, int err_size, pool_conf_t *pconf, char *name,
40973247Sgjelinek struct zone_psettab *pset_tab)
40983247Sgjelinek {
40993247Sgjelinek pool_t *pool;
41003247Sgjelinek int res = Z_OK;
41013247Sgjelinek
41023247Sgjelinek /* create a temporary pool configuration */
41033247Sgjelinek if (pool_conf_open(pconf, NULL, PO_TEMP) != PO_SUCCESS) {
41043247Sgjelinek res = zerr_pool(pool_err, err_size, Z_POOL);
41053247Sgjelinek return (res);
41063247Sgjelinek }
41073247Sgjelinek
41083247Sgjelinek if ((pool = pool_create(pconf, name)) == NULL) {
41093247Sgjelinek res = zerr_pool(pool_err, err_size, Z_POOL_CREATE);
41103247Sgjelinek goto done;
41113247Sgjelinek }
41123247Sgjelinek
41133247Sgjelinek /* set pool importance */
41143247Sgjelinek if (pset_tab->zone_importance[0] != '\0') {
41153247Sgjelinek pool_elem_t *elem;
41163247Sgjelinek pool_value_t *val;
41173247Sgjelinek
41183247Sgjelinek if ((elem = pool_to_elem(pconf, pool)) == NULL) {
41193247Sgjelinek res = zerr_pool(pool_err, err_size, Z_POOL);
41203247Sgjelinek goto done;
41213247Sgjelinek }
41223247Sgjelinek
41233247Sgjelinek if ((val = pool_value_alloc()) == NULL) {
41243247Sgjelinek res = zerr_pool(pool_err, err_size, Z_POOL);
41253247Sgjelinek goto done;
41263247Sgjelinek }
41273247Sgjelinek
41283247Sgjelinek pool_value_set_int64(val,
41293247Sgjelinek (int64_t)atoi(pset_tab->zone_importance));
41303247Sgjelinek
41313247Sgjelinek if (pool_put_property(pconf, elem, "pool.importance", val)
41323247Sgjelinek != PO_SUCCESS) {
41333247Sgjelinek res = zerr_pool(pool_err, err_size, Z_POOL);
41343247Sgjelinek pool_value_free(val);
41353247Sgjelinek goto done;
41363247Sgjelinek }
41373247Sgjelinek
41383247Sgjelinek pool_value_free(val);
41393247Sgjelinek }
41403247Sgjelinek
41413247Sgjelinek if ((res = create_tmp_pset(pool_err, err_size, pconf, pool, name,
41423247Sgjelinek atoi(pset_tab->zone_ncpu_min),
41433247Sgjelinek atoi(pset_tab->zone_ncpu_max))) != Z_OK)
41443247Sgjelinek goto done;
41453247Sgjelinek
41463247Sgjelinek /* validation */
41473247Sgjelinek if (pool_conf_status(pconf) == POF_INVALID) {
41483247Sgjelinek res = zerr_pool(pool_err, err_size, Z_POOL);
41493247Sgjelinek goto done;
41503247Sgjelinek }
41513247Sgjelinek
41523247Sgjelinek /*
41533247Sgjelinek * This validation is the one we expect to fail if the user specified
41543247Sgjelinek * an invalid configuration (too many cpus) for this system.
41553247Sgjelinek */
41563247Sgjelinek if (pool_conf_validate(pconf, POV_RUNTIME) != PO_SUCCESS) {
41573247Sgjelinek res = zerr_pool(pool_err, err_size, Z_POOL_CREATE);
41583247Sgjelinek goto done;
41593247Sgjelinek }
41603247Sgjelinek
41613247Sgjelinek /*
41623247Sgjelinek * Commit the dynamic configuration but not the pool configuration
41633247Sgjelinek * file.
41643247Sgjelinek */
41653247Sgjelinek if (pool_conf_commit(pconf, 1) != PO_SUCCESS)
41663247Sgjelinek res = zerr_pool(pool_err, err_size, Z_POOL);
41673247Sgjelinek
41683247Sgjelinek done:
41693247Sgjelinek (void) pool_conf_close(pconf);
41703247Sgjelinek return (res);
41713247Sgjelinek }
41723247Sgjelinek
41733247Sgjelinek static int
get_running_tmp_pset(pool_conf_t * pconf,pool_t * pool,pool_resource_t * pset,struct zone_psettab * pset_tab)41743247Sgjelinek get_running_tmp_pset(pool_conf_t *pconf, pool_t *pool, pool_resource_t *pset,
41753247Sgjelinek struct zone_psettab *pset_tab)
41763247Sgjelinek {
41773247Sgjelinek int nfound = 0;
41783247Sgjelinek pool_elem_t *pe;
41793247Sgjelinek pool_value_t *pv = pool_value_alloc();
41803247Sgjelinek uint64_t val_uint;
41813247Sgjelinek
41823247Sgjelinek if (pool != NULL) {
41833247Sgjelinek pe = pool_to_elem(pconf, pool);
41843247Sgjelinek if (pool_get_property(pconf, pe, "pool.importance", pv)
41853247Sgjelinek != POC_INVAL) {
41863247Sgjelinek int64_t val_int;
41873247Sgjelinek
41883247Sgjelinek (void) pool_value_get_int64(pv, &val_int);
41893247Sgjelinek (void) snprintf(pset_tab->zone_importance,
41903247Sgjelinek sizeof (pset_tab->zone_importance), "%d", val_int);
41913247Sgjelinek nfound++;
41923247Sgjelinek }
41933247Sgjelinek }
41943247Sgjelinek
41953247Sgjelinek if (pset != NULL) {
41963247Sgjelinek pe = pool_resource_to_elem(pconf, pset);
41973247Sgjelinek if (pool_get_property(pconf, pe, "pset.min", pv) != POC_INVAL) {
41983247Sgjelinek (void) pool_value_get_uint64(pv, &val_uint);
41993247Sgjelinek (void) snprintf(pset_tab->zone_ncpu_min,
42003247Sgjelinek sizeof (pset_tab->zone_ncpu_min), "%u", val_uint);
42013247Sgjelinek nfound++;
42023247Sgjelinek }
42033247Sgjelinek
42043247Sgjelinek if (pool_get_property(pconf, pe, "pset.max", pv) != POC_INVAL) {
42053247Sgjelinek (void) pool_value_get_uint64(pv, &val_uint);
42063247Sgjelinek (void) snprintf(pset_tab->zone_ncpu_max,
42073247Sgjelinek sizeof (pset_tab->zone_ncpu_max), "%u", val_uint);
42083247Sgjelinek nfound++;
42093247Sgjelinek }
42103247Sgjelinek }
42113247Sgjelinek
42123247Sgjelinek pool_value_free(pv);
42133247Sgjelinek
42143247Sgjelinek if (nfound == 3)
42153247Sgjelinek return (PO_SUCCESS);
42163247Sgjelinek
42173247Sgjelinek return (PO_FAIL);
42183247Sgjelinek }
42193247Sgjelinek
42203247Sgjelinek /*
42213247Sgjelinek * Determine if a tmp pool is configured and if so, if the configuration is
42223247Sgjelinek * still valid or if it has been changed since the tmp pool was created.
42233247Sgjelinek * If the tmp pool configuration is no longer valid, delete the tmp pool.
42243247Sgjelinek *
42253247Sgjelinek * Set *valid=B_TRUE if there is an existing, valid tmp pool configuration.
42263247Sgjelinek */
42273247Sgjelinek static int
verify_del_tmp_pool(pool_conf_t * pconf,char * tmp_name,char * pool_err,int err_size,struct zone_psettab * pset_tab,boolean_t * exists)42283247Sgjelinek verify_del_tmp_pool(pool_conf_t *pconf, char *tmp_name, char *pool_err,
42293247Sgjelinek int err_size, struct zone_psettab *pset_tab, boolean_t *exists)
42303247Sgjelinek {
42313247Sgjelinek int res = Z_OK;
42323247Sgjelinek pool_t *pool;
42333247Sgjelinek pool_resource_t *pset;
42343247Sgjelinek struct zone_psettab pset_current;
42353247Sgjelinek
42363247Sgjelinek *exists = B_FALSE;
42373247Sgjelinek
42383247Sgjelinek if (pool_conf_open(pconf, pool_dynamic_location(), PO_RDWR)
42393247Sgjelinek != PO_SUCCESS) {
42403247Sgjelinek res = zerr_pool(pool_err, err_size, Z_POOL);
42413247Sgjelinek return (res);
42423247Sgjelinek }
42433247Sgjelinek
42443247Sgjelinek pool = pool_get_pool(pconf, tmp_name);
42453247Sgjelinek pset = pool_get_resource(pconf, "pset", tmp_name);
42463247Sgjelinek
42473247Sgjelinek if (pool == NULL && pset == NULL) {
42483247Sgjelinek /* no tmp pool configured */
42493247Sgjelinek goto done;
42503247Sgjelinek }
42513247Sgjelinek
42523247Sgjelinek /*
42533247Sgjelinek * If an existing tmp pool for this zone is configured with the proper
42543247Sgjelinek * settings, then the tmp pool is valid.
42553247Sgjelinek */
42563247Sgjelinek if (get_running_tmp_pset(pconf, pool, pset, &pset_current)
42573247Sgjelinek == PO_SUCCESS &&
42583247Sgjelinek strcmp(pset_tab->zone_ncpu_min,
42593247Sgjelinek pset_current.zone_ncpu_min) == 0 &&
42603247Sgjelinek strcmp(pset_tab->zone_ncpu_max,
42613247Sgjelinek pset_current.zone_ncpu_max) == 0 &&
42623247Sgjelinek strcmp(pset_tab->zone_importance,
42633247Sgjelinek pset_current.zone_importance) == 0) {
42643247Sgjelinek *exists = B_TRUE;
42653247Sgjelinek
42663247Sgjelinek } else {
42673247Sgjelinek /*
42683247Sgjelinek * An out-of-date tmp pool configuration exists. Delete it
42693247Sgjelinek * so that we can create the correct tmp pool config.
42703247Sgjelinek */
42713247Sgjelinek if (pset != NULL &&
42723247Sgjelinek pool_resource_destroy(pconf, pset) != PO_SUCCESS) {
42733247Sgjelinek res = zerr_pool(pool_err, err_size, Z_POOL);
42743247Sgjelinek goto done;
42753247Sgjelinek }
42763247Sgjelinek
42773247Sgjelinek if (pool != NULL &&
42783247Sgjelinek pool_destroy(pconf, pool) != PO_SUCCESS) {
42793247Sgjelinek res = zerr_pool(pool_err, err_size, Z_POOL);
42803247Sgjelinek goto done;
42813247Sgjelinek }
42823247Sgjelinek
42833247Sgjelinek /* commit dynamic config */
42843247Sgjelinek if (pool_conf_commit(pconf, 0) != PO_SUCCESS)
42853247Sgjelinek res = zerr_pool(pool_err, err_size, Z_POOL);
42863247Sgjelinek }
42873247Sgjelinek
42883247Sgjelinek done:
42893247Sgjelinek (void) pool_conf_close(pconf);
42903247Sgjelinek
42913247Sgjelinek return (res);
42923247Sgjelinek }
42933247Sgjelinek
42943247Sgjelinek /*
42953247Sgjelinek * Destroy any existing tmp pool.
42963247Sgjelinek */
42973247Sgjelinek int
zonecfg_destroy_tmp_pool(char * zone_name,char * pool_err,int err_size)42983247Sgjelinek zonecfg_destroy_tmp_pool(char *zone_name, char *pool_err, int err_size)
42993247Sgjelinek {
43003247Sgjelinek int status;
43013247Sgjelinek int res = Z_OK;
43023247Sgjelinek pool_conf_t *pconf;
43033247Sgjelinek pool_t *pool;
43043247Sgjelinek pool_resource_t *pset;
43053247Sgjelinek char tmp_name[MAX_TMP_POOL_NAME];
43063247Sgjelinek
43073247Sgjelinek /* if pools not enabled then nothing to do */
43083247Sgjelinek if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
43093247Sgjelinek return (Z_OK);
43103247Sgjelinek
43113247Sgjelinek if ((pconf = pool_conf_alloc()) == NULL)
43123247Sgjelinek return (zerr_pool(pool_err, err_size, Z_POOL));
43133247Sgjelinek
43143247Sgjelinek (void) snprintf(tmp_name, sizeof (tmp_name), TMP_POOL_NAME, zone_name);
43153247Sgjelinek
43163247Sgjelinek if (pool_conf_open(pconf, pool_dynamic_location(), PO_RDWR)
43173247Sgjelinek != PO_SUCCESS) {
43183247Sgjelinek res = zerr_pool(pool_err, err_size, Z_POOL);
43193247Sgjelinek pool_conf_free(pconf);
43203247Sgjelinek return (res);
43213247Sgjelinek }
43223247Sgjelinek
43233247Sgjelinek pool = pool_get_pool(pconf, tmp_name);
43243247Sgjelinek pset = pool_get_resource(pconf, "pset", tmp_name);
43253247Sgjelinek
43263247Sgjelinek if (pool == NULL && pset == NULL) {
43273247Sgjelinek /* nothing to destroy, we're done */
43283247Sgjelinek goto done;
43293247Sgjelinek }
43303247Sgjelinek
43313247Sgjelinek if (pset != NULL && pool_resource_destroy(pconf, pset) != PO_SUCCESS) {
43323247Sgjelinek res = zerr_pool(pool_err, err_size, Z_POOL);
43333247Sgjelinek goto done;
43343247Sgjelinek }
43353247Sgjelinek
43363247Sgjelinek if (pool != NULL && pool_destroy(pconf, pool) != PO_SUCCESS) {
43373247Sgjelinek res = zerr_pool(pool_err, err_size, Z_POOL);
43383247Sgjelinek goto done;
43393247Sgjelinek }
43403247Sgjelinek
43413247Sgjelinek /* commit dynamic config */
43423247Sgjelinek if (pool_conf_commit(pconf, 0) != PO_SUCCESS)
43433247Sgjelinek res = zerr_pool(pool_err, err_size, Z_POOL);
43443247Sgjelinek
43453247Sgjelinek done:
43463247Sgjelinek (void) pool_conf_close(pconf);
43473247Sgjelinek pool_conf_free(pconf);
43483247Sgjelinek
43493247Sgjelinek return (res);
43503247Sgjelinek }
43513247Sgjelinek
43523247Sgjelinek /*
43533247Sgjelinek * Attempt to bind to a tmp pool for this zone. If there is no tmp pool
43543247Sgjelinek * configured, we just return Z_OK.
43553247Sgjelinek *
43563247Sgjelinek * We either attempt to create the tmp pool for this zone or rebind to an
43573247Sgjelinek * existing tmp pool for this zone.
43583247Sgjelinek *
43593247Sgjelinek * Rebinding is used when a zone with a tmp pool reboots so that we don't have
43603247Sgjelinek * to recreate the tmp pool. To do this we need to be sure we work correctly
43613247Sgjelinek * for the following cases:
43623247Sgjelinek *
43633247Sgjelinek * - there is an existing, properly configured tmp pool.
43643247Sgjelinek * - zonecfg added tmp pool after zone was booted, must now create.
43653247Sgjelinek * - zonecfg updated tmp pool config after zone was booted, in this case
43663247Sgjelinek * we destroy the old tmp pool and create a new one.
43673247Sgjelinek */
43683247Sgjelinek int
zonecfg_bind_tmp_pool(zone_dochandle_t handle,zoneid_t zoneid,char * pool_err,int err_size)43693247Sgjelinek zonecfg_bind_tmp_pool(zone_dochandle_t handle, zoneid_t zoneid, char *pool_err,
43703247Sgjelinek int err_size)
43713247Sgjelinek {
43723247Sgjelinek struct zone_psettab pset_tab;
43733247Sgjelinek int err;
43743247Sgjelinek int status;
43753247Sgjelinek pool_conf_t *pconf;
43763247Sgjelinek boolean_t exists;
43773247Sgjelinek char zone_name[ZONENAME_MAX];
43783247Sgjelinek char tmp_name[MAX_TMP_POOL_NAME];
43793247Sgjelinek
43803247Sgjelinek (void) getzonenamebyid(zoneid, zone_name, sizeof (zone_name));
43813247Sgjelinek
43823247Sgjelinek err = zonecfg_lookup_pset(handle, &pset_tab);
43833247Sgjelinek
43843247Sgjelinek /* if no temporary pool configured, we're done */
43853247Sgjelinek if (err == Z_NO_ENTRY)
43863247Sgjelinek return (Z_OK);
43873247Sgjelinek
43883247Sgjelinek /*
43893247Sgjelinek * importance might not have a value but we need to validate it here,
43903247Sgjelinek * so set the default.
43913247Sgjelinek */
43923247Sgjelinek if (pset_tab.zone_importance[0] == '\0')
43933247Sgjelinek (void) strlcpy(pset_tab.zone_importance, "1",
43943247Sgjelinek sizeof (pset_tab.zone_importance));
43953247Sgjelinek
43963247Sgjelinek /* if pools not enabled, enable them now */
43973247Sgjelinek if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) {
43983247Sgjelinek if (pool_set_status(POOL_ENABLED) != PO_SUCCESS)
43993247Sgjelinek return (Z_POOL_ENABLE);
44003247Sgjelinek }
44013247Sgjelinek
44023247Sgjelinek if ((pconf = pool_conf_alloc()) == NULL)
44033247Sgjelinek return (zerr_pool(pool_err, err_size, Z_POOL));
44043247Sgjelinek
44053247Sgjelinek (void) snprintf(tmp_name, sizeof (tmp_name), TMP_POOL_NAME, zone_name);
44063247Sgjelinek
44073247Sgjelinek /*
44083247Sgjelinek * Check if a valid tmp pool/pset already exists. If so, we just
44093247Sgjelinek * reuse it.
44103247Sgjelinek */
44113247Sgjelinek if ((err = verify_del_tmp_pool(pconf, tmp_name, pool_err, err_size,
44123247Sgjelinek &pset_tab, &exists)) != Z_OK) {
44133247Sgjelinek pool_conf_free(pconf);
44143247Sgjelinek return (err);
44153247Sgjelinek }
44163247Sgjelinek
44173247Sgjelinek if (!exists)
44183247Sgjelinek err = create_tmp_pool(pool_err, err_size, pconf, tmp_name,
44193247Sgjelinek &pset_tab);
44203247Sgjelinek
44213247Sgjelinek pool_conf_free(pconf);
44223247Sgjelinek
44233247Sgjelinek if (err != Z_OK)
44243247Sgjelinek return (err);
44253247Sgjelinek
44263247Sgjelinek /* Bind the zone to the pool. */
44273247Sgjelinek if (pool_set_binding(tmp_name, P_ZONEID, zoneid) != PO_SUCCESS)
44283247Sgjelinek return (zerr_pool(pool_err, err_size, Z_POOL_BIND));
44293247Sgjelinek
44303247Sgjelinek return (Z_OK);
44313247Sgjelinek }
44323247Sgjelinek
44333247Sgjelinek /*
44343247Sgjelinek * Attempt to bind to a permanent pool for this zone. If there is no
44353247Sgjelinek * permanent pool configured, we just return Z_OK.
44363247Sgjelinek */
44373247Sgjelinek int
zonecfg_bind_pool(zone_dochandle_t handle,zoneid_t zoneid,char * pool_err,int err_size)44383247Sgjelinek zonecfg_bind_pool(zone_dochandle_t handle, zoneid_t zoneid, char *pool_err,
44393247Sgjelinek int err_size)
44403247Sgjelinek {
44413247Sgjelinek pool_conf_t *poolconf;
44423247Sgjelinek pool_t *pool;
44433247Sgjelinek char poolname[MAXPATHLEN];
44443247Sgjelinek int status;
44453247Sgjelinek int error;
44463247Sgjelinek
44473247Sgjelinek /*
44483247Sgjelinek * Find the pool mentioned in the zone configuration, and bind to it.
44493247Sgjelinek */
44503247Sgjelinek error = zonecfg_get_pool(handle, poolname, sizeof (poolname));
44513247Sgjelinek if (error == Z_NO_ENTRY || (error == Z_OK && strlen(poolname) == 0)) {
44523247Sgjelinek /*
44533247Sgjelinek * The property is not set on the zone, so the pool
44543247Sgjelinek * should be bound to the default pool. But that's
44553247Sgjelinek * already done by the kernel, so we can just return.
44563247Sgjelinek */
44573247Sgjelinek return (Z_OK);
44583247Sgjelinek }
44593247Sgjelinek if (error != Z_OK) {
44603247Sgjelinek /*
44613247Sgjelinek * Not an error, even though it shouldn't be happening.
44623247Sgjelinek */
44633247Sgjelinek return (Z_OK);
44643247Sgjelinek }
44653247Sgjelinek /*
44663247Sgjelinek * Don't do anything if pools aren't enabled.
44673247Sgjelinek */
44683247Sgjelinek if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
44693247Sgjelinek return (Z_POOLS_NOT_ACTIVE);
44703247Sgjelinek
44713247Sgjelinek /*
44723247Sgjelinek * Try to provide a sane error message if the requested pool doesn't
44733247Sgjelinek * exist.
44743247Sgjelinek */
44753247Sgjelinek if ((poolconf = pool_conf_alloc()) == NULL)
44763247Sgjelinek return (zerr_pool(pool_err, err_size, Z_POOL));
44773247Sgjelinek
44783247Sgjelinek if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) !=
44793247Sgjelinek PO_SUCCESS) {
44803247Sgjelinek pool_conf_free(poolconf);
44813247Sgjelinek return (zerr_pool(pool_err, err_size, Z_POOL));
44823247Sgjelinek }
44833247Sgjelinek pool = pool_get_pool(poolconf, poolname);
44843247Sgjelinek (void) pool_conf_close(poolconf);
44853247Sgjelinek pool_conf_free(poolconf);
44863247Sgjelinek if (pool == NULL)
44873247Sgjelinek return (Z_NO_POOL);
44883247Sgjelinek
44893247Sgjelinek /*
44903247Sgjelinek * Bind the zone to the pool.
44913247Sgjelinek */
44923247Sgjelinek if (pool_set_binding(poolname, P_ZONEID, zoneid) != PO_SUCCESS) {
44933247Sgjelinek /* if bind fails, return poolname for the error msg */
44943247Sgjelinek (void) strlcpy(pool_err, poolname, err_size);
44953247Sgjelinek return (Z_POOL_BIND);
44963247Sgjelinek }
44973247Sgjelinek
44983247Sgjelinek return (Z_OK);
44993247Sgjelinek }
45003247Sgjelinek
450111878SVenu.Iyer@Sun.COM int
zonecfg_get_poolname(zone_dochandle_t handle,char * zone,char * pool,size_t poolsize)450211878SVenu.Iyer@Sun.COM zonecfg_get_poolname(zone_dochandle_t handle, char *zone, char *pool,
450311878SVenu.Iyer@Sun.COM size_t poolsize)
450411878SVenu.Iyer@Sun.COM {
450511878SVenu.Iyer@Sun.COM int err;
450611878SVenu.Iyer@Sun.COM struct zone_psettab pset_tab;
450711878SVenu.Iyer@Sun.COM
450811878SVenu.Iyer@Sun.COM err = zonecfg_lookup_pset(handle, &pset_tab);
450911878SVenu.Iyer@Sun.COM if ((err != Z_NO_ENTRY) && (err != Z_OK))
451011878SVenu.Iyer@Sun.COM return (err);
451111878SVenu.Iyer@Sun.COM
451211878SVenu.Iyer@Sun.COM /* pset was found so a temporary pool was created */
451311878SVenu.Iyer@Sun.COM if (err == Z_OK) {
451411878SVenu.Iyer@Sun.COM (void) snprintf(pool, poolsize, TMP_POOL_NAME, zone);
451511878SVenu.Iyer@Sun.COM return (Z_OK);
451611878SVenu.Iyer@Sun.COM }
451711878SVenu.Iyer@Sun.COM
451811878SVenu.Iyer@Sun.COM /* lookup the poolname in zonecfg */
451911878SVenu.Iyer@Sun.COM return (zonecfg_get_pool(handle, pool, poolsize));
452011878SVenu.Iyer@Sun.COM }
45213247Sgjelinek
45223247Sgjelinek static boolean_t
svc_enabled(char * svc_name)45233247Sgjelinek svc_enabled(char *svc_name)
45243247Sgjelinek {
45253247Sgjelinek scf_simple_prop_t *prop;
45263247Sgjelinek boolean_t found = B_FALSE;
45273247Sgjelinek
45283247Sgjelinek prop = scf_simple_prop_get(NULL, svc_name, SCF_PG_GENERAL,
45293247Sgjelinek SCF_PROPERTY_ENABLED);
45303247Sgjelinek
45313247Sgjelinek if (scf_simple_prop_numvalues(prop) == 1 &&
45323247Sgjelinek *scf_simple_prop_next_boolean(prop) != 0)
45333247Sgjelinek found = B_TRUE;
45343247Sgjelinek
45353247Sgjelinek scf_simple_prop_free(prop);
45363247Sgjelinek
45373247Sgjelinek return (found);
45383247Sgjelinek }
45393247Sgjelinek
45403247Sgjelinek /*
45413247Sgjelinek * If the zone has capped-memory, make sure the rcap service is enabled.
45423247Sgjelinek */
45433247Sgjelinek int
zonecfg_enable_rcapd(char * err,int size)45443247Sgjelinek zonecfg_enable_rcapd(char *err, int size)
45453247Sgjelinek {
45463247Sgjelinek if (!svc_enabled(RCAP_SERVICE) &&
45473247Sgjelinek smf_enable_instance(RCAP_SERVICE, 0) == -1) {
45483247Sgjelinek (void) strlcpy(err, scf_strerror(scf_error()), size);
45493247Sgjelinek return (Z_SYSTEM);
45503247Sgjelinek }
45513247Sgjelinek
45523247Sgjelinek return (Z_OK);
45533247Sgjelinek }
45543247Sgjelinek
45553247Sgjelinek /*
45563247Sgjelinek * Return true if pset has cpu range specified and poold is not enabled.
45573247Sgjelinek */
45583247Sgjelinek boolean_t
zonecfg_warn_poold(zone_dochandle_t handle)45593247Sgjelinek zonecfg_warn_poold(zone_dochandle_t handle)
45603247Sgjelinek {
45613247Sgjelinek struct zone_psettab pset_tab;
45623247Sgjelinek int min, max;
45633247Sgjelinek int err;
45643247Sgjelinek
45653247Sgjelinek err = zonecfg_lookup_pset(handle, &pset_tab);
45663247Sgjelinek
45673247Sgjelinek /* if no temporary pool configured, we're done */
45683247Sgjelinek if (err == Z_NO_ENTRY)
45693247Sgjelinek return (B_FALSE);
45703247Sgjelinek
45713247Sgjelinek min = atoi(pset_tab.zone_ncpu_min);
45723247Sgjelinek max = atoi(pset_tab.zone_ncpu_max);
45733247Sgjelinek
45743247Sgjelinek /* range not specified, no need for poold */
45753247Sgjelinek if (min == max)
45763247Sgjelinek return (B_FALSE);
45773247Sgjelinek
45783247Sgjelinek /* we have a range, check if poold service is enabled */
45793247Sgjelinek if (svc_enabled(POOLD_SERVICE))
45803247Sgjelinek return (B_FALSE);
45813247Sgjelinek
45823247Sgjelinek return (B_TRUE);
45833247Sgjelinek }
45843247Sgjelinek
458511435SJordan.Vaughan@Sun.com /*
458611435SJordan.Vaughan@Sun.com * Retrieve the specified pool's thread scheduling class. 'poolname' must
458711435SJordan.Vaughan@Sun.com * refer to the name of a configured resource pool. The thread scheduling
458811435SJordan.Vaughan@Sun.com * class specified by the pool will be stored in the buffer to which 'class'
458911435SJordan.Vaughan@Sun.com * points. 'clsize' is the byte size of the buffer to which 'class' points.
459011435SJordan.Vaughan@Sun.com *
459111435SJordan.Vaughan@Sun.com * This function returns Z_OK if it successfully stored the specified pool's
459211435SJordan.Vaughan@Sun.com * thread scheduling class into the buffer to which 'class' points. It returns
459311435SJordan.Vaughan@Sun.com * Z_NO_POOL if resource pools are not enabled, the function is unable to
459411435SJordan.Vaughan@Sun.com * access the system's resource pools configuration, or the specified pool
459511435SJordan.Vaughan@Sun.com * does not exist. The function returns Z_TOO_BIG if the buffer to which
459611435SJordan.Vaughan@Sun.com * 'class' points is not large enough to contain the thread scheduling class'
459711435SJordan.Vaughan@Sun.com * name. The function returns Z_NO_ENTRY if the pool does not specify a thread
459811435SJordan.Vaughan@Sun.com * scheduling class.
459911435SJordan.Vaughan@Sun.com */
46003247Sgjelinek static int
get_pool_sched_class(char * poolname,char * class,int clsize)46013247Sgjelinek get_pool_sched_class(char *poolname, char *class, int clsize)
46023247Sgjelinek {
46033247Sgjelinek int status;
46043247Sgjelinek pool_conf_t *poolconf;
46053247Sgjelinek pool_t *pool;
46063247Sgjelinek pool_elem_t *pe;
46073247Sgjelinek pool_value_t *pv = pool_value_alloc();
46083247Sgjelinek const char *sched_str;
46093247Sgjelinek
46103247Sgjelinek if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED)
46113247Sgjelinek return (Z_NO_POOL);
46123247Sgjelinek
46133247Sgjelinek if ((poolconf = pool_conf_alloc()) == NULL)
46143247Sgjelinek return (Z_NO_POOL);
46153247Sgjelinek
46163247Sgjelinek if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) !=
46173247Sgjelinek PO_SUCCESS) {
46183247Sgjelinek pool_conf_free(poolconf);
46193247Sgjelinek return (Z_NO_POOL);
46203247Sgjelinek }
46213247Sgjelinek
46223247Sgjelinek if ((pool = pool_get_pool(poolconf, poolname)) == NULL) {
46233247Sgjelinek (void) pool_conf_close(poolconf);
46243247Sgjelinek pool_conf_free(poolconf);
46253247Sgjelinek return (Z_NO_POOL);
46263247Sgjelinek }
46273247Sgjelinek
46283247Sgjelinek pe = pool_to_elem(poolconf, pool);
462911435SJordan.Vaughan@Sun.com if (pool_get_property(poolconf, pe, "pool.scheduler", pv) !=
463011435SJordan.Vaughan@Sun.com POC_STRING) {
463111435SJordan.Vaughan@Sun.com (void) pool_conf_close(poolconf);
463211435SJordan.Vaughan@Sun.com pool_conf_free(poolconf);
463311435SJordan.Vaughan@Sun.com return (Z_NO_ENTRY);
463411435SJordan.Vaughan@Sun.com }
463511435SJordan.Vaughan@Sun.com (void) pool_value_get_string(pv, &sched_str);
46363247Sgjelinek (void) pool_conf_close(poolconf);
46373247Sgjelinek pool_conf_free(poolconf);
463811435SJordan.Vaughan@Sun.com if (strlcpy(class, sched_str, clsize) >= clsize)
463911435SJordan.Vaughan@Sun.com return (Z_TOO_BIG);
46403247Sgjelinek return (Z_OK);
46413247Sgjelinek }
46423247Sgjelinek
46433247Sgjelinek /*
46443247Sgjelinek * Get the default scheduling class for the zone. This will either be the
46453247Sgjelinek * class set on the zone's pool or the system default scheduling class.
46463247Sgjelinek */
46473247Sgjelinek int
zonecfg_get_dflt_sched_class(zone_dochandle_t handle,char * class,int clsize)46483247Sgjelinek zonecfg_get_dflt_sched_class(zone_dochandle_t handle, char *class, int clsize)
46493247Sgjelinek {
46503247Sgjelinek char poolname[MAXPATHLEN];
46513247Sgjelinek
46523247Sgjelinek if (zonecfg_get_pool(handle, poolname, sizeof (poolname)) == Z_OK) {
46533247Sgjelinek /* check if the zone's pool specified a sched class */
46543247Sgjelinek if (get_pool_sched_class(poolname, class, clsize) == Z_OK)
46553247Sgjelinek return (Z_OK);
46563247Sgjelinek }
46573247Sgjelinek
46583247Sgjelinek if (priocntl(0, 0, PC_GETDFLCL, class, (uint64_t)clsize) == -1)
46593247Sgjelinek return (Z_TOO_BIG);
46603247Sgjelinek
46613247Sgjelinek return (Z_OK);
46623247Sgjelinek }
46633247Sgjelinek
46640Sstevel@tonic-gate int
zonecfg_setfsent(zone_dochandle_t handle)46650Sstevel@tonic-gate zonecfg_setfsent(zone_dochandle_t handle)
46660Sstevel@tonic-gate {
46670Sstevel@tonic-gate return (zonecfg_setent(handle));
46680Sstevel@tonic-gate }
46690Sstevel@tonic-gate
46700Sstevel@tonic-gate int
zonecfg_getfsent(zone_dochandle_t handle,struct zone_fstab * tabptr)46710Sstevel@tonic-gate zonecfg_getfsent(zone_dochandle_t handle, struct zone_fstab *tabptr)
46720Sstevel@tonic-gate {
46730Sstevel@tonic-gate xmlNodePtr cur, options;
46740Sstevel@tonic-gate char options_str[MAX_MNTOPT_STR];
46750Sstevel@tonic-gate int err;
46760Sstevel@tonic-gate
46770Sstevel@tonic-gate if (handle == NULL)
46780Sstevel@tonic-gate return (Z_INVAL);
46790Sstevel@tonic-gate
46800Sstevel@tonic-gate if ((cur = handle->zone_dh_cur) == NULL)
46810Sstevel@tonic-gate return (Z_NO_ENTRY);
46820Sstevel@tonic-gate
46830Sstevel@tonic-gate for (; cur != NULL; cur = cur->next)
46840Sstevel@tonic-gate if (!xmlStrcmp(cur->name, DTD_ELEM_FS))
46850Sstevel@tonic-gate break;
46860Sstevel@tonic-gate if (cur == NULL) {
46870Sstevel@tonic-gate handle->zone_dh_cur = handle->zone_dh_top;
46880Sstevel@tonic-gate return (Z_NO_ENTRY);
46890Sstevel@tonic-gate }
46900Sstevel@tonic-gate
46910Sstevel@tonic-gate if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
46920Sstevel@tonic-gate sizeof (tabptr->zone_fs_special))) != Z_OK) {
46930Sstevel@tonic-gate handle->zone_dh_cur = handle->zone_dh_top;
46940Sstevel@tonic-gate return (err);
46950Sstevel@tonic-gate }
46960Sstevel@tonic-gate
46970Sstevel@tonic-gate if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
46980Sstevel@tonic-gate sizeof (tabptr->zone_fs_raw))) != Z_OK) {
46990Sstevel@tonic-gate handle->zone_dh_cur = handle->zone_dh_top;
47000Sstevel@tonic-gate return (err);
47010Sstevel@tonic-gate }
47020Sstevel@tonic-gate
47030Sstevel@tonic-gate if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
47040Sstevel@tonic-gate sizeof (tabptr->zone_fs_dir))) != Z_OK) {
47050Sstevel@tonic-gate handle->zone_dh_cur = handle->zone_dh_top;
47060Sstevel@tonic-gate return (err);
47070Sstevel@tonic-gate }
47080Sstevel@tonic-gate
47090Sstevel@tonic-gate if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
47100Sstevel@tonic-gate sizeof (tabptr->zone_fs_type))) != Z_OK) {
47110Sstevel@tonic-gate handle->zone_dh_cur = handle->zone_dh_top;
47120Sstevel@tonic-gate return (err);
47130Sstevel@tonic-gate }
47140Sstevel@tonic-gate
47150Sstevel@tonic-gate /* OK for options to be NULL */
47160Sstevel@tonic-gate tabptr->zone_fs_options = NULL;
47170Sstevel@tonic-gate for (options = cur->xmlChildrenNode; options != NULL;
47180Sstevel@tonic-gate options = options->next) {
47190Sstevel@tonic-gate if (fetchprop(options, DTD_ATTR_NAME, options_str,
47200Sstevel@tonic-gate sizeof (options_str)) != Z_OK)
47210Sstevel@tonic-gate break;
47220Sstevel@tonic-gate if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
47230Sstevel@tonic-gate break;
47240Sstevel@tonic-gate }
47250Sstevel@tonic-gate
47260Sstevel@tonic-gate handle->zone_dh_cur = cur->next;
47270Sstevel@tonic-gate return (Z_OK);
47280Sstevel@tonic-gate }
47290Sstevel@tonic-gate
47300Sstevel@tonic-gate int
zonecfg_endfsent(zone_dochandle_t handle)47310Sstevel@tonic-gate zonecfg_endfsent(zone_dochandle_t handle)
47320Sstevel@tonic-gate {
47330Sstevel@tonic-gate return (zonecfg_endent(handle));
47340Sstevel@tonic-gate }
47350Sstevel@tonic-gate
47360Sstevel@tonic-gate int
zonecfg_setnwifent(zone_dochandle_t handle)47370Sstevel@tonic-gate zonecfg_setnwifent(zone_dochandle_t handle)
47380Sstevel@tonic-gate {
47390Sstevel@tonic-gate return (zonecfg_setent(handle));
47400Sstevel@tonic-gate }
47410Sstevel@tonic-gate
47420Sstevel@tonic-gate int
zonecfg_getnwifent(zone_dochandle_t handle,struct zone_nwiftab * tabptr)47430Sstevel@tonic-gate zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
47440Sstevel@tonic-gate {
47450Sstevel@tonic-gate xmlNodePtr cur;
47460Sstevel@tonic-gate int err;
47470Sstevel@tonic-gate
47480Sstevel@tonic-gate if (handle == NULL)
47490Sstevel@tonic-gate return (Z_INVAL);
47500Sstevel@tonic-gate
47510Sstevel@tonic-gate if ((cur = handle->zone_dh_cur) == NULL)
47520Sstevel@tonic-gate return (Z_NO_ENTRY);
47530Sstevel@tonic-gate
47540Sstevel@tonic-gate for (; cur != NULL; cur = cur->next)
47550Sstevel@tonic-gate if (!xmlStrcmp(cur->name, DTD_ELEM_NET))
47560Sstevel@tonic-gate break;
47570Sstevel@tonic-gate if (cur == NULL) {
47580Sstevel@tonic-gate handle->zone_dh_cur = handle->zone_dh_top;
47590Sstevel@tonic-gate return (Z_NO_ENTRY);
47600Sstevel@tonic-gate }
47610Sstevel@tonic-gate
47620Sstevel@tonic-gate if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
47630Sstevel@tonic-gate sizeof (tabptr->zone_nwif_address))) != Z_OK) {
47640Sstevel@tonic-gate handle->zone_dh_cur = handle->zone_dh_top;
47650Sstevel@tonic-gate return (err);
47660Sstevel@tonic-gate }
47670Sstevel@tonic-gate
476812748SSowmini.Varadhan@oracle.COM if ((err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
476912748SSowmini.Varadhan@oracle.COM tabptr->zone_nwif_allowed_address,
477012748SSowmini.Varadhan@oracle.COM sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK) {
477112748SSowmini.Varadhan@oracle.COM handle->zone_dh_cur = handle->zone_dh_top;
477212748SSowmini.Varadhan@oracle.COM return (err);
477312748SSowmini.Varadhan@oracle.COM }
477412748SSowmini.Varadhan@oracle.COM
47750Sstevel@tonic-gate if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
47760Sstevel@tonic-gate sizeof (tabptr->zone_nwif_physical))) != Z_OK) {
47770Sstevel@tonic-gate handle->zone_dh_cur = handle->zone_dh_top;
47780Sstevel@tonic-gate return (err);
47790Sstevel@tonic-gate }
47800Sstevel@tonic-gate
47816076Sgfaden if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
47826076Sgfaden tabptr->zone_nwif_defrouter,
47836076Sgfaden sizeof (tabptr->zone_nwif_defrouter))) != Z_OK) {
47846076Sgfaden handle->zone_dh_cur = handle->zone_dh_top;
47856076Sgfaden return (err);
47866076Sgfaden }
47876076Sgfaden
47880Sstevel@tonic-gate handle->zone_dh_cur = cur->next;
47890Sstevel@tonic-gate return (Z_OK);
47900Sstevel@tonic-gate }
47910Sstevel@tonic-gate
47920Sstevel@tonic-gate int
zonecfg_endnwifent(zone_dochandle_t handle)47930Sstevel@tonic-gate zonecfg_endnwifent(zone_dochandle_t handle)
47940Sstevel@tonic-gate {
47950Sstevel@tonic-gate return (zonecfg_endent(handle));
47960Sstevel@tonic-gate }
47970Sstevel@tonic-gate
47980Sstevel@tonic-gate int
zonecfg_setdevent(zone_dochandle_t handle)47990Sstevel@tonic-gate zonecfg_setdevent(zone_dochandle_t handle)
48000Sstevel@tonic-gate {
48010Sstevel@tonic-gate return (zonecfg_setent(handle));
48020Sstevel@tonic-gate }
48030Sstevel@tonic-gate
48040Sstevel@tonic-gate int
zonecfg_getdevent(zone_dochandle_t handle,struct zone_devtab * tabptr)48050Sstevel@tonic-gate zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr)
48060Sstevel@tonic-gate {
48070Sstevel@tonic-gate xmlNodePtr cur;
48080Sstevel@tonic-gate int err;
48090Sstevel@tonic-gate
48100Sstevel@tonic-gate if (handle == NULL)
48110Sstevel@tonic-gate return (Z_INVAL);
48120Sstevel@tonic-gate
48130Sstevel@tonic-gate if ((cur = handle->zone_dh_cur) == NULL)
48140Sstevel@tonic-gate return (Z_NO_ENTRY);
48150Sstevel@tonic-gate
48160Sstevel@tonic-gate for (; cur != NULL; cur = cur->next)
48170Sstevel@tonic-gate if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
48180Sstevel@tonic-gate break;
48190Sstevel@tonic-gate if (cur == NULL) {
48200Sstevel@tonic-gate handle->zone_dh_cur = handle->zone_dh_top;
48210Sstevel@tonic-gate return (Z_NO_ENTRY);
48220Sstevel@tonic-gate }
48230Sstevel@tonic-gate
48240Sstevel@tonic-gate if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
48250Sstevel@tonic-gate sizeof (tabptr->zone_dev_match))) != Z_OK) {
48260Sstevel@tonic-gate handle->zone_dh_cur = handle->zone_dh_top;
48270Sstevel@tonic-gate return (err);
48280Sstevel@tonic-gate }
48290Sstevel@tonic-gate
48300Sstevel@tonic-gate handle->zone_dh_cur = cur->next;
48310Sstevel@tonic-gate return (Z_OK);
48320Sstevel@tonic-gate }
48330Sstevel@tonic-gate
48340Sstevel@tonic-gate int
zonecfg_enddevent(zone_dochandle_t handle)48350Sstevel@tonic-gate zonecfg_enddevent(zone_dochandle_t handle)
48360Sstevel@tonic-gate {
48370Sstevel@tonic-gate return (zonecfg_endent(handle));
48380Sstevel@tonic-gate }
48390Sstevel@tonic-gate
48400Sstevel@tonic-gate int
zonecfg_setrctlent(zone_dochandle_t handle)48410Sstevel@tonic-gate zonecfg_setrctlent(zone_dochandle_t handle)
48420Sstevel@tonic-gate {
48430Sstevel@tonic-gate return (zonecfg_setent(handle));
48440Sstevel@tonic-gate }
48450Sstevel@tonic-gate
48460Sstevel@tonic-gate int
zonecfg_getrctlent(zone_dochandle_t handle,struct zone_rctltab * tabptr)48470Sstevel@tonic-gate zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr)
48480Sstevel@tonic-gate {
48490Sstevel@tonic-gate xmlNodePtr cur, val;
48500Sstevel@tonic-gate struct zone_rctlvaltab *valptr;
48510Sstevel@tonic-gate int err;
48520Sstevel@tonic-gate
48530Sstevel@tonic-gate if (handle == NULL)
48540Sstevel@tonic-gate return (Z_INVAL);
48550Sstevel@tonic-gate
48560Sstevel@tonic-gate if ((cur = handle->zone_dh_cur) == NULL)
48570Sstevel@tonic-gate return (Z_NO_ENTRY);
48580Sstevel@tonic-gate
48590Sstevel@tonic-gate for (; cur != NULL; cur = cur->next)
48600Sstevel@tonic-gate if (!xmlStrcmp(cur->name, DTD_ELEM_RCTL))
48610Sstevel@tonic-gate break;
48620Sstevel@tonic-gate if (cur == NULL) {
48630Sstevel@tonic-gate handle->zone_dh_cur = handle->zone_dh_top;
48640Sstevel@tonic-gate return (Z_NO_ENTRY);
48650Sstevel@tonic-gate }
48660Sstevel@tonic-gate
48670Sstevel@tonic-gate if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_rctl_name,
48680Sstevel@tonic-gate sizeof (tabptr->zone_rctl_name))) != Z_OK) {
48690Sstevel@tonic-gate handle->zone_dh_cur = handle->zone_dh_top;
48700Sstevel@tonic-gate return (err);
48710Sstevel@tonic-gate }
48720Sstevel@tonic-gate
48730Sstevel@tonic-gate tabptr->zone_rctl_valptr = NULL;
48740Sstevel@tonic-gate for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
48750Sstevel@tonic-gate valptr = (struct zone_rctlvaltab *)malloc(
48760Sstevel@tonic-gate sizeof (struct zone_rctlvaltab));
48770Sstevel@tonic-gate if (valptr == NULL)
48780Sstevel@tonic-gate return (Z_NOMEM);
48790Sstevel@tonic-gate if (fetchprop(val, DTD_ATTR_PRIV, valptr->zone_rctlval_priv,
48800Sstevel@tonic-gate sizeof (valptr->zone_rctlval_priv)) != Z_OK)
48810Sstevel@tonic-gate break;
48820Sstevel@tonic-gate if (fetchprop(val, DTD_ATTR_LIMIT, valptr->zone_rctlval_limit,
48830Sstevel@tonic-gate sizeof (valptr->zone_rctlval_limit)) != Z_OK)
48840Sstevel@tonic-gate break;
48850Sstevel@tonic-gate if (fetchprop(val, DTD_ATTR_ACTION, valptr->zone_rctlval_action,
48860Sstevel@tonic-gate sizeof (valptr->zone_rctlval_action)) != Z_OK)
48870Sstevel@tonic-gate break;
48880Sstevel@tonic-gate if (zonecfg_add_rctl_value(tabptr, valptr) != Z_OK)
48890Sstevel@tonic-gate break;
48900Sstevel@tonic-gate }
48910Sstevel@tonic-gate
48920Sstevel@tonic-gate handle->zone_dh_cur = cur->next;
48930Sstevel@tonic-gate return (Z_OK);
48940Sstevel@tonic-gate }
48950Sstevel@tonic-gate
48960Sstevel@tonic-gate int
zonecfg_endrctlent(zone_dochandle_t handle)48970Sstevel@tonic-gate zonecfg_endrctlent(zone_dochandle_t handle)
48980Sstevel@tonic-gate {
48990Sstevel@tonic-gate return (zonecfg_endent(handle));
49000Sstevel@tonic-gate }
49010Sstevel@tonic-gate
49020Sstevel@tonic-gate int
zonecfg_setattrent(zone_dochandle_t handle)49030Sstevel@tonic-gate zonecfg_setattrent(zone_dochandle_t handle)
49040Sstevel@tonic-gate {
49050Sstevel@tonic-gate return (zonecfg_setent(handle));
49060Sstevel@tonic-gate }
49070Sstevel@tonic-gate
49080Sstevel@tonic-gate int
zonecfg_getattrent(zone_dochandle_t handle,struct zone_attrtab * tabptr)49090Sstevel@tonic-gate zonecfg_getattrent(zone_dochandle_t handle, struct zone_attrtab *tabptr)
49100Sstevel@tonic-gate {
49110Sstevel@tonic-gate xmlNodePtr cur;
49120Sstevel@tonic-gate int err;
49130Sstevel@tonic-gate
49140Sstevel@tonic-gate if (handle == NULL)
49150Sstevel@tonic-gate return (Z_INVAL);
49160Sstevel@tonic-gate
49170Sstevel@tonic-gate if ((cur = handle->zone_dh_cur) == NULL)
49180Sstevel@tonic-gate return (Z_NO_ENTRY);
49190Sstevel@tonic-gate
49200Sstevel@tonic-gate for (; cur != NULL; cur = cur->next)
49210Sstevel@tonic-gate if (!xmlStrcmp(cur->name, DTD_ELEM_ATTR))
49220Sstevel@tonic-gate break;
49230Sstevel@tonic-gate if (cur == NULL) {
49240Sstevel@tonic-gate handle->zone_dh_cur = handle->zone_dh_top;
49250Sstevel@tonic-gate return (Z_NO_ENTRY);
49260Sstevel@tonic-gate }
49270Sstevel@tonic-gate
49280Sstevel@tonic-gate if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
49290Sstevel@tonic-gate sizeof (tabptr->zone_attr_name))) != Z_OK) {
49300Sstevel@tonic-gate handle->zone_dh_cur = handle->zone_dh_top;
49310Sstevel@tonic-gate return (err);
49320Sstevel@tonic-gate }
49330Sstevel@tonic-gate
49340Sstevel@tonic-gate if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
49350Sstevel@tonic-gate sizeof (tabptr->zone_attr_type))) != Z_OK) {
49360Sstevel@tonic-gate handle->zone_dh_cur = handle->zone_dh_top;
49370Sstevel@tonic-gate return (err);
49380Sstevel@tonic-gate }
49390Sstevel@tonic-gate
49400Sstevel@tonic-gate if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
49410Sstevel@tonic-gate sizeof (tabptr->zone_attr_value))) != Z_OK) {
49420Sstevel@tonic-gate handle->zone_dh_cur = handle->zone_dh_top;
49430Sstevel@tonic-gate return (err);
49440Sstevel@tonic-gate }
49450Sstevel@tonic-gate
49460Sstevel@tonic-gate handle->zone_dh_cur = cur->next;
49470Sstevel@tonic-gate return (Z_OK);
49480Sstevel@tonic-gate }
49490Sstevel@tonic-gate
49500Sstevel@tonic-gate int
zonecfg_endattrent(zone_dochandle_t handle)49510Sstevel@tonic-gate zonecfg_endattrent(zone_dochandle_t handle)
49520Sstevel@tonic-gate {
49530Sstevel@tonic-gate return (zonecfg_endent(handle));
49540Sstevel@tonic-gate }
49550Sstevel@tonic-gate
495612578SGlenn.Faden@Sun.COM int
zonecfg_setadminent(zone_dochandle_t handle)495712578SGlenn.Faden@Sun.COM zonecfg_setadminent(zone_dochandle_t handle)
495812578SGlenn.Faden@Sun.COM {
495912578SGlenn.Faden@Sun.COM return (zonecfg_setent(handle));
496012578SGlenn.Faden@Sun.COM }
496112578SGlenn.Faden@Sun.COM
496212578SGlenn.Faden@Sun.COM int
zonecfg_getadminent(zone_dochandle_t handle,struct zone_admintab * tabptr)496312578SGlenn.Faden@Sun.COM zonecfg_getadminent(zone_dochandle_t handle, struct zone_admintab *tabptr)
496412578SGlenn.Faden@Sun.COM {
496512578SGlenn.Faden@Sun.COM xmlNodePtr cur;
496612578SGlenn.Faden@Sun.COM int err;
496712578SGlenn.Faden@Sun.COM
496812578SGlenn.Faden@Sun.COM if (handle == NULL)
496912578SGlenn.Faden@Sun.COM return (Z_INVAL);
497012578SGlenn.Faden@Sun.COM
497112578SGlenn.Faden@Sun.COM if ((cur = handle->zone_dh_cur) == NULL)
497212578SGlenn.Faden@Sun.COM return (Z_NO_ENTRY);
497312578SGlenn.Faden@Sun.COM
497412578SGlenn.Faden@Sun.COM for (; cur != NULL; cur = cur->next)
497512578SGlenn.Faden@Sun.COM if (!xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
497612578SGlenn.Faden@Sun.COM break;
497712578SGlenn.Faden@Sun.COM if (cur == NULL) {
497812578SGlenn.Faden@Sun.COM handle->zone_dh_cur = handle->zone_dh_top;
497912578SGlenn.Faden@Sun.COM return (Z_NO_ENTRY);
498012578SGlenn.Faden@Sun.COM }
498112578SGlenn.Faden@Sun.COM
498212578SGlenn.Faden@Sun.COM if ((err = fetchprop(cur, DTD_ATTR_USER, tabptr->zone_admin_user,
498312578SGlenn.Faden@Sun.COM sizeof (tabptr->zone_admin_user))) != Z_OK) {
498412578SGlenn.Faden@Sun.COM handle->zone_dh_cur = handle->zone_dh_top;
498512578SGlenn.Faden@Sun.COM return (err);
498612578SGlenn.Faden@Sun.COM }
498712578SGlenn.Faden@Sun.COM
498812578SGlenn.Faden@Sun.COM
498912578SGlenn.Faden@Sun.COM if ((err = fetchprop(cur, DTD_ATTR_AUTHS, tabptr->zone_admin_auths,
499012578SGlenn.Faden@Sun.COM sizeof (tabptr->zone_admin_auths))) != Z_OK) {
499112578SGlenn.Faden@Sun.COM handle->zone_dh_cur = handle->zone_dh_top;
499212578SGlenn.Faden@Sun.COM return (err);
499312578SGlenn.Faden@Sun.COM }
499412578SGlenn.Faden@Sun.COM
499512578SGlenn.Faden@Sun.COM handle->zone_dh_cur = cur->next;
499612578SGlenn.Faden@Sun.COM return (Z_OK);
499712578SGlenn.Faden@Sun.COM }
499812578SGlenn.Faden@Sun.COM
499912578SGlenn.Faden@Sun.COM int
zonecfg_endadminent(zone_dochandle_t handle)500012578SGlenn.Faden@Sun.COM zonecfg_endadminent(zone_dochandle_t handle)
500112578SGlenn.Faden@Sun.COM {
500212578SGlenn.Faden@Sun.COM return (zonecfg_endent(handle));
500312578SGlenn.Faden@Sun.COM }
500412578SGlenn.Faden@Sun.COM
50051645Scomay /*
50061645Scomay * The privileges available on the system and described in privileges(5)
50072712Snn35248 * fall into four categories with respect to non-global zones:
50082712Snn35248 *
50092712Snn35248 * Default set of privileges considered safe for all non-global
50102712Snn35248 * zones. These privileges are "safe" in the sense that a
50112712Snn35248 * privileged process in the zone cannot affect processes in any
50122712Snn35248 * other zone on the system.
50132712Snn35248 *
50142712Snn35248 * Set of privileges not currently permitted within a non-global
50152712Snn35248 * zone. These privileges are considered by default, "unsafe,"
50162712Snn35248 * and include ones which affect global resources (such as the
50172712Snn35248 * system clock or physical memory) or are overly broad and cover
50182712Snn35248 * more than one mechanism in the system. In other cases, there
50192712Snn35248 * has not been sufficient virtualization in the parts of the
50202712Snn35248 * system the privilege covers to allow its use within a
50212712Snn35248 * non-global zone.
50222712Snn35248 *
50232712Snn35248 * Set of privileges required in order to get a zone booted and
50242712Snn35248 * init(1M) started. These cannot be removed from the zone's
50252712Snn35248 * privilege set.
50262712Snn35248 *
50272712Snn35248 * All other privileges are optional and are potentially useful for
50281645Scomay * processes executing inside a non-global zone.
50291645Scomay *
50301645Scomay * When privileges are added to the system, a determination needs to be
50311645Scomay * made as to which category the privilege belongs to. Ideally,
50321645Scomay * privileges should be fine-grained enough and the mechanisms they cover
50331645Scomay * virtualized enough so that they can be made available to non-global
50341645Scomay * zones.
50351645Scomay */
50361645Scomay
50371645Scomay /*
50381645Scomay * Define some of the tokens that priv_str_to_set(3C) recognizes. Since
50391645Scomay * the privilege string separator can be any character, although it is
50401645Scomay * usually a comma character, define these here as well in the event that
50411645Scomay * they change or are augmented in the future.
50421645Scomay */
50431645Scomay #define BASIC_TOKEN "basic"
50441645Scomay #define DEFAULT_TOKEN "default"
50451645Scomay #define ZONE_TOKEN "zone"
50461645Scomay #define TOKEN_PRIV_CHAR ','
50471645Scomay #define TOKEN_PRIV_STR ","
50481645Scomay
50492712Snn35248 typedef struct priv_node {
50502712Snn35248 struct priv_node *pn_next; /* Next privilege */
50512712Snn35248 char *pn_priv; /* Privileges name */
50522712Snn35248 } priv_node_t;
50532712Snn35248
50542712Snn35248 /* Privileges lists can differ across brands */
50552712Snn35248 typedef struct priv_lists {
50562712Snn35248 /* Privileges considered safe for all non-global zones of a brand */
50572712Snn35248 struct priv_node *pl_default;
50582712Snn35248
50592712Snn35248 /* Privileges not permitted for all non-global zones of a brand */
50602712Snn35248 struct priv_node *pl_prohibited;
50612712Snn35248
50622712Snn35248 /* Privileges required for all non-global zones of a brand */
50632712Snn35248 struct priv_node *pl_required;
50643673Sdh155122
50653673Sdh155122 /*
50663673Sdh155122 * ip-type of the zone these privileges lists apply to.
50673673Sdh155122 * It is used to pass ip-type to the callback function,
50683673Sdh155122 * priv_lists_cb, which has no way of getting the ip-type.
50693673Sdh155122 */
50703673Sdh155122 const char *pl_iptype;
50712712Snn35248 } priv_lists_t;
50722712Snn35248
50732712Snn35248 static int
priv_lists_cb(void * data,priv_iter_t * priv_iter)50743673Sdh155122 priv_lists_cb(void *data, priv_iter_t *priv_iter)
50752712Snn35248 {
50762712Snn35248 priv_lists_t *plp = (priv_lists_t *)data;
50772712Snn35248 priv_node_t *pnp;
50782712Snn35248
50793673Sdh155122 /* Skip this privilege if ip-type does not match */
50803673Sdh155122 if ((strcmp(priv_iter->pi_iptype, "all") != 0) &&
50813673Sdh155122 (strcmp(priv_iter->pi_iptype, plp->pl_iptype) != 0))
50823673Sdh155122 return (0);
50833673Sdh155122
50842712Snn35248 /* Allocate a new priv list node. */
50852712Snn35248 if ((pnp = malloc(sizeof (*pnp))) == NULL)
50862712Snn35248 return (-1);
50873673Sdh155122 if ((pnp->pn_priv = strdup(priv_iter->pi_name)) == NULL) {
50882712Snn35248 free(pnp);
50892712Snn35248 return (-1);
50902712Snn35248 }
50912712Snn35248
50922712Snn35248 /* Insert the new priv list node into the right list */
50933673Sdh155122 if (strcmp(priv_iter->pi_set, "default") == 0) {
50942712Snn35248 pnp->pn_next = plp->pl_default;
50952712Snn35248 plp->pl_default = pnp;
50963673Sdh155122 } else if (strcmp(priv_iter->pi_set, "prohibited") == 0) {
50972712Snn35248 pnp->pn_next = plp->pl_prohibited;
50982712Snn35248 plp->pl_prohibited = pnp;
50993673Sdh155122 } else if (strcmp(priv_iter->pi_set, "required") == 0) {
51002712Snn35248 pnp->pn_next = plp->pl_required;
51012712Snn35248 plp->pl_required = pnp;
51022712Snn35248 } else {
51032712Snn35248 free(pnp->pn_priv);
51042712Snn35248 free(pnp);
51052712Snn35248 return (-1);
51062712Snn35248 }
51072712Snn35248 return (0);
51082712Snn35248 }
51092712Snn35248
51102712Snn35248 static void
priv_lists_destroy(priv_lists_t * plp)51112712Snn35248 priv_lists_destroy(priv_lists_t *plp)
51122712Snn35248 {
51132712Snn35248 priv_node_t *pnp;
51142712Snn35248
51152712Snn35248 assert(plp != NULL);
51162712Snn35248
51172712Snn35248 while ((pnp = plp->pl_default) != NULL) {
51182712Snn35248 plp->pl_default = pnp->pn_next;
51192712Snn35248 free(pnp->pn_priv);
51202712Snn35248 free(pnp);
51212712Snn35248 }
51222712Snn35248 while ((pnp = plp->pl_prohibited) != NULL) {
51232712Snn35248 plp->pl_prohibited = pnp->pn_next;
51242712Snn35248 free(pnp->pn_priv);
51252712Snn35248 free(pnp);
51262712Snn35248 }
51272712Snn35248 while ((pnp = plp->pl_required) != NULL) {
51282712Snn35248 plp->pl_required = pnp->pn_next;
51292712Snn35248 free(pnp->pn_priv);
51302712Snn35248 free(pnp);
51312712Snn35248 }
51322712Snn35248 free(plp);
51332712Snn35248 }
51342712Snn35248
51352712Snn35248 static int
priv_lists_create(zone_dochandle_t handle,char * brand,priv_lists_t ** plpp,const char * curr_iptype)513610943SEdward.Pilatowicz@Sun.COM priv_lists_create(zone_dochandle_t handle, char *brand, priv_lists_t **plpp,
51373673Sdh155122 const char *curr_iptype)
51382712Snn35248 {
51392712Snn35248 priv_lists_t *plp;
51402727Sedp brand_handle_t bh;
514110943SEdward.Pilatowicz@Sun.COM char brand_str[MAXNAMELEN];
514210943SEdward.Pilatowicz@Sun.COM
514310943SEdward.Pilatowicz@Sun.COM /* handle or brand must be set, but never both */
514410943SEdward.Pilatowicz@Sun.COM assert((handle != NULL) || (brand != NULL));
514510943SEdward.Pilatowicz@Sun.COM assert((handle == NULL) || (brand == NULL));
51462712Snn35248
51472712Snn35248 if (handle != NULL) {
514810943SEdward.Pilatowicz@Sun.COM brand = brand_str;
514910943SEdward.Pilatowicz@Sun.COM if (zonecfg_get_brand(handle, brand, sizeof (brand_str)) != 0)
51502712Snn35248 return (Z_BRAND_ERROR);
51512712Snn35248 }
51522712Snn35248
51532727Sedp if ((bh = brand_open(brand)) == NULL)
51542712Snn35248 return (Z_BRAND_ERROR);
51552712Snn35248
51562712Snn35248 if ((plp = calloc(1, sizeof (priv_lists_t))) == NULL) {
51572727Sedp brand_close(bh);
51582712Snn35248 return (Z_NOMEM);
51592712Snn35248 }
51602712Snn35248
51613673Sdh155122 plp->pl_iptype = curr_iptype;
51623673Sdh155122
51632712Snn35248 /* construct the privilege lists */
51642727Sedp if (brand_config_iter_privilege(bh, priv_lists_cb, plp) != 0) {
51652712Snn35248 priv_lists_destroy(plp);
51662727Sedp brand_close(bh);
51672712Snn35248 return (Z_BRAND_ERROR);
51682712Snn35248 }
51692712Snn35248
51702727Sedp brand_close(bh);
51712712Snn35248 *plpp = plp;
51722712Snn35248 return (Z_OK);
51732712Snn35248 }
51742712Snn35248
51752712Snn35248 static int
get_default_privset(priv_set_t * privs,priv_lists_t * plp)51762712Snn35248 get_default_privset(priv_set_t *privs, priv_lists_t *plp)
51772712Snn35248 {
51782712Snn35248 priv_node_t *pnp;
51791645Scomay priv_set_t *basic;
51801645Scomay
51811645Scomay basic = priv_str_to_set(BASIC_TOKEN, TOKEN_PRIV_STR, NULL);
51820Sstevel@tonic-gate if (basic == NULL)
51831645Scomay return (errno == ENOMEM ? Z_NOMEM : Z_INVAL);
51840Sstevel@tonic-gate
51850Sstevel@tonic-gate priv_union(basic, privs);
51860Sstevel@tonic-gate priv_freeset(basic);
51870Sstevel@tonic-gate
51882712Snn35248 for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) {
51892712Snn35248 if (priv_addset(privs, pnp->pn_priv) != 0)
51900Sstevel@tonic-gate return (Z_INVAL);
51910Sstevel@tonic-gate }
51922712Snn35248
51930Sstevel@tonic-gate return (Z_OK);
51940Sstevel@tonic-gate }
51950Sstevel@tonic-gate
51962712Snn35248 int
zonecfg_default_brand(char * brand,size_t brandsize)519710943SEdward.Pilatowicz@Sun.COM zonecfg_default_brand(char *brand, size_t brandsize)
519810943SEdward.Pilatowicz@Sun.COM {
519910943SEdward.Pilatowicz@Sun.COM zone_dochandle_t handle;
520011176SEdward.Pilatowicz@Sun.COM int myzoneid = getzoneid();
520110943SEdward.Pilatowicz@Sun.COM int ret;
520210943SEdward.Pilatowicz@Sun.COM
520311176SEdward.Pilatowicz@Sun.COM /*
520411176SEdward.Pilatowicz@Sun.COM * If we're running within a zone, then the default brand is the
520511176SEdward.Pilatowicz@Sun.COM * current zone's brand.
520611176SEdward.Pilatowicz@Sun.COM */
520711176SEdward.Pilatowicz@Sun.COM if (myzoneid != GLOBAL_ZONEID) {
520811176SEdward.Pilatowicz@Sun.COM ret = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brand, brandsize);
520911176SEdward.Pilatowicz@Sun.COM if (ret < 0)
521011176SEdward.Pilatowicz@Sun.COM return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL);
521111176SEdward.Pilatowicz@Sun.COM return (Z_OK);
521211176SEdward.Pilatowicz@Sun.COM }
521311176SEdward.Pilatowicz@Sun.COM
521410943SEdward.Pilatowicz@Sun.COM if ((handle = zonecfg_init_handle()) == NULL)
521510943SEdward.Pilatowicz@Sun.COM return (Z_NOMEM);
521610943SEdward.Pilatowicz@Sun.COM if ((ret = zonecfg_get_handle("SUNWdefault", handle)) == Z_OK) {
521710943SEdward.Pilatowicz@Sun.COM ret = i_zonecfg_get_brand(handle, brand, brandsize, B_TRUE);
521810943SEdward.Pilatowicz@Sun.COM zonecfg_fini_handle(handle);
521910943SEdward.Pilatowicz@Sun.COM return (ret);
522010943SEdward.Pilatowicz@Sun.COM }
522110943SEdward.Pilatowicz@Sun.COM return (ret);
522210943SEdward.Pilatowicz@Sun.COM }
522310943SEdward.Pilatowicz@Sun.COM
522410943SEdward.Pilatowicz@Sun.COM int
zonecfg_default_privset(priv_set_t * privs,const char * curr_iptype)52253673Sdh155122 zonecfg_default_privset(priv_set_t *privs, const char *curr_iptype)
52262712Snn35248 {
52272712Snn35248 priv_lists_t *plp;
522810943SEdward.Pilatowicz@Sun.COM char buf[MAXNAMELEN];
52292712Snn35248 int ret;
52302712Snn35248
523110943SEdward.Pilatowicz@Sun.COM if ((ret = zonecfg_default_brand(buf, sizeof (buf))) != Z_OK)
523210943SEdward.Pilatowicz@Sun.COM return (ret);
523310943SEdward.Pilatowicz@Sun.COM if ((ret = priv_lists_create(NULL, buf, &plp, curr_iptype)) != Z_OK)
52342712Snn35248 return (ret);
52352712Snn35248 ret = get_default_privset(privs, plp);
52362712Snn35248 priv_lists_destroy(plp);
52372712Snn35248 return (ret);
52382712Snn35248 }
52392712Snn35248
52401645Scomay void
append_priv_token(char * priv,char * str,size_t strlen)52411645Scomay append_priv_token(char *priv, char *str, size_t strlen)
52421645Scomay {
52431645Scomay if (*str != '\0')
52441645Scomay (void) strlcat(str, TOKEN_PRIV_STR, strlen);
52451645Scomay (void) strlcat(str, priv, strlen);
52461645Scomay }
52471645Scomay
52481645Scomay /*
52491645Scomay * Verify that the supplied string is a valid privilege limit set for a
52501645Scomay * non-global zone. This string must not only be acceptable to
52511645Scomay * priv_str_to_set(3C) which parses it, but it also must resolve to a
52521645Scomay * privilege set that includes certain required privileges and lacks
52531645Scomay * certain prohibited privileges.
52541645Scomay */
52551645Scomay static int
verify_privset(char * privbuf,priv_set_t * privs,char ** privname,boolean_t add_default,priv_lists_t * plp)52561645Scomay verify_privset(char *privbuf, priv_set_t *privs, char **privname,
52572712Snn35248 boolean_t add_default, priv_lists_t *plp)
52582712Snn35248 {
52592712Snn35248 priv_node_t *pnp;
52602712Snn35248 char *tmp, *cp, *lasts;
52611645Scomay size_t len;
52621645Scomay priv_set_t *mergeset;
52631645Scomay const char *token;
52641645Scomay
52651645Scomay /*
52661645Scomay * The verification of the privilege string occurs in several
52671645Scomay * phases. In the first phase, the supplied string is scanned for
52681645Scomay * the ZONE_TOKEN token which is not support as part of the
52691645Scomay * "limitpriv" property.
52701645Scomay *
52711645Scomay * Duplicate the supplied privilege string since strtok_r(3C)
52721645Scomay * tokenizes its input by null-terminating the tokens.
52731645Scomay */
52741645Scomay if ((tmp = strdup(privbuf)) == NULL)
52751645Scomay return (Z_NOMEM);
52761645Scomay for (cp = strtok_r(tmp, TOKEN_PRIV_STR, &lasts); cp != NULL;
52771645Scomay cp = strtok_r(NULL, TOKEN_PRIV_STR, &lasts)) {
52781645Scomay if (strcmp(cp, ZONE_TOKEN) == 0) {
52791645Scomay free(tmp);
52801645Scomay if ((*privname = strdup(ZONE_TOKEN)) == NULL)
52811645Scomay return (Z_NOMEM);
52821645Scomay else
52831645Scomay return (Z_PRIV_UNKNOWN);
52841645Scomay }
52851645Scomay }
52861645Scomay free(tmp);
52871645Scomay
52881645Scomay if (add_default) {
52891645Scomay /*
52901645Scomay * If DEFAULT_TOKEN was specified, a string needs to be
52911645Scomay * built containing the privileges from the default, safe
52921645Scomay * set along with those of the "limitpriv" property.
52931645Scomay */
52941645Scomay len = strlen(privbuf) + sizeof (BASIC_TOKEN) + 2;
52952712Snn35248
52962712Snn35248 for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next)
52972712Snn35248 len += strlen(pnp->pn_priv) + 1;
52981645Scomay tmp = alloca(len);
52991645Scomay *tmp = '\0';
53001645Scomay
53011645Scomay append_priv_token(BASIC_TOKEN, tmp, len);
53022712Snn35248 for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next)
53032712Snn35248 append_priv_token(pnp->pn_priv, tmp, len);
53041645Scomay (void) strlcat(tmp, TOKEN_PRIV_STR, len);
53051645Scomay (void) strlcat(tmp, privbuf, len);
53061645Scomay } else {
53071645Scomay tmp = privbuf;
53081645Scomay }
53091645Scomay
53101645Scomay
53111645Scomay /*
53121645Scomay * In the next phase, attempt to convert the merged privilege
53131645Scomay * string into a privilege set. In the case of an error, either
53141645Scomay * there was a memory allocation failure or there was an invalid
53151645Scomay * privilege token in the string. In either case, return an
53161645Scomay * appropriate error code but in the event of an invalid token,
53171645Scomay * allocate a string containing its name and return that back to
53181645Scomay * the caller.
53191645Scomay */
53201645Scomay mergeset = priv_str_to_set(tmp, TOKEN_PRIV_STR, &token);
53211645Scomay if (mergeset == NULL) {
53221645Scomay if (token == NULL)
53231645Scomay return (Z_NOMEM);
53241645Scomay if ((cp = strchr(token, TOKEN_PRIV_CHAR)) != NULL)
53251645Scomay *cp = '\0';
53261645Scomay if ((*privname = strdup(token)) == NULL)
53271645Scomay return (Z_NOMEM);
53281645Scomay else
53291645Scomay return (Z_PRIV_UNKNOWN);
53301645Scomay }
53311645Scomay
53321645Scomay /*
53331645Scomay * Next, verify that none of the prohibited zone privileges are
53341645Scomay * present in the merged privilege set.
53351645Scomay */
53362712Snn35248 for (pnp = plp->pl_prohibited; pnp != NULL; pnp = pnp->pn_next) {
53372712Snn35248 if (priv_ismember(mergeset, pnp->pn_priv)) {
53381645Scomay priv_freeset(mergeset);
53392712Snn35248 if ((*privname = strdup(pnp->pn_priv)) == NULL)
53401645Scomay return (Z_NOMEM);
53411645Scomay else
53421645Scomay return (Z_PRIV_PROHIBITED);
53431645Scomay }
53441645Scomay }
53451645Scomay
53461645Scomay /*
53471645Scomay * Finally, verify that all of the required zone privileges are
53481645Scomay * present in the merged privilege set.
53491645Scomay */
53502712Snn35248 for (pnp = plp->pl_required; pnp != NULL; pnp = pnp->pn_next) {
53512712Snn35248 if (!priv_ismember(mergeset, pnp->pn_priv)) {
53521645Scomay priv_freeset(mergeset);
53532712Snn35248 if ((*privname = strdup(pnp->pn_priv)) == NULL)
53541645Scomay return (Z_NOMEM);
53551645Scomay else
53561645Scomay return (Z_PRIV_REQUIRED);
53571645Scomay }
53581645Scomay }
53591645Scomay
53601645Scomay priv_copyset(mergeset, privs);
53611645Scomay priv_freeset(mergeset);
53621645Scomay return (Z_OK);
53631645Scomay }
53641645Scomay
53651645Scomay /*
53661645Scomay * Fill in the supplied privilege set with either the default, safe set of
53671645Scomay * privileges suitable for a non-global zone, or one based on the
53681645Scomay * "limitpriv" property in the zone's configuration.
53691645Scomay *
53701645Scomay * In the event of an invalid privilege specification in the
53711645Scomay * configuration, a string is allocated and returned containing the
53721645Scomay * "privilege" causing the issue. It is the caller's responsibility to
53731645Scomay * free this memory when it is done with it.
53741645Scomay */
53751645Scomay int
zonecfg_get_privset(zone_dochandle_t handle,priv_set_t * privs,char ** privname)53761645Scomay zonecfg_get_privset(zone_dochandle_t handle, priv_set_t *privs,
53771645Scomay char **privname)
53781645Scomay {
53792712Snn35248 priv_lists_t *plp;
53802712Snn35248 char *cp, *limitpriv = NULL;
53812712Snn35248 int err, limitlen;
53823673Sdh155122 zone_iptype_t iptype;
53833673Sdh155122 const char *curr_iptype;
53841645Scomay
53851645Scomay /*
53861645Scomay * Attempt to lookup the "limitpriv" property. If it does not
53871645Scomay * exist or matches the string DEFAULT_TOKEN exactly, then the
53881645Scomay * default, safe privilege set is returned.
53891645Scomay */
53902712Snn35248 if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) != Z_OK)
53911645Scomay return (err);
53922712Snn35248
53933673Sdh155122 if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK)
53943673Sdh155122 return (err);
53953673Sdh155122
53963673Sdh155122 switch (iptype) {
53973673Sdh155122 case ZS_SHARED:
53983673Sdh155122 curr_iptype = "shared";
53993673Sdh155122 break;
54003673Sdh155122 case ZS_EXCLUSIVE:
54013673Sdh155122 curr_iptype = "exclusive";
54023673Sdh155122 break;
54033673Sdh155122 }
54043673Sdh155122
540510943SEdward.Pilatowicz@Sun.COM if ((err = priv_lists_create(handle, NULL, &plp, curr_iptype)) != Z_OK)
54062712Snn35248 return (err);
54072712Snn35248
54081645Scomay limitlen = strlen(limitpriv);
54091645Scomay if (limitlen == 0 || strcmp(limitpriv, DEFAULT_TOKEN) == 0) {
54101645Scomay free(limitpriv);
54112712Snn35248 err = get_default_privset(privs, plp);
54122712Snn35248 priv_lists_destroy(plp);
54132712Snn35248 return (err);
54141645Scomay }
54151645Scomay
54161645Scomay /*
54171645Scomay * Check if the string DEFAULT_TOKEN is the first token in a list
54181645Scomay * of privileges.
54191645Scomay */
54201645Scomay cp = strchr(limitpriv, TOKEN_PRIV_CHAR);
54211645Scomay if (cp != NULL &&
54221645Scomay strncmp(limitpriv, DEFAULT_TOKEN, cp - limitpriv) == 0)
54232712Snn35248 err = verify_privset(cp + 1, privs, privname, B_TRUE, plp);
54241645Scomay else
54252712Snn35248 err = verify_privset(limitpriv, privs, privname, B_FALSE, plp);
54261645Scomay
54271645Scomay free(limitpriv);
54282712Snn35248 priv_lists_destroy(plp);
54291645Scomay return (err);
54301645Scomay }
54311645Scomay
54320Sstevel@tonic-gate int
zone_get_zonepath(char * zone_name,char * zonepath,size_t rp_sz)54330Sstevel@tonic-gate zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz)
54340Sstevel@tonic-gate {
54350Sstevel@tonic-gate zone_dochandle_t handle;
54360Sstevel@tonic-gate boolean_t found = B_FALSE;
54370Sstevel@tonic-gate struct zoneent *ze;
54380Sstevel@tonic-gate FILE *cookie;
54390Sstevel@tonic-gate int err;
5440766Scarlsonj char *cp;
54410Sstevel@tonic-gate
54420Sstevel@tonic-gate if (zone_name == NULL)
54430Sstevel@tonic-gate return (Z_INVAL);
54440Sstevel@tonic-gate
5445766Scarlsonj (void) strlcpy(zonepath, zonecfg_root, rp_sz);
5446766Scarlsonj cp = zonepath + strlen(zonepath);
5447766Scarlsonj while (cp > zonepath && cp[-1] == '/')
5448766Scarlsonj *--cp = '\0';
5449766Scarlsonj
54500Sstevel@tonic-gate if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) {
5451766Scarlsonj if (zonepath[0] == '\0')
5452766Scarlsonj (void) strlcpy(zonepath, "/", rp_sz);
54530Sstevel@tonic-gate return (Z_OK);
54540Sstevel@tonic-gate }
54550Sstevel@tonic-gate
54560Sstevel@tonic-gate /*
54570Sstevel@tonic-gate * First check the index file. Because older versions did not have
54580Sstevel@tonic-gate * a copy of the zone path, allow for it to be zero length, in which
54590Sstevel@tonic-gate * case we ignore this result and fall back to the XML files.
54600Sstevel@tonic-gate */
54610Sstevel@tonic-gate cookie = setzoneent();
54620Sstevel@tonic-gate while ((ze = getzoneent_private(cookie)) != NULL) {
54630Sstevel@tonic-gate if (strcmp(ze->zone_name, zone_name) == 0) {
54640Sstevel@tonic-gate found = B_TRUE;
5465766Scarlsonj if (ze->zone_path[0] != '\0')
5466766Scarlsonj (void) strlcpy(cp, ze->zone_path,
5467766Scarlsonj rp_sz - (cp - zonepath));
54680Sstevel@tonic-gate }
54690Sstevel@tonic-gate free(ze);
54700Sstevel@tonic-gate if (found)
54710Sstevel@tonic-gate break;
54720Sstevel@tonic-gate }
54730Sstevel@tonic-gate endzoneent(cookie);
5474766Scarlsonj if (found && *cp != '\0')
54750Sstevel@tonic-gate return (Z_OK);
54760Sstevel@tonic-gate
54770Sstevel@tonic-gate /* Fall back to the XML files. */
54780Sstevel@tonic-gate if ((handle = zonecfg_init_handle()) == NULL)
54790Sstevel@tonic-gate return (Z_NOMEM);
54800Sstevel@tonic-gate
54810Sstevel@tonic-gate /*
54820Sstevel@tonic-gate * Check the snapshot first: if a zone is running, its zonepath
54830Sstevel@tonic-gate * may have changed.
54840Sstevel@tonic-gate */
54850Sstevel@tonic-gate if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) {
54863716Sgjelinek if ((err = zonecfg_get_handle(zone_name, handle)) != Z_OK) {
54873716Sgjelinek zonecfg_fini_handle(handle);
54880Sstevel@tonic-gate return (err);
54893716Sgjelinek }
54900Sstevel@tonic-gate }
54910Sstevel@tonic-gate err = zonecfg_get_zonepath(handle, zonepath, rp_sz);
54920Sstevel@tonic-gate zonecfg_fini_handle(handle);
54930Sstevel@tonic-gate return (err);
54940Sstevel@tonic-gate }
54950Sstevel@tonic-gate
54960Sstevel@tonic-gate int
zone_get_rootpath(char * zone_name,char * rootpath,size_t rp_sz)54970Sstevel@tonic-gate zone_get_rootpath(char *zone_name, char *rootpath, size_t rp_sz)
54980Sstevel@tonic-gate {
54990Sstevel@tonic-gate int err;
55000Sstevel@tonic-gate
55010Sstevel@tonic-gate /* This function makes sense for non-global zones only. */
55020Sstevel@tonic-gate if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
55030Sstevel@tonic-gate return (Z_BOGUS_ZONE_NAME);
55040Sstevel@tonic-gate if ((err = zone_get_zonepath(zone_name, rootpath, rp_sz)) != Z_OK)
55050Sstevel@tonic-gate return (err);
55060Sstevel@tonic-gate if (strlcat(rootpath, "/root", rp_sz) >= rp_sz)
55070Sstevel@tonic-gate return (Z_TOO_BIG);
55080Sstevel@tonic-gate return (Z_OK);
55090Sstevel@tonic-gate }
55100Sstevel@tonic-gate
55112712Snn35248 int
zone_get_brand(char * zone_name,char * brandname,size_t rp_sz)55122712Snn35248 zone_get_brand(char *zone_name, char *brandname, size_t rp_sz)
55132712Snn35248 {
55142712Snn35248 int err;
55152712Snn35248 zone_dochandle_t handle;
55162712Snn35248 char myzone[MAXNAMELEN];
55172712Snn35248 int myzoneid = getzoneid();
55182712Snn35248
55192712Snn35248 /*
55202712Snn35248 * If we are not in the global zone, then we don't have the zone
55212712Snn35248 * .xml files with the brand name available. Thus, we are going to
55222712Snn35248 * have to ask the kernel for the information.
55232712Snn35248 */
55242712Snn35248 if (myzoneid != GLOBAL_ZONEID) {
55253979Sgjelinek if (is_system_labeled()) {
55263979Sgjelinek (void) strlcpy(brandname, NATIVE_BRAND_NAME, rp_sz);
55273979Sgjelinek return (Z_OK);
55283979Sgjelinek }
55292712Snn35248 if (zone_getattr(myzoneid, ZONE_ATTR_NAME, myzone,
55302712Snn35248 sizeof (myzone)) < 0)
55312712Snn35248 return (Z_NO_ZONE);
55329719SSaurabh.Vyas@Sun.COM if (!zonecfg_is_scratch(myzone)) {
55339719SSaurabh.Vyas@Sun.COM if (strncmp(zone_name, myzone, MAXNAMELEN) != 0)
55349719SSaurabh.Vyas@Sun.COM return (Z_NO_ZONE);
55359719SSaurabh.Vyas@Sun.COM }
55362712Snn35248 err = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brandname, rp_sz);
55372712Snn35248 if (err < 0)
55382712Snn35248 return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL);
55399719SSaurabh.Vyas@Sun.COM
55402712Snn35248 return (Z_OK);
55412712Snn35248 }
55422712Snn35248
554310943SEdward.Pilatowicz@Sun.COM if (strcmp(zone_name, "global") == 0)
554410943SEdward.Pilatowicz@Sun.COM return (zonecfg_default_brand(brandname, rp_sz));
554510943SEdward.Pilatowicz@Sun.COM
55462712Snn35248 if ((handle = zonecfg_init_handle()) == NULL)
55472712Snn35248 return (Z_NOMEM);
55482712Snn35248
55492712Snn35248 err = zonecfg_get_handle((char *)zone_name, handle);
55502712Snn35248 if (err == Z_OK)
55512712Snn35248 err = zonecfg_get_brand(handle, brandname, rp_sz);
55522712Snn35248
55532712Snn35248 zonecfg_fini_handle(handle);
55542712Snn35248 return (err);
55552712Snn35248 }
55562712Snn35248
55572621Sllai1 /*
55582621Sllai1 * Return the appropriate root for the active /dev.
55592621Sllai1 * For normal zone, the path is $ZONEPATH/root;
55602621Sllai1 * for scratch zone, the dev path is $ZONEPATH/lu.
55612621Sllai1 */
55622621Sllai1 int
zone_get_devroot(char * zone_name,char * devroot,size_t rp_sz)55632621Sllai1 zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz)
55642621Sllai1 {
55652621Sllai1 int err;
55662621Sllai1 char *suffix;
55672621Sllai1 zone_state_t state;
55682621Sllai1
55692621Sllai1 /* This function makes sense for non-global zones only. */
55702621Sllai1 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
55712621Sllai1 return (Z_BOGUS_ZONE_NAME);
55722621Sllai1 if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK)
55732621Sllai1 return (err);
55742621Sllai1
55752621Sllai1 if (zone_get_state(zone_name, &state) == Z_OK &&
55762621Sllai1 state == ZONE_STATE_MOUNTED)
55772621Sllai1 suffix = "/lu";
55782621Sllai1 else
55792621Sllai1 suffix = "/root";
55802621Sllai1 if (strlcat(devroot, suffix, rp_sz) >= rp_sz)
55812621Sllai1 return (Z_TOO_BIG);
55822621Sllai1 return (Z_OK);
55832621Sllai1 }
55842621Sllai1
55850Sstevel@tonic-gate static zone_state_t
kernel_state_to_user_state(zoneid_t zoneid,zone_status_t kernel_state)5586766Scarlsonj kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state)
55870Sstevel@tonic-gate {
5588766Scarlsonj char zoneroot[MAXPATHLEN];
5589766Scarlsonj size_t zlen;
5590766Scarlsonj
55910Sstevel@tonic-gate assert(kernel_state <= ZONE_MAX_STATE);
55920Sstevel@tonic-gate switch (kernel_state) {
55930Sstevel@tonic-gate case ZONE_IS_UNINITIALIZED:
55945880Snordmark case ZONE_IS_INITIALIZED:
55955880Snordmark /* The kernel will not return these two states */
5596766Scarlsonj return (ZONE_STATE_READY);
55970Sstevel@tonic-gate case ZONE_IS_READY:
5598766Scarlsonj /*
5599766Scarlsonj * If the zone's root is mounted on $ZONEPATH/lu, then
5600766Scarlsonj * it's a mounted scratch zone.
5601766Scarlsonj */
5602766Scarlsonj if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot,
5603766Scarlsonj sizeof (zoneroot)) >= 0) {
5604766Scarlsonj zlen = strlen(zoneroot);
5605766Scarlsonj if (zlen > 3 &&
5606766Scarlsonj strcmp(zoneroot + zlen - 3, "/lu") == 0)
5607766Scarlsonj return (ZONE_STATE_MOUNTED);
5608766Scarlsonj }
56090Sstevel@tonic-gate return (ZONE_STATE_READY);
56100Sstevel@tonic-gate case ZONE_IS_BOOTING:
56110Sstevel@tonic-gate case ZONE_IS_RUNNING:
56120Sstevel@tonic-gate return (ZONE_STATE_RUNNING);
56130Sstevel@tonic-gate case ZONE_IS_SHUTTING_DOWN:
56140Sstevel@tonic-gate case ZONE_IS_EMPTY:
56150Sstevel@tonic-gate return (ZONE_STATE_SHUTTING_DOWN);
56160Sstevel@tonic-gate case ZONE_IS_DOWN:
56170Sstevel@tonic-gate case ZONE_IS_DYING:
56180Sstevel@tonic-gate case ZONE_IS_DEAD:
56190Sstevel@tonic-gate default:
56200Sstevel@tonic-gate return (ZONE_STATE_DOWN);
56210Sstevel@tonic-gate }
56220Sstevel@tonic-gate /* NOTREACHED */
56230Sstevel@tonic-gate }
56240Sstevel@tonic-gate
56250Sstevel@tonic-gate int
zone_get_state(char * zone_name,zone_state_t * state_num)56260Sstevel@tonic-gate zone_get_state(char *zone_name, zone_state_t *state_num)
56270Sstevel@tonic-gate {
56280Sstevel@tonic-gate zone_status_t status;
56290Sstevel@tonic-gate zoneid_t zone_id;
56300Sstevel@tonic-gate struct zoneent *ze;
56310Sstevel@tonic-gate boolean_t found = B_FALSE;
56320Sstevel@tonic-gate FILE *cookie;
5633766Scarlsonj char kernzone[ZONENAME_MAX];
5634766Scarlsonj FILE *fp;
56350Sstevel@tonic-gate
56360Sstevel@tonic-gate if (zone_name == NULL)
56370Sstevel@tonic-gate return (Z_INVAL);
56380Sstevel@tonic-gate
5639766Scarlsonj /*
5640766Scarlsonj * If we're looking at an alternate root, then we need to query the
5641766Scarlsonj * kernel using the scratch zone name.
5642766Scarlsonj */
5643766Scarlsonj zone_id = -1;
5644766Scarlsonj if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) {
5645766Scarlsonj if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) {
5646766Scarlsonj if (zonecfg_find_scratch(fp, zone_name, zonecfg_root,
5647766Scarlsonj kernzone, sizeof (kernzone)) == 0)
5648766Scarlsonj zone_id = getzoneidbyname(kernzone);
5649766Scarlsonj zonecfg_close_scratch(fp);
5650766Scarlsonj }
5651766Scarlsonj } else {
5652766Scarlsonj zone_id = getzoneidbyname(zone_name);
5653766Scarlsonj }
5654766Scarlsonj
56550Sstevel@tonic-gate /* check to see if zone is running */
5656766Scarlsonj if (zone_id != -1 &&
56570Sstevel@tonic-gate zone_getattr(zone_id, ZONE_ATTR_STATUS, &status,
56580Sstevel@tonic-gate sizeof (status)) >= 0) {
5659766Scarlsonj *state_num = kernel_state_to_user_state(zone_id, status);
56600Sstevel@tonic-gate return (Z_OK);
56610Sstevel@tonic-gate }
56620Sstevel@tonic-gate
56630Sstevel@tonic-gate cookie = setzoneent();
56640Sstevel@tonic-gate while ((ze = getzoneent_private(cookie)) != NULL) {
56650Sstevel@tonic-gate if (strcmp(ze->zone_name, zone_name) == 0) {
56660Sstevel@tonic-gate found = B_TRUE;
56670Sstevel@tonic-gate *state_num = ze->zone_state;
56680Sstevel@tonic-gate }
56690Sstevel@tonic-gate free(ze);
56700Sstevel@tonic-gate if (found)
56710Sstevel@tonic-gate break;
56720Sstevel@tonic-gate }
56730Sstevel@tonic-gate endzoneent(cookie);
56740Sstevel@tonic-gate return ((found) ? Z_OK : Z_NO_ZONE);
56750Sstevel@tonic-gate }
56760Sstevel@tonic-gate
56770Sstevel@tonic-gate int
zone_set_state(char * zone,zone_state_t state)56780Sstevel@tonic-gate zone_set_state(char *zone, zone_state_t state)
56790Sstevel@tonic-gate {
56800Sstevel@tonic-gate struct zoneent ze;
56810Sstevel@tonic-gate
56820Sstevel@tonic-gate if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED &&
56830Sstevel@tonic-gate state != ZONE_STATE_INCOMPLETE)
56840Sstevel@tonic-gate return (Z_INVAL);
56850Sstevel@tonic-gate
5686565Sdp bzero(&ze, sizeof (ze));
56870Sstevel@tonic-gate (void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name));
56880Sstevel@tonic-gate ze.zone_state = state;
56890Sstevel@tonic-gate (void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path));
56900Sstevel@tonic-gate return (putzoneent(&ze, PZE_MODIFY));
56910Sstevel@tonic-gate }
56920Sstevel@tonic-gate
56930Sstevel@tonic-gate /*
56940Sstevel@tonic-gate * Get id (if any) for specified zone. There are four possible outcomes:
56950Sstevel@tonic-gate * - If the string corresponds to the numeric id of an active (booted)
56960Sstevel@tonic-gate * zone, sets *zip to the zone id and returns 0.
56970Sstevel@tonic-gate * - If the string corresponds to the name of an active (booted) zone,
56980Sstevel@tonic-gate * sets *zip to the zone id and returns 0.
56990Sstevel@tonic-gate * - If the string is a name in the configuration but is not booted,
57000Sstevel@tonic-gate * sets *zip to ZONE_ID_UNDEFINED and returns 0.
57010Sstevel@tonic-gate * - Otherwise, leaves *zip unchanged and returns -1.
57020Sstevel@tonic-gate *
57030Sstevel@tonic-gate * This function acts as an auxiliary filter on the function of the same
57040Sstevel@tonic-gate * name in libc; the linker binds to this version if libzonecfg exists,
57050Sstevel@tonic-gate * and the libc version if it doesn't. Any changes to this version of
57060Sstevel@tonic-gate * the function should probably be reflected in the libc version as well.
57070Sstevel@tonic-gate */
57080Sstevel@tonic-gate int
zone_get_id(const char * str,zoneid_t * zip)57090Sstevel@tonic-gate zone_get_id(const char *str, zoneid_t *zip)
57100Sstevel@tonic-gate {
57110Sstevel@tonic-gate zone_dochandle_t hdl;
57120Sstevel@tonic-gate zoneid_t zoneid;
57130Sstevel@tonic-gate char *cp;
57140Sstevel@tonic-gate int err;
57150Sstevel@tonic-gate
57160Sstevel@tonic-gate /* first try looking for active zone by id */
57170Sstevel@tonic-gate errno = 0;
57180Sstevel@tonic-gate zoneid = (zoneid_t)strtol(str, &cp, 0);
57190Sstevel@tonic-gate if (errno == 0 && cp != str && *cp == '\0' &&
57200Sstevel@tonic-gate getzonenamebyid(zoneid, NULL, 0) != -1) {
57210Sstevel@tonic-gate *zip = zoneid;
57220Sstevel@tonic-gate return (0);
57230Sstevel@tonic-gate }
57240Sstevel@tonic-gate
57250Sstevel@tonic-gate /* then look for active zone by name */
57260Sstevel@tonic-gate if ((zoneid = getzoneidbyname(str)) != -1) {
57270Sstevel@tonic-gate *zip = zoneid;
57280Sstevel@tonic-gate return (0);
57290Sstevel@tonic-gate }
57300Sstevel@tonic-gate
57310Sstevel@tonic-gate /* if in global zone, try looking up name in configuration database */
57320Sstevel@tonic-gate if (getzoneid() != GLOBAL_ZONEID ||
57330Sstevel@tonic-gate (hdl = zonecfg_init_handle()) == NULL)
57340Sstevel@tonic-gate return (-1);
57350Sstevel@tonic-gate
5736766Scarlsonj if (zonecfg_get_handle(str, hdl) == Z_OK) {
57370Sstevel@tonic-gate /* zone exists but isn't active */
57380Sstevel@tonic-gate *zip = ZONE_ID_UNDEFINED;
57390Sstevel@tonic-gate err = 0;
57400Sstevel@tonic-gate } else {
57410Sstevel@tonic-gate err = -1;
57420Sstevel@tonic-gate }
57430Sstevel@tonic-gate
57440Sstevel@tonic-gate zonecfg_fini_handle(hdl);
57450Sstevel@tonic-gate return (err);
57460Sstevel@tonic-gate }
57470Sstevel@tonic-gate
57480Sstevel@tonic-gate char *
zone_state_str(zone_state_t state_num)57490Sstevel@tonic-gate zone_state_str(zone_state_t state_num)
57500Sstevel@tonic-gate {
57510Sstevel@tonic-gate switch (state_num) {
57520Sstevel@tonic-gate case ZONE_STATE_CONFIGURED:
57530Sstevel@tonic-gate return (ZONE_STATE_STR_CONFIGURED);
57540Sstevel@tonic-gate case ZONE_STATE_INCOMPLETE:
57550Sstevel@tonic-gate return (ZONE_STATE_STR_INCOMPLETE);
57560Sstevel@tonic-gate case ZONE_STATE_INSTALLED:
57570Sstevel@tonic-gate return (ZONE_STATE_STR_INSTALLED);
57580Sstevel@tonic-gate case ZONE_STATE_READY:
57590Sstevel@tonic-gate return (ZONE_STATE_STR_READY);
5760766Scarlsonj case ZONE_STATE_MOUNTED:
5761766Scarlsonj return (ZONE_STATE_STR_MOUNTED);
57620Sstevel@tonic-gate case ZONE_STATE_RUNNING:
57630Sstevel@tonic-gate return (ZONE_STATE_STR_RUNNING);
57640Sstevel@tonic-gate case ZONE_STATE_SHUTTING_DOWN:
57650Sstevel@tonic-gate return (ZONE_STATE_STR_SHUTTING_DOWN);
57660Sstevel@tonic-gate case ZONE_STATE_DOWN:
57670Sstevel@tonic-gate return (ZONE_STATE_STR_DOWN);
57680Sstevel@tonic-gate default:
57690Sstevel@tonic-gate return ("unknown");
57700Sstevel@tonic-gate }
57710Sstevel@tonic-gate }
57720Sstevel@tonic-gate
57730Sstevel@tonic-gate /*
5774766Scarlsonj * Given a UUID value, find an associated zone name. This is intended to be
5775766Scarlsonj * used by callers who set up some 'default' name (corresponding to the
5776766Scarlsonj * expected name for the zone) in the zonename buffer, and thus the function
5777766Scarlsonj * doesn't touch this buffer on failure.
5778766Scarlsonj */
5779766Scarlsonj int
zonecfg_get_name_by_uuid(const uuid_t uuidin,char * zonename,size_t namelen)57802303Scarlsonj zonecfg_get_name_by_uuid(const uuid_t uuidin, char *zonename, size_t namelen)
5781766Scarlsonj {
5782766Scarlsonj FILE *fp;
5783766Scarlsonj struct zoneent *ze;
57842303Scarlsonj uchar_t *uuid;
5785766Scarlsonj
5786766Scarlsonj /*
5787766Scarlsonj * A small amount of subterfuge via casts is necessary here because
5788766Scarlsonj * libuuid doesn't use const correctly, but we don't want to export
5789766Scarlsonj * this brokenness to our clients.
5790766Scarlsonj */
57912303Scarlsonj uuid = (uchar_t *)uuidin;
57922303Scarlsonj if (uuid_is_null(uuid))
5793766Scarlsonj return (Z_NO_ZONE);
5794766Scarlsonj if ((fp = setzoneent()) == NULL)
5795766Scarlsonj return (Z_NO_ZONE);
5796766Scarlsonj while ((ze = getzoneent_private(fp)) != NULL) {
57972303Scarlsonj if (uuid_compare(uuid, ze->zone_uuid) == 0)
5798766Scarlsonj break;
5799766Scarlsonj free(ze);
5800766Scarlsonj }
5801766Scarlsonj endzoneent(fp);
5802766Scarlsonj if (ze != NULL) {
5803766Scarlsonj (void) strlcpy(zonename, ze->zone_name, namelen);
5804766Scarlsonj free(ze);
5805766Scarlsonj return (Z_OK);
5806766Scarlsonj } else {
5807766Scarlsonj return (Z_NO_ZONE);
5808766Scarlsonj }
5809766Scarlsonj }
5810766Scarlsonj
5811766Scarlsonj /*
5812766Scarlsonj * Given a zone name, get its UUID. Returns a "NULL" UUID value if the zone
5813766Scarlsonj * exists but the file doesn't have a value set yet. Returns an error if the
5814766Scarlsonj * zone cannot be located.
5815766Scarlsonj */
5816766Scarlsonj int
zonecfg_get_uuid(const char * zonename,uuid_t uuid)5817766Scarlsonj zonecfg_get_uuid(const char *zonename, uuid_t uuid)
5818766Scarlsonj {
5819766Scarlsonj FILE *fp;
5820766Scarlsonj struct zoneent *ze;
5821766Scarlsonj
5822766Scarlsonj if ((fp = setzoneent()) == NULL)
5823766Scarlsonj return (Z_NO_ZONE);
5824766Scarlsonj while ((ze = getzoneent_private(fp)) != NULL) {
5825766Scarlsonj if (strcmp(ze->zone_name, zonename) == 0)
5826766Scarlsonj break;
5827766Scarlsonj free(ze);
5828766Scarlsonj }
5829766Scarlsonj endzoneent(fp);
5830766Scarlsonj if (ze != NULL) {
5831766Scarlsonj uuid_copy(uuid, ze->zone_uuid);
5832766Scarlsonj free(ze);
5833766Scarlsonj return (Z_OK);
5834766Scarlsonj } else {
5835766Scarlsonj return (Z_NO_ZONE);
5836766Scarlsonj }
5837766Scarlsonj }
5838766Scarlsonj
5839766Scarlsonj /*
58400Sstevel@tonic-gate * File-system convenience functions.
58410Sstevel@tonic-gate */
58420Sstevel@tonic-gate boolean_t
zonecfg_valid_fs_type(const char * type)58430Sstevel@tonic-gate zonecfg_valid_fs_type(const char *type)
58440Sstevel@tonic-gate {
58450Sstevel@tonic-gate /*
58460Sstevel@tonic-gate * We already know which FS types don't work.
58470Sstevel@tonic-gate */
58480Sstevel@tonic-gate if (strcmp(type, "proc") == 0 ||
58490Sstevel@tonic-gate strcmp(type, "mntfs") == 0 ||
58500Sstevel@tonic-gate strcmp(type, "autofs") == 0 ||
58510Sstevel@tonic-gate strncmp(type, "nfs", sizeof ("nfs") - 1) == 0 ||
58520Sstevel@tonic-gate strcmp(type, "cachefs") == 0)
58530Sstevel@tonic-gate return (B_FALSE);
58540Sstevel@tonic-gate /*
58550Sstevel@tonic-gate * The caller may do more detailed verification to make sure other
58560Sstevel@tonic-gate * aspects of this filesystem type make sense.
58570Sstevel@tonic-gate */
58580Sstevel@tonic-gate return (B_TRUE);
58590Sstevel@tonic-gate }
58600Sstevel@tonic-gate
58610Sstevel@tonic-gate /*
58620Sstevel@tonic-gate * Generally uninteresting rctl convenience functions.
58630Sstevel@tonic-gate */
58640Sstevel@tonic-gate
58650Sstevel@tonic-gate int
zonecfg_construct_rctlblk(const struct zone_rctlvaltab * rctlval,rctlblk_t * rctlblk)58660Sstevel@tonic-gate zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval,
58670Sstevel@tonic-gate rctlblk_t *rctlblk)
58680Sstevel@tonic-gate {
58690Sstevel@tonic-gate unsigned long long ull;
58700Sstevel@tonic-gate char *endp;
58710Sstevel@tonic-gate rctl_priv_t priv;
58720Sstevel@tonic-gate rctl_qty_t limit;
58730Sstevel@tonic-gate uint_t action;
58740Sstevel@tonic-gate
58750Sstevel@tonic-gate /* Get the privilege */
58760Sstevel@tonic-gate if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) {
58770Sstevel@tonic-gate priv = RCPRIV_BASIC;
58780Sstevel@tonic-gate } else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) {
58790Sstevel@tonic-gate priv = RCPRIV_PRIVILEGED;
58800Sstevel@tonic-gate } else {
58810Sstevel@tonic-gate /* Invalid privilege */
58820Sstevel@tonic-gate return (Z_INVAL);
58830Sstevel@tonic-gate }
58840Sstevel@tonic-gate
58850Sstevel@tonic-gate /* deal with negative input; strtoull(3c) doesn't do what we want */
58860Sstevel@tonic-gate if (rctlval->zone_rctlval_limit[0] == '-')
58870Sstevel@tonic-gate return (Z_INVAL);
58880Sstevel@tonic-gate /* Get the limit */
58890Sstevel@tonic-gate errno = 0;
58900Sstevel@tonic-gate ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0);
58910Sstevel@tonic-gate if (errno != 0 || *endp != '\0') {
58920Sstevel@tonic-gate /* parse failed */
58930Sstevel@tonic-gate return (Z_INVAL);
58940Sstevel@tonic-gate }
58950Sstevel@tonic-gate limit = (rctl_qty_t)ull;
58960Sstevel@tonic-gate
58970Sstevel@tonic-gate /* Get the action */
58980Sstevel@tonic-gate if (strcmp(rctlval->zone_rctlval_action, "none") == 0) {
58990Sstevel@tonic-gate action = RCTL_LOCAL_NOACTION;
59000Sstevel@tonic-gate } else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) {
59010Sstevel@tonic-gate action = RCTL_LOCAL_SIGNAL;
59020Sstevel@tonic-gate } else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) {
59030Sstevel@tonic-gate action = RCTL_LOCAL_DENY;
59040Sstevel@tonic-gate } else {
59050Sstevel@tonic-gate /* Invalid Action */
59060Sstevel@tonic-gate return (Z_INVAL);
59070Sstevel@tonic-gate }
59080Sstevel@tonic-gate rctlblk_set_local_action(rctlblk, action, 0);
59090Sstevel@tonic-gate rctlblk_set_privilege(rctlblk, priv);
59100Sstevel@tonic-gate rctlblk_set_value(rctlblk, limit);
59110Sstevel@tonic-gate return (Z_OK);
59120Sstevel@tonic-gate }
59130Sstevel@tonic-gate
59140Sstevel@tonic-gate static int
rctl_check(const char * rctlname,void * arg)59150Sstevel@tonic-gate rctl_check(const char *rctlname, void *arg)
59160Sstevel@tonic-gate {
59170Sstevel@tonic-gate const char *attrname = arg;
59180Sstevel@tonic-gate
59190Sstevel@tonic-gate /*
59200Sstevel@tonic-gate * Returning 1 here is our signal to zonecfg_is_rctl() that it is
59210Sstevel@tonic-gate * indeed an rctl name recognized by the system.
59220Sstevel@tonic-gate */
59230Sstevel@tonic-gate return (strcmp(rctlname, attrname) == 0 ? 1 : 0);
59240Sstevel@tonic-gate }
59250Sstevel@tonic-gate
59260Sstevel@tonic-gate boolean_t
zonecfg_is_rctl(const char * name)59270Sstevel@tonic-gate zonecfg_is_rctl(const char *name)
59280Sstevel@tonic-gate {
59290Sstevel@tonic-gate return (rctl_walk(rctl_check, (void *)name) == 1);
59300Sstevel@tonic-gate }
59310Sstevel@tonic-gate
59320Sstevel@tonic-gate boolean_t
zonecfg_valid_rctlname(const char * name)59330Sstevel@tonic-gate zonecfg_valid_rctlname(const char *name)
59340Sstevel@tonic-gate {
59350Sstevel@tonic-gate const char *c;
59360Sstevel@tonic-gate
59370Sstevel@tonic-gate if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0)
59380Sstevel@tonic-gate return (B_FALSE);
59390Sstevel@tonic-gate if (strlen(name) == sizeof ("zone.") - 1)
59400Sstevel@tonic-gate return (B_FALSE);
59410Sstevel@tonic-gate for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) {
59420Sstevel@tonic-gate if (!isalpha(*c) && *c != '-')
59430Sstevel@tonic-gate return (B_FALSE);
59440Sstevel@tonic-gate }
59450Sstevel@tonic-gate return (B_TRUE);
59460Sstevel@tonic-gate }
59470Sstevel@tonic-gate
59480Sstevel@tonic-gate boolean_t
zonecfg_valid_rctlblk(const rctlblk_t * rctlblk)59490Sstevel@tonic-gate zonecfg_valid_rctlblk(const rctlblk_t *rctlblk)
59500Sstevel@tonic-gate {
59510Sstevel@tonic-gate rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk);
59520Sstevel@tonic-gate uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
59530Sstevel@tonic-gate
59540Sstevel@tonic-gate if (priv != RCPRIV_PRIVILEGED)
59550Sstevel@tonic-gate return (B_FALSE);
59560Sstevel@tonic-gate if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY)
59570Sstevel@tonic-gate return (B_FALSE);
59580Sstevel@tonic-gate return (B_TRUE);
59590Sstevel@tonic-gate }
59600Sstevel@tonic-gate
59610Sstevel@tonic-gate boolean_t
zonecfg_valid_rctl(const char * name,const rctlblk_t * rctlblk)59620Sstevel@tonic-gate zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk)
59630Sstevel@tonic-gate {
59640Sstevel@tonic-gate rctlblk_t *current, *next;
59650Sstevel@tonic-gate rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk);
59660Sstevel@tonic-gate uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL);
59670Sstevel@tonic-gate uint_t global_flags;
59680Sstevel@tonic-gate
59690Sstevel@tonic-gate if (!zonecfg_valid_rctlblk(rctlblk))
59700Sstevel@tonic-gate return (B_FALSE);
59710Sstevel@tonic-gate if (!zonecfg_valid_rctlname(name))
59720Sstevel@tonic-gate return (B_FALSE);
59730Sstevel@tonic-gate
59740Sstevel@tonic-gate current = alloca(rctlblk_size());
59750Sstevel@tonic-gate if (getrctl(name, NULL, current, RCTL_FIRST) != 0)
59760Sstevel@tonic-gate return (B_TRUE); /* not an rctl on this system */
59770Sstevel@tonic-gate /*
59780Sstevel@tonic-gate * Make sure the proposed value isn't greater than the current system
59790Sstevel@tonic-gate * value.
59800Sstevel@tonic-gate */
59810Sstevel@tonic-gate next = alloca(rctlblk_size());
59820Sstevel@tonic-gate while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) {
59830Sstevel@tonic-gate rctlblk_t *tmp;
59840Sstevel@tonic-gate
59850Sstevel@tonic-gate if (getrctl(name, current, next, RCTL_NEXT) != 0)
59860Sstevel@tonic-gate return (B_FALSE); /* shouldn't happen */
59870Sstevel@tonic-gate tmp = current;
59880Sstevel@tonic-gate current = next;
59890Sstevel@tonic-gate next = tmp;
59900Sstevel@tonic-gate }
59910Sstevel@tonic-gate if (limit > rctlblk_get_value(current))
59920Sstevel@tonic-gate return (B_FALSE);
59930Sstevel@tonic-gate
59940Sstevel@tonic-gate /*
59950Sstevel@tonic-gate * Make sure the proposed action is allowed.
59960Sstevel@tonic-gate */
59970Sstevel@tonic-gate global_flags = rctlblk_get_global_flags(current);
59980Sstevel@tonic-gate if ((global_flags & RCTL_GLOBAL_DENY_NEVER) &&
59990Sstevel@tonic-gate action == RCTL_LOCAL_DENY)
60000Sstevel@tonic-gate return (B_FALSE);
60010Sstevel@tonic-gate if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) &&
60020Sstevel@tonic-gate action == RCTL_LOCAL_NOACTION)
60030Sstevel@tonic-gate return (B_FALSE);
60040Sstevel@tonic-gate
60050Sstevel@tonic-gate return (B_TRUE);
60060Sstevel@tonic-gate }
6007789Sahrens
60081166Sdstaff /*
60091166Sdstaff * There is always a race condition between reading the initial copy of
60101166Sdstaff * a zones state and its state changing. We address this by providing
60111166Sdstaff * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions.
60121166Sdstaff * When zonecfg_critical_enter is called, sets the state field to LOCKED
60131166Sdstaff * and aquires biglock. Biglock protects against other threads executing
60141166Sdstaff * critical_enter and the state field protects against state changes during
60151166Sdstaff * the critical period.
60161166Sdstaff *
60171166Sdstaff * If any state changes occur, zn_cb will set the failed field of the znotify
60181166Sdstaff * structure. This will cause the critical_exit function to re-lock the
60191166Sdstaff * channel and return an error. Since evsnts may be delayed, the critical_exit
60201166Sdstaff * function "flushes" the queue by putting an event on the queue and waiting for
60211166Sdstaff * zn_cb to notify critical_exit that it received the ping event.
60221166Sdstaff */
60231166Sdstaff static const char *
string_get_tok(const char * in,char delim,int num)60241166Sdstaff string_get_tok(const char *in, char delim, int num)
60251166Sdstaff {
60261166Sdstaff int i = 0;
60271166Sdstaff
60281166Sdstaff for (; i < num; in++) {
60291166Sdstaff if (*in == delim)
60301166Sdstaff i++;
60311166Sdstaff if (*in == 0)
60321166Sdstaff return (NULL);
60331166Sdstaff }
60341166Sdstaff return (in);
60351166Sdstaff }
60361166Sdstaff
60371166Sdstaff static boolean_t
is_ping(sysevent_t * ev)60381166Sdstaff is_ping(sysevent_t *ev)
60391166Sdstaff {
60401166Sdstaff if (strcmp(sysevent_get_subclass_name(ev),
60411645Scomay ZONE_EVENT_PING_SUBCLASS) == 0) {
60421166Sdstaff return (B_TRUE);
60431166Sdstaff } else {
60441166Sdstaff return (B_FALSE);
60451166Sdstaff }
60461166Sdstaff }
60471166Sdstaff
60481166Sdstaff static boolean_t
is_my_ping(sysevent_t * ev)60491166Sdstaff is_my_ping(sysevent_t *ev)
60501166Sdstaff {
60511166Sdstaff const char *sender;
60521166Sdstaff char mypid[sizeof (pid_t) * 3 + 1];
60531166Sdstaff
60541166Sdstaff (void) snprintf(mypid, sizeof (mypid), "%i", getpid());
60551166Sdstaff sender = string_get_tok(sysevent_get_pub(ev), ':', 3);
60561166Sdstaff if (sender == NULL)
60571166Sdstaff return (B_FALSE);
60581166Sdstaff if (strcmp(sender, mypid) != 0)
60591166Sdstaff return (B_FALSE);
60601166Sdstaff return (B_TRUE);
60611166Sdstaff }
60621166Sdstaff
60631166Sdstaff static int
do_callback(struct znotify * zevtchan,sysevent_t * ev)60641166Sdstaff do_callback(struct znotify *zevtchan, sysevent_t *ev)
60651166Sdstaff {
60661166Sdstaff nvlist_t *l;
60671166Sdstaff int zid;
60681166Sdstaff char *zonename;
60691166Sdstaff char *newstate;
60701166Sdstaff char *oldstate;
60711166Sdstaff int ret;
60721166Sdstaff hrtime_t when;
60731166Sdstaff
60741166Sdstaff if (strcmp(sysevent_get_subclass_name(ev),
60751166Sdstaff ZONE_EVENT_STATUS_SUBCLASS) == 0) {
60761166Sdstaff
60771166Sdstaff if (sysevent_get_attr_list(ev, &l) != 0) {
60781166Sdstaff if (errno == ENOMEM) {
60791166Sdstaff zevtchan->zn_failure_count++;
60801166Sdstaff return (EAGAIN);
60811166Sdstaff }
60821166Sdstaff return (0);
60831166Sdstaff }
60841166Sdstaff ret = 0;
60851166Sdstaff
60861166Sdstaff if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) &&
60871166Sdstaff (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate)
60881645Scomay == 0) &&
60891166Sdstaff (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate)
60901645Scomay == 0) &&
60911166Sdstaff (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP,
60921645Scomay (uint64_t *)&when) == 0) &&
60931166Sdstaff (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) {
60941166Sdstaff ret = zevtchan->zn_callback(zonename, zid, newstate,
60951166Sdstaff oldstate, when, zevtchan->zn_private);
60961166Sdstaff }
60971166Sdstaff
60981166Sdstaff zevtchan->zn_failure_count = 0;
60991166Sdstaff nvlist_free(l);
61001166Sdstaff return (ret);
61011166Sdstaff } else {
61021166Sdstaff /*
61031166Sdstaff * We have received an event in an unknown subclass. Ignore.
61041166Sdstaff */
61051166Sdstaff zevtchan->zn_failure_count = 0;
61061166Sdstaff return (0);
61071166Sdstaff }
61081166Sdstaff }
61091166Sdstaff
61101166Sdstaff static int
zn_cb(sysevent_t * ev,void * p)61111166Sdstaff zn_cb(sysevent_t *ev, void *p)
61121166Sdstaff {
61131166Sdstaff struct znotify *zevtchan = p;
61141166Sdstaff int error;
61151166Sdstaff
61161166Sdstaff (void) pthread_mutex_lock(&(zevtchan->zn_mutex));
61171166Sdstaff
61181166Sdstaff if (is_ping(ev) && !is_my_ping(ev)) {
61191166Sdstaff (void) pthread_mutex_unlock((&zevtchan->zn_mutex));
61201166Sdstaff return (0);
61211166Sdstaff }
61221166Sdstaff
61231166Sdstaff if (zevtchan->zn_state == ZN_LOCKED) {
61241166Sdstaff assert(!is_ping(ev));
61251166Sdstaff zevtchan->zn_failed = B_TRUE;
61261166Sdstaff (void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
61271166Sdstaff return (0);
61281166Sdstaff }
61291166Sdstaff
61301166Sdstaff if (zevtchan->zn_state == ZN_PING_INFLIGHT) {
61311166Sdstaff if (is_ping(ev)) {
61321166Sdstaff zevtchan->zn_state = ZN_PING_RECEIVED;
61331166Sdstaff (void) pthread_cond_signal(&(zevtchan->zn_cond));
61341166Sdstaff (void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
61351166Sdstaff return (0);
61361166Sdstaff } else {
61371166Sdstaff zevtchan->zn_failed = B_TRUE;
61381166Sdstaff (void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
61391166Sdstaff return (0);
61401166Sdstaff }
61411166Sdstaff }
61421166Sdstaff
61431166Sdstaff if (zevtchan->zn_state == ZN_UNLOCKED) {
61441166Sdstaff
61451166Sdstaff error = do_callback(zevtchan, ev);
61461166Sdstaff (void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
61471166Sdstaff /*
61481166Sdstaff * Every ENOMEM failure causes do_callback to increment
61491166Sdstaff * zn_failure_count and every success causes it to
61501166Sdstaff * set zn_failure_count to zero. If we got EAGAIN,
61511166Sdstaff * we will sleep for zn_failure_count seconds and return
61521166Sdstaff * EAGAIN to gpec to try again.
61531166Sdstaff *
61541166Sdstaff * After 55 seconds, or 10 try's we give up and drop the
61551166Sdstaff * event.
61561166Sdstaff */
61571166Sdstaff if (error == EAGAIN) {
61581166Sdstaff if (zevtchan->zn_failure_count > ZONE_CB_RETRY_COUNT) {
61591166Sdstaff return (0);
61601166Sdstaff }
61611166Sdstaff (void) sleep(zevtchan->zn_failure_count);
61621166Sdstaff }
61631166Sdstaff return (error);
61641166Sdstaff }
61651166Sdstaff
61661166Sdstaff if (zevtchan->zn_state == ZN_PING_RECEIVED) {
61671166Sdstaff (void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
61681166Sdstaff return (0);
61691166Sdstaff }
61701166Sdstaff
61711166Sdstaff abort();
61721166Sdstaff return (0);
61731166Sdstaff }
61741166Sdstaff
61751166Sdstaff void
zonecfg_notify_critical_enter(void * h)61761166Sdstaff zonecfg_notify_critical_enter(void *h)
61771166Sdstaff {
61781166Sdstaff struct znotify *zevtchan = h;
61791166Sdstaff
61801166Sdstaff (void) pthread_mutex_lock(&(zevtchan->zn_bigmutex));
61811166Sdstaff zevtchan->zn_state = ZN_LOCKED;
61821166Sdstaff }
61831166Sdstaff
61841166Sdstaff int
zonecfg_notify_critical_exit(void * h)61851166Sdstaff zonecfg_notify_critical_exit(void * h)
61861166Sdstaff {
61871166Sdstaff
61881166Sdstaff struct znotify *zevtchan = h;
61891166Sdstaff
61901166Sdstaff if (zevtchan->zn_state == ZN_UNLOCKED)
61911166Sdstaff return (0);
61921166Sdstaff
61931166Sdstaff (void) pthread_mutex_lock(&(zevtchan->zn_mutex));
61941166Sdstaff zevtchan->zn_state = ZN_PING_INFLIGHT;
61951166Sdstaff
61961507Sgjelinek (void) sysevent_evc_publish(zevtchan->zn_eventchan,
61971507Sgjelinek ZONE_EVENT_STATUS_CLASS,
61981166Sdstaff ZONE_EVENT_PING_SUBCLASS, ZONE_EVENT_PING_PUBLISHER,
61991166Sdstaff zevtchan->zn_subscriber_id, NULL, EVCH_SLEEP);
62001166Sdstaff
62011166Sdstaff while (zevtchan->zn_state != ZN_PING_RECEIVED) {
62021166Sdstaff (void) pthread_cond_wait(&(zevtchan->zn_cond),
62031166Sdstaff &(zevtchan->zn_mutex));
62041166Sdstaff }
62051166Sdstaff
62061166Sdstaff if (zevtchan->zn_failed == B_TRUE) {
62071166Sdstaff zevtchan->zn_state = ZN_LOCKED;
62081166Sdstaff zevtchan->zn_failed = B_FALSE;
62091166Sdstaff (void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
62101166Sdstaff return (1);
62111166Sdstaff }
62121166Sdstaff
62131166Sdstaff zevtchan->zn_state = ZN_UNLOCKED;
62141166Sdstaff (void) pthread_mutex_unlock(&(zevtchan->zn_mutex));
62151166Sdstaff (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex));
62161166Sdstaff return (0);
62171166Sdstaff }
62181166Sdstaff
62191166Sdstaff void
zonecfg_notify_critical_abort(void * h)62201166Sdstaff zonecfg_notify_critical_abort(void *h)
62211166Sdstaff {
62221166Sdstaff struct znotify *zevtchan = h;
62231166Sdstaff
62241166Sdstaff zevtchan->zn_state = ZN_UNLOCKED;
62251166Sdstaff zevtchan->zn_failed = B_FALSE;
62261166Sdstaff /*
62271166Sdstaff * Don't do anything about zn_lock. If it is held, it could only be
62281166Sdstaff * held by zn_cb and it will be unlocked soon.
62291166Sdstaff */
62301166Sdstaff (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex));
62311166Sdstaff }
62321166Sdstaff
62331166Sdstaff void *
zonecfg_notify_bind(int (* func)(const char * zonename,zoneid_t zid,const char * newstate,const char * oldstate,hrtime_t when,void * p),void * p)62341166Sdstaff zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid,
62351166Sdstaff const char *newstate, const char *oldstate, hrtime_t when, void *p),
62361166Sdstaff void *p)
62371166Sdstaff {
62381166Sdstaff struct znotify *zevtchan;
62391166Sdstaff int i = 1;
62401166Sdstaff int r;
62411166Sdstaff
62421166Sdstaff zevtchan = malloc(sizeof (struct znotify));
62431166Sdstaff
62441166Sdstaff if (zevtchan == NULL)
62451166Sdstaff return (NULL);
62461166Sdstaff
62471166Sdstaff zevtchan->zn_private = p;
62481166Sdstaff zevtchan->zn_callback = func;
62491166Sdstaff zevtchan->zn_state = ZN_UNLOCKED;
62501166Sdstaff zevtchan->zn_failed = B_FALSE;
62511166Sdstaff
62521166Sdstaff if (pthread_mutex_init(&(zevtchan->zn_mutex), NULL))
62531374Sdstaff goto out3;
62541166Sdstaff if (pthread_cond_init(&(zevtchan->zn_cond), NULL)) {
62551166Sdstaff (void) pthread_mutex_destroy(&(zevtchan->zn_mutex));
62561374Sdstaff goto out3;
62571166Sdstaff }
62581166Sdstaff if (pthread_mutex_init(&(zevtchan->zn_bigmutex), NULL)) {
62591166Sdstaff (void) pthread_mutex_destroy(&(zevtchan->zn_mutex));
62601166Sdstaff (void) pthread_cond_destroy(&(zevtchan->zn_cond));
62611374Sdstaff goto out3;
62621166Sdstaff }
62631166Sdstaff
62641166Sdstaff if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &(zevtchan->zn_eventchan),
62651645Scomay 0) != 0)
62661166Sdstaff goto out2;
62671166Sdstaff
62681166Sdstaff do {
62691166Sdstaff /*
62701166Sdstaff * At 4 digits the subscriber ID gets too long and we have
62711166Sdstaff * no chance of successfully registering.
62721166Sdstaff */
62731166Sdstaff if (i > 999)
62741374Sdstaff goto out1;
62751166Sdstaff
62761166Sdstaff (void) sprintf(zevtchan->zn_subscriber_id, "zone_%li_%i",
62771166Sdstaff getpid() % 999999l, i);
62781166Sdstaff
62791166Sdstaff r = sysevent_evc_subscribe(zevtchan->zn_eventchan,
62801166Sdstaff zevtchan->zn_subscriber_id, ZONE_EVENT_STATUS_CLASS, zn_cb,
62811166Sdstaff zevtchan, 0);
62821166Sdstaff
62831166Sdstaff i++;
62841166Sdstaff
62851166Sdstaff } while (r);
62861166Sdstaff
62871166Sdstaff return (zevtchan);
62881374Sdstaff out1:
628911102SGavin.Maltby@Sun.COM (void) sysevent_evc_unbind(zevtchan->zn_eventchan);
62901374Sdstaff out2:
62911166Sdstaff (void) pthread_mutex_destroy(&zevtchan->zn_mutex);
62921166Sdstaff (void) pthread_cond_destroy(&zevtchan->zn_cond);
62931166Sdstaff (void) pthread_mutex_destroy(&(zevtchan->zn_bigmutex));
62941374Sdstaff out3:
62951166Sdstaff free(zevtchan);
62961166Sdstaff
62971166Sdstaff return (NULL);
62981166Sdstaff }
62991166Sdstaff
63001166Sdstaff void
zonecfg_notify_unbind(void * handle)63011166Sdstaff zonecfg_notify_unbind(void *handle)
63021166Sdstaff {
63031166Sdstaff
63041166Sdstaff int ret;
63051166Sdstaff
630611102SGavin.Maltby@Sun.COM (void) sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan);
63071166Sdstaff /*
63081166Sdstaff * Check that all evc threads have gone away. This should be
63091166Sdstaff * enforced by sysevent_evc_unbind.
63101166Sdstaff */
63111166Sdstaff ret = pthread_mutex_trylock(&((struct znotify *)handle)->zn_mutex);
63121166Sdstaff
63131166Sdstaff if (ret)
63141166Sdstaff abort();
63151166Sdstaff
63161166Sdstaff (void) pthread_mutex_unlock(&((struct znotify *)handle)->zn_mutex);
63171166Sdstaff (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_mutex);
63181166Sdstaff (void) pthread_cond_destroy(&((struct znotify *)handle)->zn_cond);
63191166Sdstaff (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_bigmutex);
63201166Sdstaff
63211166Sdstaff free(handle);
63221166Sdstaff }
63231166Sdstaff
6324789Sahrens static int
zonecfg_add_ds_core(zone_dochandle_t handle,struct zone_dstab * tabptr)6325789Sahrens zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
6326789Sahrens {
6327789Sahrens xmlNodePtr newnode, cur = handle->zone_dh_cur;
6328789Sahrens int err;
6329789Sahrens
6330789Sahrens newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DATASET, NULL);
6331789Sahrens if ((err = newprop(newnode, DTD_ATTR_NAME,
6332789Sahrens tabptr->zone_dataset_name)) != Z_OK)
6333789Sahrens return (err);
6334789Sahrens return (Z_OK);
6335789Sahrens }
6336789Sahrens
6337789Sahrens int
zonecfg_add_ds(zone_dochandle_t handle,struct zone_dstab * tabptr)6338789Sahrens zonecfg_add_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
6339789Sahrens {
6340789Sahrens int err;
6341789Sahrens
6342789Sahrens if (tabptr == NULL)
6343789Sahrens return (Z_INVAL);
6344789Sahrens
6345789Sahrens if ((err = operation_prep(handle)) != Z_OK)
6346789Sahrens return (err);
6347789Sahrens
6348789Sahrens if ((err = zonecfg_add_ds_core(handle, tabptr)) != Z_OK)
6349789Sahrens return (err);
6350789Sahrens
6351789Sahrens return (Z_OK);
6352789Sahrens }
6353789Sahrens
6354789Sahrens static int
zonecfg_delete_ds_core(zone_dochandle_t handle,struct zone_dstab * tabptr)6355789Sahrens zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr)
6356789Sahrens {
6357789Sahrens xmlNodePtr cur = handle->zone_dh_cur;
6358789Sahrens
6359789Sahrens for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6360789Sahrens if (xmlStrcmp(cur->name, DTD_ELEM_DATASET))
6361789Sahrens continue;
6362789Sahrens
6363789Sahrens if (match_prop(cur, DTD_ATTR_NAME,
6364789Sahrens tabptr->zone_dataset_name)) {
6365789Sahrens xmlUnlinkNode(cur);
6366789Sahrens xmlFreeNode(cur);
6367789Sahrens return (Z_OK);
6368789Sahrens }
6369789Sahrens }
6370789Sahrens return (Z_NO_RESOURCE_ID);
6371789Sahrens }
6372789Sahrens
6373789Sahrens int
zonecfg_delete_ds(zone_dochandle_t handle,struct zone_dstab * tabptr)6374789Sahrens zonecfg_delete_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
6375789Sahrens {
6376789Sahrens int err;
6377789Sahrens
6378789Sahrens if (tabptr == NULL)
6379789Sahrens return (Z_INVAL);
6380789Sahrens
6381789Sahrens if ((err = operation_prep(handle)) != Z_OK)
6382789Sahrens return (err);
6383789Sahrens
6384789Sahrens if ((err = zonecfg_delete_ds_core(handle, tabptr)) != Z_OK)
6385789Sahrens return (err);
6386789Sahrens
6387789Sahrens return (Z_OK);
6388789Sahrens }
6389789Sahrens
6390789Sahrens int
zonecfg_modify_ds(zone_dochandle_t handle,struct zone_dstab * oldtabptr,struct zone_dstab * newtabptr)6391789Sahrens zonecfg_modify_ds(
6392789Sahrens zone_dochandle_t handle,
6393789Sahrens struct zone_dstab *oldtabptr,
6394789Sahrens struct zone_dstab *newtabptr)
6395789Sahrens {
6396789Sahrens int err;
6397789Sahrens
6398789Sahrens if (oldtabptr == NULL || newtabptr == NULL)
6399789Sahrens return (Z_INVAL);
6400789Sahrens
6401789Sahrens if ((err = operation_prep(handle)) != Z_OK)
6402789Sahrens return (err);
6403789Sahrens
6404789Sahrens if ((err = zonecfg_delete_ds_core(handle, oldtabptr)) != Z_OK)
6405789Sahrens return (err);
6406789Sahrens
6407789Sahrens if ((err = zonecfg_add_ds_core(handle, newtabptr)) != Z_OK)
6408789Sahrens return (err);
6409789Sahrens
6410789Sahrens return (Z_OK);
6411789Sahrens }
6412789Sahrens
6413789Sahrens int
zonecfg_lookup_ds(zone_dochandle_t handle,struct zone_dstab * tabptr)6414789Sahrens zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr)
6415789Sahrens {
6416789Sahrens xmlNodePtr cur, firstmatch;
6417789Sahrens int err;
6418789Sahrens char dataset[MAXNAMELEN];
6419789Sahrens
6420789Sahrens if (tabptr == NULL)
6421789Sahrens return (Z_INVAL);
6422789Sahrens
6423789Sahrens if ((err = operation_prep(handle)) != Z_OK)
6424789Sahrens return (err);
6425789Sahrens
6426789Sahrens cur = handle->zone_dh_cur;
6427789Sahrens firstmatch = NULL;
6428789Sahrens for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6429789Sahrens if (xmlStrcmp(cur->name, DTD_ELEM_DATASET))
6430789Sahrens continue;
6431789Sahrens if (strlen(tabptr->zone_dataset_name) > 0) {
6432789Sahrens if ((fetchprop(cur, DTD_ATTR_NAME, dataset,
6433789Sahrens sizeof (dataset)) == Z_OK) &&
6434789Sahrens (strcmp(tabptr->zone_dataset_name,
6435789Sahrens dataset) == 0)) {
6436789Sahrens if (firstmatch == NULL)
6437789Sahrens firstmatch = cur;
6438789Sahrens else
6439789Sahrens return (Z_INSUFFICIENT_SPEC);
6440789Sahrens }
6441789Sahrens }
6442789Sahrens }
6443789Sahrens if (firstmatch == NULL)
6444789Sahrens return (Z_NO_RESOURCE_ID);
6445789Sahrens
6446789Sahrens cur = firstmatch;
6447789Sahrens
6448789Sahrens if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
6449789Sahrens sizeof (tabptr->zone_dataset_name))) != Z_OK)
6450789Sahrens return (err);
6451789Sahrens
6452789Sahrens return (Z_OK);
6453789Sahrens }
6454789Sahrens
6455789Sahrens int
zonecfg_setdsent(zone_dochandle_t handle)6456789Sahrens zonecfg_setdsent(zone_dochandle_t handle)
6457789Sahrens {
6458789Sahrens return (zonecfg_setent(handle));
6459789Sahrens }
6460789Sahrens
6461789Sahrens int
zonecfg_getdsent(zone_dochandle_t handle,struct zone_dstab * tabptr)6462789Sahrens zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr)
6463789Sahrens {
6464789Sahrens xmlNodePtr cur;
6465789Sahrens int err;
6466789Sahrens
6467789Sahrens if (handle == NULL)
6468789Sahrens return (Z_INVAL);
6469789Sahrens
6470789Sahrens if ((cur = handle->zone_dh_cur) == NULL)
6471789Sahrens return (Z_NO_ENTRY);
6472789Sahrens
6473789Sahrens for (; cur != NULL; cur = cur->next)
6474789Sahrens if (!xmlStrcmp(cur->name, DTD_ELEM_DATASET))
6475789Sahrens break;
6476789Sahrens if (cur == NULL) {
6477789Sahrens handle->zone_dh_cur = handle->zone_dh_top;
6478789Sahrens return (Z_NO_ENTRY);
6479789Sahrens }
6480789Sahrens
6481789Sahrens if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name,
6482789Sahrens sizeof (tabptr->zone_dataset_name))) != Z_OK) {
6483789Sahrens handle->zone_dh_cur = handle->zone_dh_top;
6484789Sahrens return (err);
6485789Sahrens }
6486789Sahrens
6487789Sahrens handle->zone_dh_cur = cur->next;
6488789Sahrens return (Z_OK);
6489789Sahrens }
6490789Sahrens
6491789Sahrens int
zonecfg_enddsent(zone_dochandle_t handle)6492789Sahrens zonecfg_enddsent(zone_dochandle_t handle)
6493789Sahrens {
6494789Sahrens return (zonecfg_endent(handle));
6495789Sahrens }
64961507Sgjelinek
64973247Sgjelinek /*
64983247Sgjelinek * Support for aliased rctls; that is, rctls that have simplified names in
64993247Sgjelinek * zonecfg. For example, max-lwps is an alias for a well defined zone.max-lwps
65003247Sgjelinek * rctl. If there are multiple existing values for one of these rctls or if
65013247Sgjelinek * there is a single value that does not match the well defined template (i.e.
65023247Sgjelinek * it has a different action) then we cannot treat the rctl as having an alias
65033247Sgjelinek * so we return Z_ALIAS_DISALLOW. That means that the rctl cannot be
65043247Sgjelinek * managed in zonecfg via an alias and that the standard rctl syntax must be
65053247Sgjelinek * used.
65063247Sgjelinek *
65073247Sgjelinek * The possible return values are:
65083247Sgjelinek * Z_NO_PROPERTY_ID - invalid alias name
65093247Sgjelinek * Z_ALIAS_DISALLOW - pre-existing, incompatible rctl definition
65103247Sgjelinek * Z_NO_ENTRY - no rctl is configured for this alias
65113247Sgjelinek * Z_OK - we got a valid rctl for the specified alias
65123247Sgjelinek */
65133247Sgjelinek int
zonecfg_get_aliased_rctl(zone_dochandle_t handle,char * name,uint64_t * rval)65143247Sgjelinek zonecfg_get_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t *rval)
65153247Sgjelinek {
65163247Sgjelinek boolean_t found = B_FALSE;
65173247Sgjelinek boolean_t found_val = B_FALSE;
65183247Sgjelinek xmlNodePtr cur, val;
65193247Sgjelinek char savedname[MAXNAMELEN];
65203247Sgjelinek struct zone_rctlvaltab rctl;
65213247Sgjelinek int i;
65223247Sgjelinek int err;
65233247Sgjelinek
65243247Sgjelinek for (i = 0; aliases[i].shortname != NULL; i++)
65253247Sgjelinek if (strcmp(name, aliases[i].shortname) == 0)
65263247Sgjelinek break;
65273247Sgjelinek
65283247Sgjelinek if (aliases[i].shortname == NULL)
65293247Sgjelinek return (Z_NO_PROPERTY_ID);
65303247Sgjelinek
65313247Sgjelinek if ((err = operation_prep(handle)) != Z_OK)
65323247Sgjelinek return (err);
65333247Sgjelinek
65343247Sgjelinek cur = handle->zone_dh_cur;
65353247Sgjelinek for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
65363247Sgjelinek if (xmlStrcmp(cur->name, DTD_ELEM_RCTL) != 0)
65373247Sgjelinek continue;
65383247Sgjelinek if ((fetchprop(cur, DTD_ATTR_NAME, savedname,
65393247Sgjelinek sizeof (savedname)) == Z_OK) &&
65403247Sgjelinek (strcmp(savedname, aliases[i].realname) == 0)) {
65413247Sgjelinek
65423247Sgjelinek /*
65433247Sgjelinek * If we already saw one of these, we can't have an
65443247Sgjelinek * alias since we just found another.
65453247Sgjelinek */
65463247Sgjelinek if (found)
65473247Sgjelinek return (Z_ALIAS_DISALLOW);
65483247Sgjelinek found = B_TRUE;
65493247Sgjelinek
65503247Sgjelinek for (val = cur->xmlChildrenNode; val != NULL;
65513247Sgjelinek val = val->next) {
65523247Sgjelinek /*
65533247Sgjelinek * If we already have one value, we can't have
65543247Sgjelinek * an alias since we just found another.
65553247Sgjelinek */
65563247Sgjelinek if (found_val)
65573247Sgjelinek return (Z_ALIAS_DISALLOW);
65583247Sgjelinek found_val = B_TRUE;
65593247Sgjelinek
65603247Sgjelinek if ((fetchprop(val, DTD_ATTR_PRIV,
65613247Sgjelinek rctl.zone_rctlval_priv,
65623247Sgjelinek sizeof (rctl.zone_rctlval_priv)) != Z_OK))
65633247Sgjelinek break;
65643247Sgjelinek if ((fetchprop(val, DTD_ATTR_LIMIT,
65653247Sgjelinek rctl.zone_rctlval_limit,
65663247Sgjelinek sizeof (rctl.zone_rctlval_limit)) != Z_OK))
65673247Sgjelinek break;
65683247Sgjelinek if ((fetchprop(val, DTD_ATTR_ACTION,
65693247Sgjelinek rctl.zone_rctlval_action,
65703247Sgjelinek sizeof (rctl.zone_rctlval_action)) != Z_OK))
65713247Sgjelinek break;
65723247Sgjelinek }
65733247Sgjelinek
65743247Sgjelinek /* check priv and action match the expected vals */
65753247Sgjelinek if (strcmp(rctl.zone_rctlval_priv,
65763247Sgjelinek aliases[i].priv) != 0 ||
65773247Sgjelinek strcmp(rctl.zone_rctlval_action,
65783247Sgjelinek aliases[i].action) != 0)
65793247Sgjelinek return (Z_ALIAS_DISALLOW);
65803247Sgjelinek }
65813247Sgjelinek }
65823247Sgjelinek
65833247Sgjelinek if (found) {
65843247Sgjelinek *rval = strtoull(rctl.zone_rctlval_limit, NULL, 10);
65853247Sgjelinek return (Z_OK);
65863247Sgjelinek }
65873247Sgjelinek
65883247Sgjelinek return (Z_NO_ENTRY);
65893247Sgjelinek }
65903247Sgjelinek
65913247Sgjelinek int
zonecfg_rm_aliased_rctl(zone_dochandle_t handle,char * name)65923247Sgjelinek zonecfg_rm_aliased_rctl(zone_dochandle_t handle, char *name)
65933247Sgjelinek {
65943247Sgjelinek int i;
65953247Sgjelinek uint64_t val;
65963247Sgjelinek struct zone_rctltab rctltab;
65973247Sgjelinek
65983247Sgjelinek /*
65993247Sgjelinek * First check that we have a valid aliased rctl to remove.
66003247Sgjelinek * This will catch an rctl entry with non-standard values or
66013247Sgjelinek * multiple rctl values for this name. We need to ignore those
66023247Sgjelinek * rctl entries.
66033247Sgjelinek */
66043247Sgjelinek if (zonecfg_get_aliased_rctl(handle, name, &val) != Z_OK)
66053247Sgjelinek return (Z_OK);
66063247Sgjelinek
66073247Sgjelinek for (i = 0; aliases[i].shortname != NULL; i++)
66083247Sgjelinek if (strcmp(name, aliases[i].shortname) == 0)
66093247Sgjelinek break;
66103247Sgjelinek
66113247Sgjelinek if (aliases[i].shortname == NULL)
66123247Sgjelinek return (Z_NO_RESOURCE_ID);
66133247Sgjelinek
66143247Sgjelinek (void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname,
66153247Sgjelinek sizeof (rctltab.zone_rctl_name));
66163247Sgjelinek
66173247Sgjelinek return (zonecfg_delete_rctl(handle, &rctltab));
66183247Sgjelinek }
66193247Sgjelinek
66203247Sgjelinek boolean_t
zonecfg_aliased_rctl_ok(zone_dochandle_t handle,char * name)66213247Sgjelinek zonecfg_aliased_rctl_ok(zone_dochandle_t handle, char *name)
66223247Sgjelinek {
66233247Sgjelinek uint64_t tmp_val;
66243247Sgjelinek
66253247Sgjelinek switch (zonecfg_get_aliased_rctl(handle, name, &tmp_val)) {
66263247Sgjelinek case Z_OK:
66273247Sgjelinek /*FALLTHRU*/
66283247Sgjelinek case Z_NO_ENTRY:
66293247Sgjelinek return (B_TRUE);
66303247Sgjelinek default:
66313247Sgjelinek return (B_FALSE);
66323247Sgjelinek }
66333247Sgjelinek }
66343247Sgjelinek
66353247Sgjelinek int
zonecfg_set_aliased_rctl(zone_dochandle_t handle,char * name,uint64_t val)66363247Sgjelinek zonecfg_set_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t val)
66373247Sgjelinek {
66383247Sgjelinek int i;
66393247Sgjelinek int err;
66403247Sgjelinek struct zone_rctltab rctltab;
66413247Sgjelinek struct zone_rctlvaltab *rctlvaltab;
66423247Sgjelinek char buf[128];
66433247Sgjelinek
66443247Sgjelinek if (!zonecfg_aliased_rctl_ok(handle, name))
66453247Sgjelinek return (Z_ALIAS_DISALLOW);
66463247Sgjelinek
66473247Sgjelinek for (i = 0; aliases[i].shortname != NULL; i++)
66483247Sgjelinek if (strcmp(name, aliases[i].shortname) == 0)
66493247Sgjelinek break;
66503247Sgjelinek
66513247Sgjelinek if (aliases[i].shortname == NULL)
66523247Sgjelinek return (Z_NO_RESOURCE_ID);
66533247Sgjelinek
66543247Sgjelinek /* remove any pre-existing definition for this rctl */
66553247Sgjelinek (void) zonecfg_rm_aliased_rctl(handle, name);
66563247Sgjelinek
66573247Sgjelinek (void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname,
66583247Sgjelinek sizeof (rctltab.zone_rctl_name));
66593247Sgjelinek
66603247Sgjelinek rctltab.zone_rctl_valptr = NULL;
66613247Sgjelinek
66623247Sgjelinek if ((rctlvaltab = calloc(1, sizeof (struct zone_rctlvaltab))) == NULL)
66633247Sgjelinek return (Z_NOMEM);
66643247Sgjelinek
66653247Sgjelinek (void) snprintf(buf, sizeof (buf), "%llu", (long long)val);
66663247Sgjelinek
66673247Sgjelinek (void) strlcpy(rctlvaltab->zone_rctlval_priv, aliases[i].priv,
66683247Sgjelinek sizeof (rctlvaltab->zone_rctlval_priv));
66693247Sgjelinek (void) strlcpy(rctlvaltab->zone_rctlval_limit, buf,
66703247Sgjelinek sizeof (rctlvaltab->zone_rctlval_limit));
66713247Sgjelinek (void) strlcpy(rctlvaltab->zone_rctlval_action, aliases[i].action,
66723247Sgjelinek sizeof (rctlvaltab->zone_rctlval_action));
66733247Sgjelinek
66743247Sgjelinek rctlvaltab->zone_rctlval_next = NULL;
66753247Sgjelinek
66763247Sgjelinek if ((err = zonecfg_add_rctl_value(&rctltab, rctlvaltab)) != Z_OK)
66773247Sgjelinek return (err);
66783247Sgjelinek
66793247Sgjelinek return (zonecfg_add_rctl(handle, &rctltab));
66803247Sgjelinek }
66813247Sgjelinek
66823247Sgjelinek static int
delete_tmp_pool(zone_dochandle_t handle)66833247Sgjelinek delete_tmp_pool(zone_dochandle_t handle)
66843247Sgjelinek {
66853247Sgjelinek int err;
66863247Sgjelinek xmlNodePtr cur = handle->zone_dh_cur;
66873247Sgjelinek
66883247Sgjelinek if ((err = operation_prep(handle)) != Z_OK)
66893247Sgjelinek return (err);
66903247Sgjelinek
66913247Sgjelinek for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
66923247Sgjelinek if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) {
66933247Sgjelinek xmlUnlinkNode(cur);
66943247Sgjelinek xmlFreeNode(cur);
66953247Sgjelinek return (Z_OK);
66963247Sgjelinek }
66973247Sgjelinek }
66983247Sgjelinek
66993247Sgjelinek return (Z_NO_RESOURCE_ID);
67003247Sgjelinek }
67013247Sgjelinek
67023247Sgjelinek static int
modify_tmp_pool(zone_dochandle_t handle,char * pool_importance)67033247Sgjelinek modify_tmp_pool(zone_dochandle_t handle, char *pool_importance)
67043247Sgjelinek {
67053247Sgjelinek int err;
67063247Sgjelinek xmlNodePtr cur = handle->zone_dh_cur;
67073247Sgjelinek xmlNodePtr newnode;
67083247Sgjelinek
67093247Sgjelinek err = delete_tmp_pool(handle);
67103247Sgjelinek if (err != Z_OK && err != Z_NO_RESOURCE_ID)
67113247Sgjelinek return (err);
67123247Sgjelinek
67133247Sgjelinek if (*pool_importance != '\0') {
67143247Sgjelinek if ((err = operation_prep(handle)) != Z_OK)
67153247Sgjelinek return (err);
67163247Sgjelinek
67173247Sgjelinek newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_TMPPOOL, NULL);
67183247Sgjelinek if ((err = newprop(newnode, DTD_ATTR_IMPORTANCE,
67193247Sgjelinek pool_importance)) != Z_OK)
67203247Sgjelinek return (err);
67213247Sgjelinek }
67223247Sgjelinek
67233247Sgjelinek return (Z_OK);
67243247Sgjelinek }
67253247Sgjelinek
67263247Sgjelinek static int
add_pset_core(zone_dochandle_t handle,struct zone_psettab * tabptr)67273247Sgjelinek add_pset_core(zone_dochandle_t handle, struct zone_psettab *tabptr)
67283247Sgjelinek {
67293247Sgjelinek xmlNodePtr newnode, cur = handle->zone_dh_cur;
67303247Sgjelinek int err;
67313247Sgjelinek
67323247Sgjelinek newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PSET, NULL);
67333247Sgjelinek if ((err = newprop(newnode, DTD_ATTR_NCPU_MIN,
67343247Sgjelinek tabptr->zone_ncpu_min)) != Z_OK)
67353247Sgjelinek return (err);
67363247Sgjelinek if ((err = newprop(newnode, DTD_ATTR_NCPU_MAX,
67373247Sgjelinek tabptr->zone_ncpu_max)) != Z_OK)
67383247Sgjelinek return (err);
67393247Sgjelinek
67403247Sgjelinek if ((err = modify_tmp_pool(handle, tabptr->zone_importance)) != Z_OK)
67413247Sgjelinek return (err);
67423247Sgjelinek
67433247Sgjelinek return (Z_OK);
67443247Sgjelinek }
67453247Sgjelinek
67463247Sgjelinek int
zonecfg_add_pset(zone_dochandle_t handle,struct zone_psettab * tabptr)67473247Sgjelinek zonecfg_add_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
67483247Sgjelinek {
67493247Sgjelinek int err;
67503247Sgjelinek
67513247Sgjelinek if (tabptr == NULL)
67523247Sgjelinek return (Z_INVAL);
67533247Sgjelinek
67543247Sgjelinek if ((err = operation_prep(handle)) != Z_OK)
67553247Sgjelinek return (err);
67563247Sgjelinek
67573247Sgjelinek if ((err = add_pset_core(handle, tabptr)) != Z_OK)
67583247Sgjelinek return (err);
67593247Sgjelinek
67603247Sgjelinek return (Z_OK);
67613247Sgjelinek }
67623247Sgjelinek
67633247Sgjelinek int
zonecfg_delete_pset(zone_dochandle_t handle)67643247Sgjelinek zonecfg_delete_pset(zone_dochandle_t handle)
67653247Sgjelinek {
67663247Sgjelinek int err;
67673247Sgjelinek int res = Z_NO_RESOURCE_ID;
67683247Sgjelinek xmlNodePtr cur = handle->zone_dh_cur;
67693247Sgjelinek
67703247Sgjelinek if ((err = operation_prep(handle)) != Z_OK)
67713247Sgjelinek return (err);
67723247Sgjelinek
67733247Sgjelinek for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
67743247Sgjelinek if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) {
67753247Sgjelinek xmlUnlinkNode(cur);
67763247Sgjelinek xmlFreeNode(cur);
67773247Sgjelinek res = Z_OK;
67783247Sgjelinek break;
67793247Sgjelinek }
67803247Sgjelinek }
67813247Sgjelinek
67823247Sgjelinek /*
67833247Sgjelinek * Once we have msets, we should check that a mset
67843247Sgjelinek * do not exist before we delete the tmp_pool data.
67853247Sgjelinek */
67863247Sgjelinek err = delete_tmp_pool(handle);
67873247Sgjelinek if (err != Z_OK && err != Z_NO_RESOURCE_ID)
67883247Sgjelinek return (err);
67893247Sgjelinek
67903247Sgjelinek return (res);
67913247Sgjelinek }
67923247Sgjelinek
67933247Sgjelinek int
zonecfg_modify_pset(zone_dochandle_t handle,struct zone_psettab * tabptr)67943247Sgjelinek zonecfg_modify_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
67953247Sgjelinek {
67963247Sgjelinek int err;
67973247Sgjelinek
67983247Sgjelinek if (tabptr == NULL)
67993247Sgjelinek return (Z_INVAL);
68003247Sgjelinek
68013247Sgjelinek if ((err = zonecfg_delete_pset(handle)) != Z_OK)
68023247Sgjelinek return (err);
68033247Sgjelinek
68043247Sgjelinek if ((err = add_pset_core(handle, tabptr)) != Z_OK)
68053247Sgjelinek return (err);
68063247Sgjelinek
68073247Sgjelinek return (Z_OK);
68083247Sgjelinek }
68093247Sgjelinek
68103247Sgjelinek int
zonecfg_lookup_pset(zone_dochandle_t handle,struct zone_psettab * tabptr)68113247Sgjelinek zonecfg_lookup_pset(zone_dochandle_t handle, struct zone_psettab *tabptr)
68123247Sgjelinek {
68133247Sgjelinek xmlNodePtr cur;
68143247Sgjelinek int err;
68153247Sgjelinek int res = Z_NO_ENTRY;
68163247Sgjelinek
68173247Sgjelinek if (tabptr == NULL)
68183247Sgjelinek return (Z_INVAL);
68193247Sgjelinek
68203247Sgjelinek if ((err = operation_prep(handle)) != Z_OK)
68213247Sgjelinek return (err);
68223247Sgjelinek
68233247Sgjelinek /* this is an optional component */
68243247Sgjelinek tabptr->zone_importance[0] = '\0';
68253247Sgjelinek
68263247Sgjelinek cur = handle->zone_dh_cur;
68273247Sgjelinek for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
68283247Sgjelinek if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) {
68293247Sgjelinek if ((err = fetchprop(cur, DTD_ATTR_NCPU_MIN,
68303247Sgjelinek tabptr->zone_ncpu_min,
68313247Sgjelinek sizeof (tabptr->zone_ncpu_min))) != Z_OK) {
68323247Sgjelinek handle->zone_dh_cur = handle->zone_dh_top;
68333247Sgjelinek return (err);
68343247Sgjelinek }
68353247Sgjelinek
68363247Sgjelinek if ((err = fetchprop(cur, DTD_ATTR_NCPU_MAX,
68373247Sgjelinek tabptr->zone_ncpu_max,
68383247Sgjelinek sizeof (tabptr->zone_ncpu_max))) != Z_OK) {
68393247Sgjelinek handle->zone_dh_cur = handle->zone_dh_top;
68403247Sgjelinek return (err);
68413247Sgjelinek }
68423247Sgjelinek
68433247Sgjelinek res = Z_OK;
68443247Sgjelinek
68453247Sgjelinek } else if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) {
68463247Sgjelinek if ((err = fetchprop(cur, DTD_ATTR_IMPORTANCE,
68473247Sgjelinek tabptr->zone_importance,
68483247Sgjelinek sizeof (tabptr->zone_importance))) != Z_OK) {
68493247Sgjelinek handle->zone_dh_cur = handle->zone_dh_top;
68503247Sgjelinek return (err);
68513247Sgjelinek }
68523247Sgjelinek }
68533247Sgjelinek }
68543247Sgjelinek
68553247Sgjelinek return (res);
68563247Sgjelinek }
68573247Sgjelinek
68583247Sgjelinek int
zonecfg_getpsetent(zone_dochandle_t handle,struct zone_psettab * tabptr)68593247Sgjelinek zonecfg_getpsetent(zone_dochandle_t handle, struct zone_psettab *tabptr)
68603247Sgjelinek {
68613247Sgjelinek int err;
68623247Sgjelinek
68633247Sgjelinek if ((err = zonecfg_setent(handle)) != Z_OK)
68643247Sgjelinek return (err);
68653247Sgjelinek
68663247Sgjelinek err = zonecfg_lookup_pset(handle, tabptr);
68673247Sgjelinek
68683247Sgjelinek (void) zonecfg_endent(handle);
68693247Sgjelinek
68703247Sgjelinek return (err);
68713247Sgjelinek }
68723247Sgjelinek
68733247Sgjelinek static int
add_mcap(zone_dochandle_t handle,struct zone_mcaptab * tabptr)68743247Sgjelinek add_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
68753247Sgjelinek {
68763247Sgjelinek xmlNodePtr newnode, cur = handle->zone_dh_cur;
68773247Sgjelinek int err;
68783247Sgjelinek
68793247Sgjelinek newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_MCAP, NULL);
68803247Sgjelinek if ((err = newprop(newnode, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap))
68813247Sgjelinek != Z_OK)
68823247Sgjelinek return (err);
68833247Sgjelinek
68843247Sgjelinek return (Z_OK);
68853247Sgjelinek }
68863247Sgjelinek
68873247Sgjelinek int
zonecfg_delete_mcap(zone_dochandle_t handle)68883247Sgjelinek zonecfg_delete_mcap(zone_dochandle_t handle)
68893247Sgjelinek {
68903247Sgjelinek int err;
68913247Sgjelinek xmlNodePtr cur = handle->zone_dh_cur;
68923247Sgjelinek
68933247Sgjelinek if ((err = operation_prep(handle)) != Z_OK)
68943247Sgjelinek return (err);
68953247Sgjelinek
68963247Sgjelinek for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
68973247Sgjelinek if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
68983247Sgjelinek continue;
68993247Sgjelinek
69003247Sgjelinek xmlUnlinkNode(cur);
69013247Sgjelinek xmlFreeNode(cur);
69023247Sgjelinek return (Z_OK);
69033247Sgjelinek }
69043247Sgjelinek return (Z_NO_RESOURCE_ID);
69053247Sgjelinek }
69063247Sgjelinek
69073247Sgjelinek int
zonecfg_modify_mcap(zone_dochandle_t handle,struct zone_mcaptab * tabptr)69083247Sgjelinek zonecfg_modify_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
69093247Sgjelinek {
69103247Sgjelinek int err;
69113247Sgjelinek
69123247Sgjelinek if (tabptr == NULL)
69133247Sgjelinek return (Z_INVAL);
69143247Sgjelinek
69153247Sgjelinek err = zonecfg_delete_mcap(handle);
69163247Sgjelinek /* it is ok if there is no mcap entry */
69173247Sgjelinek if (err != Z_OK && err != Z_NO_RESOURCE_ID)
69183247Sgjelinek return (err);
69193247Sgjelinek
69203247Sgjelinek if ((err = add_mcap(handle, tabptr)) != Z_OK)
69213247Sgjelinek return (err);
69223247Sgjelinek
69233247Sgjelinek return (Z_OK);
69243247Sgjelinek }
69253247Sgjelinek
69263247Sgjelinek int
zonecfg_lookup_mcap(zone_dochandle_t handle,struct zone_mcaptab * tabptr)69273247Sgjelinek zonecfg_lookup_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
69283247Sgjelinek {
69293247Sgjelinek xmlNodePtr cur;
69303247Sgjelinek int err;
69313247Sgjelinek
69323247Sgjelinek if (tabptr == NULL)
69333247Sgjelinek return (Z_INVAL);
69343247Sgjelinek
69353247Sgjelinek if ((err = operation_prep(handle)) != Z_OK)
69363247Sgjelinek return (err);
69373247Sgjelinek
69383247Sgjelinek cur = handle->zone_dh_cur;
69393247Sgjelinek for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
69403247Sgjelinek if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
69413247Sgjelinek continue;
69423247Sgjelinek if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP,
69433247Sgjelinek tabptr->zone_physmem_cap,
69443247Sgjelinek sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
69453247Sgjelinek handle->zone_dh_cur = handle->zone_dh_top;
69463247Sgjelinek return (err);
69473247Sgjelinek }
69483247Sgjelinek
69493247Sgjelinek return (Z_OK);
69503247Sgjelinek }
69513247Sgjelinek
69523247Sgjelinek return (Z_NO_ENTRY);
69533247Sgjelinek }
69543247Sgjelinek
69553247Sgjelinek static int
getmcapent_core(zone_dochandle_t handle,struct zone_mcaptab * tabptr)69563247Sgjelinek getmcapent_core(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
69573247Sgjelinek {
69583247Sgjelinek xmlNodePtr cur;
69593247Sgjelinek int err;
69603247Sgjelinek
69613247Sgjelinek if (handle == NULL)
69623247Sgjelinek return (Z_INVAL);
69633247Sgjelinek
69643247Sgjelinek if ((cur = handle->zone_dh_cur) == NULL)
69653247Sgjelinek return (Z_NO_ENTRY);
69663247Sgjelinek
69673247Sgjelinek for (; cur != NULL; cur = cur->next)
69683247Sgjelinek if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) == 0)
69693247Sgjelinek break;
69703247Sgjelinek if (cur == NULL) {
69713247Sgjelinek handle->zone_dh_cur = handle->zone_dh_top;
69723247Sgjelinek return (Z_NO_ENTRY);
69733247Sgjelinek }
69743247Sgjelinek
69753247Sgjelinek if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap,
69763247Sgjelinek sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
69773247Sgjelinek handle->zone_dh_cur = handle->zone_dh_top;
69783247Sgjelinek return (err);
69793247Sgjelinek }
69803247Sgjelinek
69813247Sgjelinek handle->zone_dh_cur = cur->next;
69823247Sgjelinek return (Z_OK);
69833247Sgjelinek }
69843247Sgjelinek
69853247Sgjelinek int
zonecfg_getmcapent(zone_dochandle_t handle,struct zone_mcaptab * tabptr)69863247Sgjelinek zonecfg_getmcapent(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
69873247Sgjelinek {
69883247Sgjelinek int err;
69893247Sgjelinek
69903247Sgjelinek if ((err = zonecfg_setent(handle)) != Z_OK)
69913247Sgjelinek return (err);
69923247Sgjelinek
69933247Sgjelinek err = getmcapent_core(handle, tabptr);
69943247Sgjelinek
69953247Sgjelinek (void) zonecfg_endent(handle);
69963247Sgjelinek
69973247Sgjelinek return (err);
69983247Sgjelinek }
69993247Sgjelinek
70005829Sgjelinek /*
70015829Sgjelinek * Get the full tree of pkg/patch metadata in a set of nested AVL trees.
70025829Sgjelinek * pkgs_avl is an AVL tree of pkgs. Each pkg element contains a
70035829Sgjelinek * zpe_patches_avl member which holds an AVL tree of patches for that pkg.
70045829Sgjelinek * The patch elements have the same zpe_patches_avl member, each of which can
70055829Sgjelinek * hold an AVL tree of patches that are obsoleted by the patch.
70065829Sgjelinek *
70075829Sgjelinek * The zone xml data contains DTD_ELEM_PACKAGE elements, followed by
70085829Sgjelinek * DTD_ELEM_PATCH elements. The DTD_ELEM_PATCH patch element applies to the
70095829Sgjelinek * DTD_ELEM_PACKAGE that precedes it. The DTD_ELEM_PATCH element may have
70105829Sgjelinek * child DTD_ELEM_OBSOLETES nodes associated with it. The DTD_ELEM_PACKAGE
70115829Sgjelinek * really should have had the DTD_ELEM_PATCH elements as children but it
70125829Sgjelinek * was not defined that way initially so we are stuck with the DTD definition
70135829Sgjelinek * now. However, we can safely assume the ordering for compatibility.
70145829Sgjelinek */
70155829Sgjelinek int
zonecfg_getpkgdata(zone_dochandle_t handle,uu_avl_pool_t * pkg_pool,uu_avl_t * pkgs_avl)70165829Sgjelinek zonecfg_getpkgdata(zone_dochandle_t handle, uu_avl_pool_t *pkg_pool,
70175829Sgjelinek uu_avl_t *pkgs_avl)
70181507Sgjelinek {
70191507Sgjelinek xmlNodePtr cur;
70205829Sgjelinek int res;
70215829Sgjelinek zone_pkg_entry_t *pkg;
70225829Sgjelinek char name[MAXNAMELEN];
70235829Sgjelinek char version[ZONE_PKG_VERSMAX];
70241507Sgjelinek
70251507Sgjelinek if (handle == NULL)
70261507Sgjelinek return (Z_INVAL);
70271507Sgjelinek
70285829Sgjelinek if ((res = zonecfg_setent(handle)) != Z_OK)
70295829Sgjelinek return (res);
70305829Sgjelinek
70315829Sgjelinek if ((cur = handle->zone_dh_cur) == NULL) {
70325829Sgjelinek res = Z_NO_ENTRY;
70335829Sgjelinek goto done;
70345829Sgjelinek }
70355829Sgjelinek
70365829Sgjelinek for (; cur != NULL; cur = cur->next) {
70375829Sgjelinek if (xmlStrcmp(cur->name, DTD_ELEM_PACKAGE) == 0) {
70385829Sgjelinek uu_avl_index_t where;
70395829Sgjelinek
70405829Sgjelinek if ((res = fetchprop(cur, DTD_ATTR_NAME, name,
70415829Sgjelinek sizeof (name))) != Z_OK)
70425829Sgjelinek goto done;
70435829Sgjelinek
70445829Sgjelinek if ((res = fetchprop(cur, DTD_ATTR_VERSION, version,
70455829Sgjelinek sizeof (version))) != Z_OK)
70465829Sgjelinek goto done;
70475829Sgjelinek
70485829Sgjelinek if ((pkg = (zone_pkg_entry_t *)
70495829Sgjelinek malloc(sizeof (zone_pkg_entry_t))) == NULL) {
70505829Sgjelinek res = Z_NOMEM;
70515829Sgjelinek goto done;
70525829Sgjelinek }
70535829Sgjelinek
70545829Sgjelinek if ((pkg->zpe_name = strdup(name)) == NULL) {
70555829Sgjelinek free(pkg);
70565829Sgjelinek res = Z_NOMEM;
70575829Sgjelinek goto done;
70585829Sgjelinek }
70595829Sgjelinek
70605829Sgjelinek if ((pkg->zpe_vers = strdup(version)) == NULL) {
70615829Sgjelinek free(pkg->zpe_name);
70625829Sgjelinek free(pkg);
70635829Sgjelinek res = Z_NOMEM;
70645829Sgjelinek goto done;
70655829Sgjelinek }
70665829Sgjelinek
70675829Sgjelinek pkg->zpe_patches_avl = NULL;
70685829Sgjelinek
70695829Sgjelinek uu_avl_node_init(pkg, &pkg->zpe_entry, pkg_pool);
70705829Sgjelinek if (uu_avl_find(pkgs_avl, pkg, NULL, &where) != NULL) {
70715829Sgjelinek free(pkg->zpe_name);
70725829Sgjelinek free(pkg->zpe_vers);
70735829Sgjelinek free(pkg);
70745829Sgjelinek } else {
70755829Sgjelinek uu_avl_insert(pkgs_avl, pkg, where);
70765829Sgjelinek }
70775829Sgjelinek
70785829Sgjelinek } else if (xmlStrcmp(cur->name, DTD_ELEM_PATCH) == 0) {
70795829Sgjelinek zone_pkg_entry_t *patch;
70805829Sgjelinek uu_avl_index_t where;
70815829Sgjelinek char *p;
70825829Sgjelinek char *dashp = NULL;
70835829Sgjelinek xmlNodePtr child;
70845829Sgjelinek
70855829Sgjelinek if ((res = fetchprop(cur, DTD_ATTR_ID, name,
70865829Sgjelinek sizeof (name))) != Z_OK)
70875829Sgjelinek goto done;
70885829Sgjelinek
70895829Sgjelinek if ((patch = (zone_pkg_entry_t *)
70905829Sgjelinek malloc(sizeof (zone_pkg_entry_t))) == NULL) {
70915829Sgjelinek res = Z_NOMEM;
70925829Sgjelinek goto done;
70935829Sgjelinek }
70945829Sgjelinek
70955829Sgjelinek if ((p = strchr(name, '-')) != NULL) {
70965829Sgjelinek dashp = p;
70975829Sgjelinek *p++ = '\0';
70985829Sgjelinek } else {
70995829Sgjelinek p = "";
71005829Sgjelinek }
71015829Sgjelinek
71025829Sgjelinek if ((patch->zpe_name = strdup(name)) == NULL) {
71035829Sgjelinek free(patch);
71045829Sgjelinek res = Z_NOMEM;
71055829Sgjelinek goto done;
71065829Sgjelinek }
71075829Sgjelinek
71085829Sgjelinek if ((patch->zpe_vers = strdup(p)) == NULL) {
71095829Sgjelinek free(patch->zpe_name);
71105829Sgjelinek free(patch);
71115829Sgjelinek res = Z_NOMEM;
71125829Sgjelinek goto done;
71135829Sgjelinek }
71145829Sgjelinek
71155829Sgjelinek if (dashp != NULL)
71165829Sgjelinek *dashp = '-';
71175829Sgjelinek
71185829Sgjelinek patch->zpe_patches_avl = NULL;
71195829Sgjelinek
71205829Sgjelinek if (pkg->zpe_patches_avl == NULL) {
71215829Sgjelinek pkg->zpe_patches_avl = uu_avl_create(pkg_pool,
71225829Sgjelinek NULL, UU_DEFAULT);
71235829Sgjelinek if (pkg->zpe_patches_avl == NULL) {
71245829Sgjelinek free(patch->zpe_name);
71255829Sgjelinek free(patch->zpe_vers);
71265829Sgjelinek free(patch);
71275829Sgjelinek res = Z_NOMEM;
71285829Sgjelinek goto done;
71295829Sgjelinek }
71305829Sgjelinek }
71315829Sgjelinek
71325829Sgjelinek uu_avl_node_init(patch, &patch->zpe_entry, pkg_pool);
71335829Sgjelinek if (uu_avl_find(pkg->zpe_patches_avl, patch, NULL,
71345829Sgjelinek &where) != NULL) {
71355829Sgjelinek free(patch->zpe_name);
71365829Sgjelinek free(patch->zpe_vers);
71375829Sgjelinek free(patch);
71385829Sgjelinek } else {
71395829Sgjelinek uu_avl_insert(pkg->zpe_patches_avl, patch,
71405829Sgjelinek where);
71415829Sgjelinek }
71425829Sgjelinek
71435829Sgjelinek /* Add any patches this patch obsoletes. */
71445829Sgjelinek for (child = cur->xmlChildrenNode; child != NULL;
71455829Sgjelinek child = child->next) {
71465829Sgjelinek zone_pkg_entry_t *obs;
71475829Sgjelinek
71485829Sgjelinek if (xmlStrcmp(child->name, DTD_ELEM_OBSOLETES)
71495829Sgjelinek != 0)
71505829Sgjelinek continue;
71515829Sgjelinek
71525829Sgjelinek if ((res = fetchprop(child, DTD_ATTR_ID,
71535829Sgjelinek name, sizeof (name))) != Z_OK)
71545829Sgjelinek goto done;
71555829Sgjelinek
71565829Sgjelinek if ((obs = (zone_pkg_entry_t *)malloc(
71575829Sgjelinek sizeof (zone_pkg_entry_t))) == NULL) {
71585829Sgjelinek res = Z_NOMEM;
71595829Sgjelinek goto done;
71605829Sgjelinek }
71615829Sgjelinek
71625829Sgjelinek if ((obs->zpe_name = strdup(name)) == NULL) {
71635829Sgjelinek free(obs);
71645829Sgjelinek res = Z_NOMEM;
71655829Sgjelinek goto done;
71665829Sgjelinek }
71675829Sgjelinek /*
71685829Sgjelinek * The version doesn't matter for obsoleted
71695829Sgjelinek * patches.
71705829Sgjelinek */
71715829Sgjelinek obs->zpe_vers = NULL;
71725829Sgjelinek obs->zpe_patches_avl = NULL;
71735829Sgjelinek
71745829Sgjelinek /*
71755829Sgjelinek * If this is the first obsolete patch, add an
71765829Sgjelinek * AVL tree to the parent patch element.
71775829Sgjelinek */
71785829Sgjelinek if (patch->zpe_patches_avl == NULL) {
71795829Sgjelinek patch->zpe_patches_avl =
71805829Sgjelinek uu_avl_create(pkg_pool, NULL,
71815829Sgjelinek UU_DEFAULT);
71825829Sgjelinek if (patch->zpe_patches_avl == NULL) {
71835829Sgjelinek free(obs->zpe_name);
71845829Sgjelinek free(obs);
71855829Sgjelinek res = Z_NOMEM;
71865829Sgjelinek goto done;
71875829Sgjelinek }
71885829Sgjelinek }
71895829Sgjelinek
71905829Sgjelinek /* Insert obsolete patch into the AVL tree. */
71915829Sgjelinek uu_avl_node_init(obs, &obs->zpe_entry,
71925829Sgjelinek pkg_pool);
71935829Sgjelinek if (uu_avl_find(patch->zpe_patches_avl, obs,
71945829Sgjelinek NULL, &where) != NULL) {
71955829Sgjelinek free(obs->zpe_name);
71965829Sgjelinek free(obs);
71975829Sgjelinek } else {
71985829Sgjelinek uu_avl_insert(patch->zpe_patches_avl,
71995829Sgjelinek obs, where);
72005829Sgjelinek }
72015829Sgjelinek }
72025829Sgjelinek }
72035829Sgjelinek }
72045829Sgjelinek
72055829Sgjelinek done:
72065829Sgjelinek (void) zonecfg_endent(handle);
72075829Sgjelinek return (res);
72081507Sgjelinek }
72091507Sgjelinek
72101507Sgjelinek int
zonecfg_setdevperment(zone_dochandle_t handle)72111507Sgjelinek zonecfg_setdevperment(zone_dochandle_t handle)
72121507Sgjelinek {
72131507Sgjelinek return (zonecfg_setent(handle));
72141507Sgjelinek }
72151507Sgjelinek
72161507Sgjelinek int
zonecfg_getdevperment(zone_dochandle_t handle,struct zone_devpermtab * tabptr)72171507Sgjelinek zonecfg_getdevperment(zone_dochandle_t handle, struct zone_devpermtab *tabptr)
72181507Sgjelinek {
72191507Sgjelinek xmlNodePtr cur;
72201507Sgjelinek int err;
72211507Sgjelinek char buf[128];
72221507Sgjelinek
72231507Sgjelinek tabptr->zone_devperm_acl = NULL;
72241507Sgjelinek
72251507Sgjelinek if (handle == NULL)
72261507Sgjelinek return (Z_INVAL);
72271507Sgjelinek
72281507Sgjelinek if ((cur = handle->zone_dh_cur) == NULL)
72291507Sgjelinek return (Z_NO_ENTRY);
72301507Sgjelinek
72311507Sgjelinek for (; cur != NULL; cur = cur->next)
72321507Sgjelinek if (!xmlStrcmp(cur->name, DTD_ELEM_DEV_PERM))
72331507Sgjelinek break;
72341507Sgjelinek if (cur == NULL) {
72351507Sgjelinek handle->zone_dh_cur = handle->zone_dh_top;
72361507Sgjelinek return (Z_NO_ENTRY);
72371507Sgjelinek }
72381507Sgjelinek
72391507Sgjelinek if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_devperm_name,
72401507Sgjelinek sizeof (tabptr->zone_devperm_name))) != Z_OK) {
72411507Sgjelinek handle->zone_dh_cur = handle->zone_dh_top;
72421507Sgjelinek return (err);
72431507Sgjelinek }
72441507Sgjelinek
72451507Sgjelinek if ((err = fetchprop(cur, DTD_ATTR_UID, buf, sizeof (buf))) != Z_OK) {
72461507Sgjelinek handle->zone_dh_cur = handle->zone_dh_top;
72471507Sgjelinek return (err);
72481507Sgjelinek }
72491507Sgjelinek tabptr->zone_devperm_uid = (uid_t)atol(buf);
72501507Sgjelinek
72511507Sgjelinek if ((err = fetchprop(cur, DTD_ATTR_GID, buf, sizeof (buf))) != Z_OK) {
72521507Sgjelinek handle->zone_dh_cur = handle->zone_dh_top;
72531507Sgjelinek return (err);
72541507Sgjelinek }
72551507Sgjelinek tabptr->zone_devperm_gid = (gid_t)atol(buf);
72561507Sgjelinek
72571507Sgjelinek if ((err = fetchprop(cur, DTD_ATTR_MODE, buf, sizeof (buf))) != Z_OK) {
72581507Sgjelinek handle->zone_dh_cur = handle->zone_dh_top;
72591507Sgjelinek return (err);
72601507Sgjelinek }
72611507Sgjelinek tabptr->zone_devperm_mode = (mode_t)strtol(buf, (char **)NULL, 8);
72621507Sgjelinek
72631507Sgjelinek if ((err = fetch_alloc_prop(cur, DTD_ATTR_ACL,
72641507Sgjelinek &(tabptr->zone_devperm_acl))) != Z_OK) {
72651507Sgjelinek handle->zone_dh_cur = handle->zone_dh_top;
72661507Sgjelinek return (err);
72671507Sgjelinek }
72681507Sgjelinek
72691507Sgjelinek handle->zone_dh_cur = cur->next;
72701507Sgjelinek return (Z_OK);
72711507Sgjelinek }
72721507Sgjelinek
72731507Sgjelinek int
zonecfg_enddevperment(zone_dochandle_t handle)72741507Sgjelinek zonecfg_enddevperment(zone_dochandle_t handle)
72751507Sgjelinek {
72761507Sgjelinek return (zonecfg_endent(handle));
72771507Sgjelinek }
72781507Sgjelinek
72797089Sgjelinek /* PRINTFLIKE1 */
72807089Sgjelinek static void
zerror(const char * zone_name,const char * fmt,...)72817089Sgjelinek zerror(const char *zone_name, const char *fmt, ...)
72827089Sgjelinek {
72837089Sgjelinek va_list alist;
72847089Sgjelinek
72857089Sgjelinek va_start(alist, fmt);
72867089Sgjelinek (void) fprintf(stderr, "zone '%s': ", zone_name);
72877089Sgjelinek (void) vfprintf(stderr, fmt, alist);
72887089Sgjelinek (void) fprintf(stderr, "\n");
72897089Sgjelinek va_end(alist);
72901507Sgjelinek }
72911507Sgjelinek
72921507Sgjelinek static void
zperror(const char * str)72937089Sgjelinek zperror(const char *str)
72947089Sgjelinek {
72957089Sgjelinek (void) fprintf(stderr, "%s: %s\n", str, strerror(errno));
72961507Sgjelinek }
72971507Sgjelinek
72981507Sgjelinek /*
72997089Sgjelinek * The following three routines implement a simple locking mechanism to
73007089Sgjelinek * ensure that only one instance of zoneadm at a time is able to manipulate
73017089Sgjelinek * a given zone. The lock is built on top of an fcntl(2) lock of
73027089Sgjelinek * [<altroot>]/var/run/zones/<zonename>.zoneadm.lock. If a zoneadm instance
73037089Sgjelinek * can grab that lock, it is allowed to manipulate the zone.
73047089Sgjelinek *
73057089Sgjelinek * Since zoneadm may call external applications which in turn invoke
73067089Sgjelinek * zoneadm again, we introduce the notion of "lock inheritance". Any
73077089Sgjelinek * instance of zoneadm that has another instance in its ancestry is assumed
73087089Sgjelinek * to be acting on behalf of the original zoneadm, and is thus allowed to
73097089Sgjelinek * manipulate its zone.
73107089Sgjelinek *
73117089Sgjelinek * This inheritance is implemented via the _ZONEADM_LOCK_HELD environment
73127089Sgjelinek * variable. When zoneadm is granted a lock on its zone, this environment
73137089Sgjelinek * variable is set to 1. When it releases the lock, the variable is set to
73147089Sgjelinek * 0. Since a child process inherits its parent's environment, checking
73157089Sgjelinek * the state of this variable indicates whether or not any ancestor owns
73167089Sgjelinek * the lock.
73171507Sgjelinek */
73187089Sgjelinek void
zonecfg_init_lock_file(const char * zone_name,char ** lock_env)73197089Sgjelinek zonecfg_init_lock_file(const char *zone_name, char **lock_env)
73207089Sgjelinek {
73217089Sgjelinek *lock_env = getenv(LOCK_ENV_VAR);
73227089Sgjelinek if (*lock_env == NULL) {
73237089Sgjelinek if (putenv(zoneadm_lock_not_held) != 0) {
73247089Sgjelinek zerror(zone_name, gettext("could not set env: %s"),
73257089Sgjelinek strerror(errno));
73267089Sgjelinek exit(1);
73271507Sgjelinek }
73281507Sgjelinek } else {
73297089Sgjelinek if (atoi(*lock_env) == 1)
73307089Sgjelinek zone_lock_cnt = 1;
73317089Sgjelinek }
73327089Sgjelinek }
73337089Sgjelinek
73347089Sgjelinek void
zonecfg_release_lock_file(const char * zone_name,int lockfd)73357089Sgjelinek zonecfg_release_lock_file(const char *zone_name, int lockfd)
73367089Sgjelinek {
73377089Sgjelinek /*
73387089Sgjelinek * If we are cleaning up from a failed attempt to lock the zone for
73397089Sgjelinek * the first time, we might have a zone_lock_cnt of 0. In that
73407089Sgjelinek * error case, we don't want to do anything but close the lock
73417089Sgjelinek * file.
73427089Sgjelinek */
73437089Sgjelinek assert(zone_lock_cnt >= 0);
73447089Sgjelinek if (zone_lock_cnt > 0) {
73457089Sgjelinek assert(getenv(LOCK_ENV_VAR) != NULL);
73467089Sgjelinek assert(atoi(getenv(LOCK_ENV_VAR)) == 1);
73477089Sgjelinek if (--zone_lock_cnt > 0) {
73487089Sgjelinek assert(lockfd == -1);
73497089Sgjelinek return;
73507089Sgjelinek }
73517089Sgjelinek if (putenv(zoneadm_lock_not_held) != 0) {
73527089Sgjelinek zerror(zone_name, gettext("could not set env: %s"),
73537089Sgjelinek strerror(errno));
73547089Sgjelinek exit(1);
73557089Sgjelinek }
73567089Sgjelinek }
73577089Sgjelinek assert(lockfd >= 0);
73587089Sgjelinek (void) close(lockfd);
73597089Sgjelinek }
73607089Sgjelinek
73617089Sgjelinek int
zonecfg_grab_lock_file(const char * zone_name,int * lockfd)73627089Sgjelinek zonecfg_grab_lock_file(const char *zone_name, int *lockfd)
73637089Sgjelinek {
73647089Sgjelinek char pathbuf[PATH_MAX];
73657089Sgjelinek struct flock flock;
73664229Sgjelinek
73676831Sgjelinek /*
73687089Sgjelinek * If we already have the lock, we can skip this expensive song
73697089Sgjelinek * and dance.
73707089Sgjelinek */
73717089Sgjelinek assert(zone_lock_cnt >= 0);
73727089Sgjelinek assert(getenv(LOCK_ENV_VAR) != NULL);
73737089Sgjelinek if (zone_lock_cnt > 0) {
73747089Sgjelinek assert(atoi(getenv(LOCK_ENV_VAR)) == 1);
73757089Sgjelinek zone_lock_cnt++;
73767089Sgjelinek *lockfd = -1;
73777089Sgjelinek return (Z_OK);
73787089Sgjelinek }
73797089Sgjelinek assert(getenv(LOCK_ENV_VAR) != NULL);
73807089Sgjelinek assert(atoi(getenv(LOCK_ENV_VAR)) == 0);
73817089Sgjelinek
73827089Sgjelinek if (snprintf(pathbuf, sizeof (pathbuf), "%s%s", zonecfg_get_root(),
73837089Sgjelinek ZONES_TMPDIR) >= sizeof (pathbuf)) {
73847089Sgjelinek zerror(zone_name, gettext("alternate root path is too long"));
73857089Sgjelinek return (-1);
73867089Sgjelinek }
73877089Sgjelinek if (mkdir(pathbuf, S_IRWXU) < 0 && errno != EEXIST) {
73887089Sgjelinek zerror(zone_name, gettext("could not mkdir %s: %s"), pathbuf,
73897089Sgjelinek strerror(errno));
73907089Sgjelinek return (-1);
73917089Sgjelinek }
73927089Sgjelinek (void) chmod(pathbuf, S_IRWXU);
73937089Sgjelinek
73947089Sgjelinek /*
73957089Sgjelinek * One of these lock files is created for each zone (when needed).
73967089Sgjelinek * The lock files are not cleaned up (except on system reboot),
73977089Sgjelinek * but since there is only one per zone, there is no resource
73987089Sgjelinek * starvation issue.
73996831Sgjelinek */
74007089Sgjelinek if (snprintf(pathbuf, sizeof (pathbuf), "%s%s/%s.zoneadm.lock",
74017089Sgjelinek zonecfg_get_root(), ZONES_TMPDIR, zone_name) >= sizeof (pathbuf)) {
74027089Sgjelinek zerror(zone_name, gettext("alternate root path is too long"));
74037089Sgjelinek return (-1);
74047089Sgjelinek }
74057089Sgjelinek if ((*lockfd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
74067089Sgjelinek zerror(zone_name, gettext("could not open %s: %s"), pathbuf,
74077089Sgjelinek strerror(errno));
74087089Sgjelinek return (-1);
74097089Sgjelinek }
74107089Sgjelinek /*
74117089Sgjelinek * Lock the file to synchronize with other zoneadmds
74127089Sgjelinek */
74137089Sgjelinek flock.l_type = F_WRLCK;
74147089Sgjelinek flock.l_whence = SEEK_SET;
74157089Sgjelinek flock.l_start = (off_t)0;
74167089Sgjelinek flock.l_len = (off_t)0;
74177089Sgjelinek if ((fcntl(*lockfd, F_SETLKW, &flock) < 0) ||
74187089Sgjelinek (putenv(zoneadm_lock_held) != 0)) {
74197089Sgjelinek zerror(zone_name, gettext("unable to lock %s: %s"), pathbuf,
74207089Sgjelinek strerror(errno));
74217089Sgjelinek zonecfg_release_lock_file(zone_name, *lockfd);
74227089Sgjelinek return (-1);
74237089Sgjelinek }
74247089Sgjelinek zone_lock_cnt = 1;
74257089Sgjelinek return (Z_OK);
74267089Sgjelinek }
74277089Sgjelinek
74288759Sgerald.jelinek@sun.com boolean_t
zonecfg_lock_file_held(int * lockfd)74298759Sgerald.jelinek@sun.com zonecfg_lock_file_held(int *lockfd)
74308759Sgerald.jelinek@sun.com {
74318759Sgerald.jelinek@sun.com if (*lockfd >= 0 || zone_lock_cnt > 0)
74328759Sgerald.jelinek@sun.com return (B_TRUE);
74338759Sgerald.jelinek@sun.com return (B_FALSE);
74348759Sgerald.jelinek@sun.com }
74358759Sgerald.jelinek@sun.com
74364229Sgjelinek static boolean_t
get_doorname(const char * zone_name,char * buffer)74377089Sgjelinek get_doorname(const char *zone_name, char *buffer)
74387089Sgjelinek {
74397089Sgjelinek return (snprintf(buffer, PATH_MAX, "%s" ZONE_DOOR_PATH,
74407089Sgjelinek zonecfg_get_root(), zone_name) < PATH_MAX);
74414229Sgjelinek }
74424229Sgjelinek
74434229Sgjelinek /*
74447089Sgjelinek * system daemons are not audited. For the global zone, this occurs
74457089Sgjelinek * "naturally" since init is started with the default audit
74467089Sgjelinek * characteristics. Since zoneadmd is a system daemon and it starts
74477089Sgjelinek * init for a zone, it is necessary to clear out the audit
74487089Sgjelinek * characteristics inherited from whomever started zoneadmd. This is
74497089Sgjelinek * indicated by the audit id, which is set from the ruid parameter of
74507089Sgjelinek * adt_set_user(), below.
74514229Sgjelinek */
74527089Sgjelinek
74537089Sgjelinek static void
prepare_audit_context(const char * zone_name)74547089Sgjelinek prepare_audit_context(const char *zone_name)
74557089Sgjelinek {
74567089Sgjelinek adt_session_data_t *ah;
74577089Sgjelinek char *failure = gettext("audit failure: %s");
74587089Sgjelinek
74597089Sgjelinek if (adt_start_session(&ah, NULL, 0)) {
74607089Sgjelinek zerror(zone_name, failure, strerror(errno));
74617089Sgjelinek return;
74627089Sgjelinek }
74637089Sgjelinek if (adt_set_user(ah, ADT_NO_AUDIT, ADT_NO_AUDIT,
74647089Sgjelinek ADT_NO_AUDIT, ADT_NO_AUDIT, NULL, ADT_NEW)) {
74657089Sgjelinek zerror(zone_name, failure, strerror(errno));
74667089Sgjelinek (void) adt_end_session(ah);
74677089Sgjelinek return;
74687089Sgjelinek }
74697089Sgjelinek if (adt_set_proc(ah))
74707089Sgjelinek zerror(zone_name, failure, strerror(errno));
74717089Sgjelinek
74727089Sgjelinek (void) adt_end_session(ah);
74737089Sgjelinek }
74747089Sgjelinek
74754229Sgjelinek static int
start_zoneadmd(const char * zone_name,boolean_t lock)74767089Sgjelinek start_zoneadmd(const char *zone_name, boolean_t lock)
74777089Sgjelinek {
74787089Sgjelinek char doorpath[PATH_MAX];
74797089Sgjelinek pid_t child_pid;
74807089Sgjelinek int error = -1;
74817089Sgjelinek int doorfd, lockfd;
74827089Sgjelinek struct door_info info;
74837089Sgjelinek
74847089Sgjelinek if (!get_doorname(zone_name, doorpath))
74857089Sgjelinek return (-1);
74867089Sgjelinek
74877089Sgjelinek if (lock)
74887089Sgjelinek if (zonecfg_grab_lock_file(zone_name, &lockfd) != Z_OK)
74897089Sgjelinek return (-1);
74907089Sgjelinek
74917089Sgjelinek /*
74927089Sgjelinek * Now that we have the lock, re-confirm that the daemon is
74937089Sgjelinek * *not* up and working fine. If it is still down, we have a green
74947089Sgjelinek * light to start it.
74957089Sgjelinek */
74967089Sgjelinek if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
74977089Sgjelinek if (errno != ENOENT) {
74987089Sgjelinek zperror(doorpath);
74997089Sgjelinek goto out;
75007089Sgjelinek }
75017089Sgjelinek } else {
75027089Sgjelinek if (door_info(doorfd, &info) == 0 &&
75037089Sgjelinek ((info.di_attributes & DOOR_REVOKED) == 0)) {
75047089Sgjelinek error = Z_OK;
75057089Sgjelinek (void) close(doorfd);
75067089Sgjelinek goto out;
75077089Sgjelinek }
75087089Sgjelinek (void) close(doorfd);
75097089Sgjelinek }
75107089Sgjelinek
75117089Sgjelinek if ((child_pid = fork()) == -1) {
75127089Sgjelinek zperror(gettext("could not fork"));
75137089Sgjelinek goto out;
75147089Sgjelinek }
75157089Sgjelinek
75167089Sgjelinek if (child_pid == 0) {
75177089Sgjelinek const char *argv[6], **ap;
75187089Sgjelinek
75197089Sgjelinek /* child process */
75207089Sgjelinek prepare_audit_context(zone_name);
75217089Sgjelinek
75227089Sgjelinek ap = argv;
75237089Sgjelinek *ap++ = "zoneadmd";
75247089Sgjelinek *ap++ = "-z";
75257089Sgjelinek *ap++ = zone_name;
75267089Sgjelinek if (zonecfg_in_alt_root()) {
75277089Sgjelinek *ap++ = "-R";
75287089Sgjelinek *ap++ = zonecfg_get_root();
75297089Sgjelinek }
75307089Sgjelinek *ap = NULL;
75317089Sgjelinek
75327089Sgjelinek (void) execv("/usr/lib/zones/zoneadmd", (char * const *)argv);
75337089Sgjelinek /*
75347089Sgjelinek * TRANSLATION_NOTE
75357089Sgjelinek * zoneadmd is a literal that should not be translated.
75367089Sgjelinek */
75377089Sgjelinek zperror(gettext("could not exec zoneadmd"));
75387089Sgjelinek _exit(1);
75397089Sgjelinek } else {
75407089Sgjelinek /* parent process */
75417089Sgjelinek pid_t retval;
75427089Sgjelinek int pstatus = 0;
75437089Sgjelinek
75447089Sgjelinek do {
75457089Sgjelinek retval = waitpid(child_pid, &pstatus, 0);
75467089Sgjelinek } while (retval != child_pid);
75477089Sgjelinek if (WIFSIGNALED(pstatus) || (WIFEXITED(pstatus) &&
75487089Sgjelinek WEXITSTATUS(pstatus) != 0)) {
75497089Sgjelinek zerror(zone_name, gettext("could not start %s"),
75507089Sgjelinek "zoneadmd");
75517089Sgjelinek goto out;
75527089Sgjelinek }
75537089Sgjelinek }
75547089Sgjelinek error = Z_OK;
75557089Sgjelinek out:
75567089Sgjelinek if (lock)
75577089Sgjelinek zonecfg_release_lock_file(zone_name, lockfd);
75587089Sgjelinek return (error);
75597089Sgjelinek }
75607089Sgjelinek
75617089Sgjelinek int
zonecfg_ping_zoneadmd(const char * zone_name)75627089Sgjelinek zonecfg_ping_zoneadmd(const char *zone_name)
75637089Sgjelinek {
75647089Sgjelinek char doorpath[PATH_MAX];
75657089Sgjelinek int doorfd;
75667089Sgjelinek struct door_info info;
75677089Sgjelinek
75687089Sgjelinek if (!get_doorname(zone_name, doorpath))
75697089Sgjelinek return (-1);
75707089Sgjelinek
75717089Sgjelinek if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
75727089Sgjelinek return (-1);
75737089Sgjelinek }
75747089Sgjelinek if (door_info(doorfd, &info) == 0 &&
75757089Sgjelinek ((info.di_attributes & DOOR_REVOKED) == 0)) {
75767089Sgjelinek (void) close(doorfd);
75774229Sgjelinek return (Z_OK);
75787089Sgjelinek }
75797089Sgjelinek (void) close(doorfd);
75807089Sgjelinek return (-1);
75817089Sgjelinek }
75827089Sgjelinek
75837089Sgjelinek int
zonecfg_call_zoneadmd(const char * zone_name,zone_cmd_arg_t * arg,char * locale,boolean_t lock)75847089Sgjelinek zonecfg_call_zoneadmd(const char *zone_name, zone_cmd_arg_t *arg, char *locale,
75857089Sgjelinek boolean_t lock)
75867089Sgjelinek {
75877089Sgjelinek char doorpath[PATH_MAX];
75887089Sgjelinek int doorfd, result;
75897089Sgjelinek door_arg_t darg;
75907089Sgjelinek
75917089Sgjelinek zoneid_t zoneid;
75927089Sgjelinek uint64_t uniqid = 0;
75937089Sgjelinek
75947089Sgjelinek zone_cmd_rval_t *rvalp;
75957089Sgjelinek size_t rlen;
75967089Sgjelinek char *cp, *errbuf;
75977089Sgjelinek
75987089Sgjelinek rlen = getpagesize();
75997089Sgjelinek if ((rvalp = malloc(rlen)) == NULL) {
76007089Sgjelinek zerror(zone_name, gettext("failed to allocate %lu bytes: %s"),
76017089Sgjelinek rlen, strerror(errno));
76027089Sgjelinek return (-1);
76037089Sgjelinek }
76047089Sgjelinek
76057089Sgjelinek if ((zoneid = getzoneidbyname(zone_name)) != ZONE_ID_UNDEFINED) {
76067089Sgjelinek (void) zone_getattr(zoneid, ZONE_ATTR_UNIQID, &uniqid,
76077089Sgjelinek sizeof (uniqid));
76087089Sgjelinek }
76097089Sgjelinek arg->uniqid = uniqid;
76107089Sgjelinek (void) strlcpy(arg->locale, locale, sizeof (arg->locale));
76117089Sgjelinek if (!get_doorname(zone_name, doorpath)) {
76127089Sgjelinek zerror(zone_name, gettext("alternate root path is too long"));
76137089Sgjelinek free(rvalp);
76147089Sgjelinek return (-1);
76157059Sgjelinek }
76161507Sgjelinek
76171507Sgjelinek /*
76187089Sgjelinek * Loop trying to start zoneadmd; if something goes seriously
76197089Sgjelinek * wrong we break out and fail.
76201507Sgjelinek */
76217089Sgjelinek for (;;) {
76227089Sgjelinek if (start_zoneadmd(zone_name, lock) != Z_OK)
76237089Sgjelinek break;
76247089Sgjelinek
76257089Sgjelinek if ((doorfd = open(doorpath, O_RDONLY)) < 0) {
76267089Sgjelinek zperror(gettext("failed to open zone door"));
76277089Sgjelinek break;
76281507Sgjelinek }
76294229Sgjelinek
76307089Sgjelinek darg.data_ptr = (char *)arg;
76317089Sgjelinek darg.data_size = sizeof (*arg);
76327089Sgjelinek darg.desc_ptr = NULL;
76337089Sgjelinek darg.desc_num = 0;
76347089Sgjelinek darg.rbuf = (char *)rvalp;
76357089Sgjelinek darg.rsize = rlen;
76367089Sgjelinek if (door_call(doorfd, &darg) != 0) {
76377089Sgjelinek (void) close(doorfd);
76387089Sgjelinek /*
76397089Sgjelinek * We'll get EBADF if the door has been revoked.
76407089Sgjelinek */
76417089Sgjelinek if (errno != EBADF) {
76427089Sgjelinek zperror(gettext("door_call failed"));
76431507Sgjelinek break;
76441507Sgjelinek }
76457089Sgjelinek continue; /* take another lap */
76461507Sgjelinek }
76477089Sgjelinek (void) close(doorfd);
76487089Sgjelinek
76497089Sgjelinek if (darg.data_size == 0) {
76507089Sgjelinek /* Door server is going away; kick it again. */
76515829Sgjelinek continue;
76525829Sgjelinek }
76535829Sgjelinek
76547089Sgjelinek errbuf = rvalp->errbuf;
76557089Sgjelinek while (*errbuf != '\0') {
76567089Sgjelinek /*
76577089Sgjelinek * Remove any newlines since zerror()
76587089Sgjelinek * will append one automatically.
76597089Sgjelinek */
76607089Sgjelinek cp = strchr(errbuf, '\n');
76617089Sgjelinek if (cp != NULL)
76627089Sgjelinek *cp = '\0';
76637089Sgjelinek zerror(zone_name, "%s", errbuf);
76647089Sgjelinek if (cp == NULL)
76657089Sgjelinek break;
76667089Sgjelinek errbuf = cp + 1;
76675829Sgjelinek }
76687089Sgjelinek result = rvalp->rval == 0 ? 0 : -1;
76697089Sgjelinek free(rvalp);
76707089Sgjelinek return (result);
76717089Sgjelinek }
76727089Sgjelinek
76737089Sgjelinek free(rvalp);
76747089Sgjelinek return (-1);
76757089Sgjelinek }
767612578SGlenn.Faden@Sun.COM
767712578SGlenn.Faden@Sun.COM boolean_t
zonecfg_valid_auths(const char * auths,const char * zonename)767812578SGlenn.Faden@Sun.COM zonecfg_valid_auths(const char *auths, const char *zonename)
767912578SGlenn.Faden@Sun.COM {
768012578SGlenn.Faden@Sun.COM char *right;
768112578SGlenn.Faden@Sun.COM char *tmpauths;
768212578SGlenn.Faden@Sun.COM char *lasts;
768312578SGlenn.Faden@Sun.COM char authname[MAXAUTHS];
768412578SGlenn.Faden@Sun.COM boolean_t status = B_TRUE;
768512578SGlenn.Faden@Sun.COM
768612578SGlenn.Faden@Sun.COM tmpauths = strdup(auths);
768712578SGlenn.Faden@Sun.COM if (tmpauths == NULL) {
768812578SGlenn.Faden@Sun.COM zerror(zonename, gettext("Out of memory"));
768912578SGlenn.Faden@Sun.COM return (B_FALSE);
769012578SGlenn.Faden@Sun.COM }
769112578SGlenn.Faden@Sun.COM right = strtok_r(tmpauths, ",", &lasts);
769212578SGlenn.Faden@Sun.COM while (right != NULL) {
769312578SGlenn.Faden@Sun.COM (void) snprintf(authname, MAXAUTHS, "%s%s",
769412578SGlenn.Faden@Sun.COM ZONE_AUTH_PREFIX, right);
769512578SGlenn.Faden@Sun.COM if (getauthnam(authname) == NULL) {
769612578SGlenn.Faden@Sun.COM status = B_FALSE;
769712582SGlenn.Faden@Sun.COM zerror(zonename,
769812635SGlenn.Faden@Sun.COM gettext("'%s' is not a valid authorization"),
769912578SGlenn.Faden@Sun.COM right);
770012578SGlenn.Faden@Sun.COM }
770112578SGlenn.Faden@Sun.COM right = strtok_r(NULL, ",", &lasts);
770212578SGlenn.Faden@Sun.COM }
770312578SGlenn.Faden@Sun.COM free(tmpauths);
770412578SGlenn.Faden@Sun.COM return (status);
770512578SGlenn.Faden@Sun.COM }
770612578SGlenn.Faden@Sun.COM
770712578SGlenn.Faden@Sun.COM int
zonecfg_delete_admins(zone_dochandle_t handle,char * zonename)770812578SGlenn.Faden@Sun.COM zonecfg_delete_admins(zone_dochandle_t handle, char *zonename)
770912578SGlenn.Faden@Sun.COM {
771012578SGlenn.Faden@Sun.COM int err;
771112578SGlenn.Faden@Sun.COM struct zone_admintab admintab;
771212578SGlenn.Faden@Sun.COM boolean_t changed = B_FALSE;
771312578SGlenn.Faden@Sun.COM
771412578SGlenn.Faden@Sun.COM if ((err = zonecfg_setadminent(handle)) != Z_OK) {
771512578SGlenn.Faden@Sun.COM return (err);
771612578SGlenn.Faden@Sun.COM }
771712578SGlenn.Faden@Sun.COM while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
771812578SGlenn.Faden@Sun.COM err = zonecfg_delete_admin(handle, &admintab,
771912578SGlenn.Faden@Sun.COM zonename);
772012578SGlenn.Faden@Sun.COM if (err != Z_OK) {
772112578SGlenn.Faden@Sun.COM (void) zonecfg_endadminent(handle);
772212578SGlenn.Faden@Sun.COM return (err);
772312578SGlenn.Faden@Sun.COM } else {
772412578SGlenn.Faden@Sun.COM changed = B_TRUE;
772512578SGlenn.Faden@Sun.COM }
772612578SGlenn.Faden@Sun.COM if ((err = zonecfg_setadminent(handle)) != Z_OK) {
772712578SGlenn.Faden@Sun.COM return (err);
772812578SGlenn.Faden@Sun.COM }
772912578SGlenn.Faden@Sun.COM }
773012578SGlenn.Faden@Sun.COM (void) zonecfg_endadminent(handle);
773112578SGlenn.Faden@Sun.COM return (changed? Z_OK:Z_NO_ENTRY);
773212578SGlenn.Faden@Sun.COM }
773312578SGlenn.Faden@Sun.COM
773412578SGlenn.Faden@Sun.COM /*
773512578SGlenn.Faden@Sun.COM * Checks if a long authorization applies to this zone.
773612578SGlenn.Faden@Sun.COM * If so, it returns true, after destructively stripping
773712578SGlenn.Faden@Sun.COM * the authorization of its prefix and zone suffix.
773812578SGlenn.Faden@Sun.COM */
773912578SGlenn.Faden@Sun.COM static boolean_t
is_zone_auth(char ** auth,char * zonename,char * oldzonename)774012578SGlenn.Faden@Sun.COM is_zone_auth(char **auth, char *zonename, char *oldzonename)
774112578SGlenn.Faden@Sun.COM {
774212578SGlenn.Faden@Sun.COM char *suffix;
774312578SGlenn.Faden@Sun.COM size_t offset;
774412578SGlenn.Faden@Sun.COM
774512578SGlenn.Faden@Sun.COM offset = strlen(ZONE_AUTH_PREFIX);
774612578SGlenn.Faden@Sun.COM if ((strncmp(*auth, ZONE_AUTH_PREFIX, offset) == 0) &&
774712578SGlenn.Faden@Sun.COM ((suffix = strchr(*auth, '/')) != NULL)) {
774812635SGlenn.Faden@Sun.COM if (strcmp(suffix + 1, zonename) == 0) {
774912578SGlenn.Faden@Sun.COM *auth += offset;
775012578SGlenn.Faden@Sun.COM suffix[0] = '\0';
775112578SGlenn.Faden@Sun.COM return (B_TRUE);
775212578SGlenn.Faden@Sun.COM } else if ((oldzonename != NULL) &&
775312635SGlenn.Faden@Sun.COM (strcmp(suffix + 1, oldzonename) == 0)) {
775412578SGlenn.Faden@Sun.COM *auth += offset;
775512578SGlenn.Faden@Sun.COM suffix[0] = '\0';
775612578SGlenn.Faden@Sun.COM return (B_TRUE);
775712578SGlenn.Faden@Sun.COM }
775812578SGlenn.Faden@Sun.COM }
775912578SGlenn.Faden@Sun.COM return (B_FALSE);
776012578SGlenn.Faden@Sun.COM }
776112578SGlenn.Faden@Sun.COM
776212578SGlenn.Faden@Sun.COM /*
776312578SGlenn.Faden@Sun.COM * This function determines whether the zone-specific authorization
776412578SGlenn.Faden@Sun.COM * assignments in /etc/user_attr have been changed more recently
776512578SGlenn.Faden@Sun.COM * than the equivalent data stored in the zone's configuration file.
776612578SGlenn.Faden@Sun.COM * This should only happen if the zone-specific authorizations in
776712578SGlenn.Faden@Sun.COM * the user_attr file were modified using a tool other than zonecfg.
776812578SGlenn.Faden@Sun.COM * If the configuration file is out-of-date with respect to these
776912578SGlenn.Faden@Sun.COM * authorization assignments, it is updated to match those specified
777012578SGlenn.Faden@Sun.COM * in /etc/user_attr.
777112578SGlenn.Faden@Sun.COM */
777212578SGlenn.Faden@Sun.COM
777312578SGlenn.Faden@Sun.COM int
zonecfg_update_userauths(zone_dochandle_t handle,char * zonename)777412578SGlenn.Faden@Sun.COM zonecfg_update_userauths(zone_dochandle_t handle, char *zonename)
777512578SGlenn.Faden@Sun.COM {
777612578SGlenn.Faden@Sun.COM userattr_t *ua_ptr;
777712578SGlenn.Faden@Sun.COM char *authlist;
777812578SGlenn.Faden@Sun.COM char *lasts;
777912578SGlenn.Faden@Sun.COM FILE *uaf;
778012578SGlenn.Faden@Sun.COM struct zone_admintab admintab;
778112578SGlenn.Faden@Sun.COM struct stat config_st, ua_st;
778212578SGlenn.Faden@Sun.COM char config_file[MAXPATHLEN];
778312578SGlenn.Faden@Sun.COM boolean_t changed = B_FALSE;
778412578SGlenn.Faden@Sun.COM int err;
778512578SGlenn.Faden@Sun.COM
778612578SGlenn.Faden@Sun.COM if ((uaf = fopen(USERATTR_FILENAME, "r")) == NULL) {
778712578SGlenn.Faden@Sun.COM zerror(zonename, gettext("could not open file %s: %s"),
778812578SGlenn.Faden@Sun.COM USERATTR_FILENAME, strerror(errno));
778912578SGlenn.Faden@Sun.COM if (errno == EACCES)
779012578SGlenn.Faden@Sun.COM return (Z_ACCES);
779112578SGlenn.Faden@Sun.COM if (errno == ENOENT)
779212578SGlenn.Faden@Sun.COM return (Z_NO_ZONE);
779312578SGlenn.Faden@Sun.COM return (Z_MISC_FS);
779412578SGlenn.Faden@Sun.COM }
779512578SGlenn.Faden@Sun.COM if ((err = fstat(fileno(uaf), &ua_st)) != 0) {
779612578SGlenn.Faden@Sun.COM zerror(zonename, gettext("could not stat file %s: %s"),
779712578SGlenn.Faden@Sun.COM USERATTR_FILENAME, strerror(errno));
779812578SGlenn.Faden@Sun.COM (void) fclose(uaf);
779912578SGlenn.Faden@Sun.COM return (Z_MISC_FS);
780012578SGlenn.Faden@Sun.COM }
780112578SGlenn.Faden@Sun.COM if (!config_file_path(zonename, config_file)) {
780212578SGlenn.Faden@Sun.COM (void) fclose(uaf);
780312578SGlenn.Faden@Sun.COM return (Z_MISC_FS);
780412578SGlenn.Faden@Sun.COM }
780512578SGlenn.Faden@Sun.COM
780612578SGlenn.Faden@Sun.COM if ((err = stat(config_file, &config_st)) != 0) {
780712578SGlenn.Faden@Sun.COM zerror(zonename, gettext("could not stat file %s: %s"),
780812578SGlenn.Faden@Sun.COM config_file, strerror(errno));
780912578SGlenn.Faden@Sun.COM (void) fclose(uaf);
781012578SGlenn.Faden@Sun.COM return (Z_MISC_FS);
781112578SGlenn.Faden@Sun.COM }
781212578SGlenn.Faden@Sun.COM if (config_st.st_mtime >= ua_st.st_mtime) {
781312578SGlenn.Faden@Sun.COM (void) fclose(uaf);
781412578SGlenn.Faden@Sun.COM return (Z_NO_ENTRY);
781512578SGlenn.Faden@Sun.COM }
781612578SGlenn.Faden@Sun.COM if ((err = zonecfg_delete_admins(handle, zonename)) == Z_OK) {
781712578SGlenn.Faden@Sun.COM changed = B_TRUE;
781812578SGlenn.Faden@Sun.COM } else if (err != Z_NO_ENTRY) {
781912578SGlenn.Faden@Sun.COM (void) fclose(uaf);
782012578SGlenn.Faden@Sun.COM return (err);
782112578SGlenn.Faden@Sun.COM }
782212578SGlenn.Faden@Sun.COM while ((ua_ptr = fgetuserattr(uaf)) != NULL) {
782312578SGlenn.Faden@Sun.COM if (ua_ptr->name[0] == '#') {
782412578SGlenn.Faden@Sun.COM continue;
782512578SGlenn.Faden@Sun.COM }
782612578SGlenn.Faden@Sun.COM authlist = kva_match(ua_ptr->attr, USERATTR_AUTHS_KW);
782712578SGlenn.Faden@Sun.COM if (authlist != NULL) {
782812578SGlenn.Faden@Sun.COM char *cur_auth;
782912578SGlenn.Faden@Sun.COM boolean_t first;
783012578SGlenn.Faden@Sun.COM
783112578SGlenn.Faden@Sun.COM first = B_TRUE;
783212578SGlenn.Faden@Sun.COM bzero(&admintab.zone_admin_auths, MAXAUTHS);
783312578SGlenn.Faden@Sun.COM cur_auth = strtok_r(authlist, ",", &lasts);
783412578SGlenn.Faden@Sun.COM while (cur_auth != NULL) {
783512578SGlenn.Faden@Sun.COM if (is_zone_auth(&cur_auth, zonename,
783612578SGlenn.Faden@Sun.COM NULL)) {
783712578SGlenn.Faden@Sun.COM /*
783812578SGlenn.Faden@Sun.COM * Add auths for this zone
783912578SGlenn.Faden@Sun.COM */
784012578SGlenn.Faden@Sun.COM if (first) {
784112578SGlenn.Faden@Sun.COM first = B_FALSE;
784212578SGlenn.Faden@Sun.COM } else {
784312578SGlenn.Faden@Sun.COM (void) strlcat(
784412578SGlenn.Faden@Sun.COM admintab.zone_admin_auths,
784512578SGlenn.Faden@Sun.COM ",", MAXAUTHS);
784612578SGlenn.Faden@Sun.COM }
784712578SGlenn.Faden@Sun.COM (void) strlcat(
784812578SGlenn.Faden@Sun.COM admintab.zone_admin_auths,
784912578SGlenn.Faden@Sun.COM cur_auth, MAXAUTHS);
785012578SGlenn.Faden@Sun.COM }
785112578SGlenn.Faden@Sun.COM cur_auth = strtok_r(NULL, ",", &lasts);
785212578SGlenn.Faden@Sun.COM }
785312578SGlenn.Faden@Sun.COM if (!first) {
785412578SGlenn.Faden@Sun.COM /*
785512578SGlenn.Faden@Sun.COM * Add this right to config file
785612578SGlenn.Faden@Sun.COM */
785712578SGlenn.Faden@Sun.COM (void) strlcpy(admintab.zone_admin_user,
785812578SGlenn.Faden@Sun.COM ua_ptr->name,
785912578SGlenn.Faden@Sun.COM sizeof (admintab.zone_admin_user));
786012578SGlenn.Faden@Sun.COM err = zonecfg_add_admin(handle,
786112578SGlenn.Faden@Sun.COM &admintab, zonename);
786212578SGlenn.Faden@Sun.COM if (err != Z_OK) {
786312578SGlenn.Faden@Sun.COM (void) fclose(uaf);
786412578SGlenn.Faden@Sun.COM return (err);
786512578SGlenn.Faden@Sun.COM } else {
786612578SGlenn.Faden@Sun.COM changed = B_TRUE;
786712578SGlenn.Faden@Sun.COM }
786812578SGlenn.Faden@Sun.COM }
786912578SGlenn.Faden@Sun.COM }
787012578SGlenn.Faden@Sun.COM } /* end-of-while-loop */
787112578SGlenn.Faden@Sun.COM (void) fclose(uaf);
787212578SGlenn.Faden@Sun.COM return (changed? Z_OK: Z_NO_ENTRY);
787312578SGlenn.Faden@Sun.COM }
787412578SGlenn.Faden@Sun.COM
787512578SGlenn.Faden@Sun.COM static void
update_profiles(char * rbac_profs,boolean_t add)787612578SGlenn.Faden@Sun.COM update_profiles(char *rbac_profs, boolean_t add)
787712578SGlenn.Faden@Sun.COM {
787812578SGlenn.Faden@Sun.COM char new_profs[MAXPROFS];
787912578SGlenn.Faden@Sun.COM char *cur_prof;
788012578SGlenn.Faden@Sun.COM boolean_t first = B_TRUE;
788112578SGlenn.Faden@Sun.COM boolean_t found = B_FALSE;
788212578SGlenn.Faden@Sun.COM char *lasts;
788312578SGlenn.Faden@Sun.COM
788412578SGlenn.Faden@Sun.COM cur_prof = strtok_r(rbac_profs, ",", &lasts);
788512578SGlenn.Faden@Sun.COM while (cur_prof != NULL) {
788612578SGlenn.Faden@Sun.COM if (strcmp(cur_prof, ZONE_MGMT_PROF) == 0) {
788712578SGlenn.Faden@Sun.COM found = B_TRUE;
788812578SGlenn.Faden@Sun.COM if (!add) {
788912578SGlenn.Faden@Sun.COM cur_prof = strtok_r(NULL, ",", &lasts);
789012578SGlenn.Faden@Sun.COM continue;
789112578SGlenn.Faden@Sun.COM }
789212578SGlenn.Faden@Sun.COM }
789312578SGlenn.Faden@Sun.COM if (first) {
789412578SGlenn.Faden@Sun.COM first = B_FALSE;
789512578SGlenn.Faden@Sun.COM } else {
789612578SGlenn.Faden@Sun.COM (void) strlcat(new_profs, ",",
789712578SGlenn.Faden@Sun.COM MAXPROFS);
789812578SGlenn.Faden@Sun.COM }
789912578SGlenn.Faden@Sun.COM (void) strlcat(new_profs, cur_prof,
790012578SGlenn.Faden@Sun.COM MAXPROFS);
790112578SGlenn.Faden@Sun.COM cur_prof = strtok_r(NULL, ",", &lasts);
790212578SGlenn.Faden@Sun.COM }
790312578SGlenn.Faden@Sun.COM /*
790412578SGlenn.Faden@Sun.COM * Now prepend the Zone Management profile at the beginning
790512578SGlenn.Faden@Sun.COM * of the list if it is needed, and append the rest.
790612578SGlenn.Faden@Sun.COM * Return the updated list in the original buffer.
790712578SGlenn.Faden@Sun.COM */
790812578SGlenn.Faden@Sun.COM if (add && !found) {
790912578SGlenn.Faden@Sun.COM first = B_FALSE;
791012578SGlenn.Faden@Sun.COM (void) strlcpy(rbac_profs, ZONE_MGMT_PROF, MAXPROFS);
791112578SGlenn.Faden@Sun.COM } else {
791212578SGlenn.Faden@Sun.COM first = B_TRUE;
791312578SGlenn.Faden@Sun.COM rbac_profs[0] = '\0';
791412578SGlenn.Faden@Sun.COM }
791512578SGlenn.Faden@Sun.COM if (strlen(new_profs) > 0) {
791612578SGlenn.Faden@Sun.COM if (!first)
791712578SGlenn.Faden@Sun.COM (void) strlcat(rbac_profs, ",", MAXPROFS);
791812578SGlenn.Faden@Sun.COM (void) strlcat(rbac_profs, new_profs, MAXPROFS);
791912578SGlenn.Faden@Sun.COM }
792012578SGlenn.Faden@Sun.COM }
792112578SGlenn.Faden@Sun.COM
792212578SGlenn.Faden@Sun.COM #define MAX_CMD_LEN 1024
792312578SGlenn.Faden@Sun.COM
792412578SGlenn.Faden@Sun.COM static int
do_subproc(char * zonename,char * cmdbuf)792512578SGlenn.Faden@Sun.COM do_subproc(char *zonename, char *cmdbuf)
792612578SGlenn.Faden@Sun.COM {
792712578SGlenn.Faden@Sun.COM char inbuf[MAX_CMD_LEN];
792812578SGlenn.Faden@Sun.COM FILE *file;
792912578SGlenn.Faden@Sun.COM int status;
793012578SGlenn.Faden@Sun.COM
793112578SGlenn.Faden@Sun.COM file = popen(cmdbuf, "r");
793212578SGlenn.Faden@Sun.COM if (file == NULL) {
793312578SGlenn.Faden@Sun.COM zerror(zonename, gettext("Could not launch: %s"), cmdbuf);
793412578SGlenn.Faden@Sun.COM return (-1);
793512578SGlenn.Faden@Sun.COM }
793612578SGlenn.Faden@Sun.COM
793712578SGlenn.Faden@Sun.COM while (fgets(inbuf, sizeof (inbuf), file) != NULL)
793812578SGlenn.Faden@Sun.COM (void) fprintf(stderr, "%s", inbuf);
793912578SGlenn.Faden@Sun.COM status = pclose(file);
794012578SGlenn.Faden@Sun.COM
794112578SGlenn.Faden@Sun.COM if (WIFSIGNALED(status)) {
794212578SGlenn.Faden@Sun.COM zerror(zonename, gettext("%s unexpectedly terminated "
794312578SGlenn.Faden@Sun.COM "due to signal %d"),
794412578SGlenn.Faden@Sun.COM cmdbuf, WTERMSIG(status));
794512578SGlenn.Faden@Sun.COM return (-1);
794612578SGlenn.Faden@Sun.COM }
794712578SGlenn.Faden@Sun.COM assert(WIFEXITED(status));
794812578SGlenn.Faden@Sun.COM return (WEXITSTATUS(status));
794912578SGlenn.Faden@Sun.COM }
795012578SGlenn.Faden@Sun.COM
795112578SGlenn.Faden@Sun.COM /*
795212578SGlenn.Faden@Sun.COM * This function updates the local /etc/user_attr file to
795312578SGlenn.Faden@Sun.COM * correspond to the admin settings that are currently being
795412578SGlenn.Faden@Sun.COM * committed. The updates are done via usermod and/or rolemod
795512578SGlenn.Faden@Sun.COM * depending on the type of the specified user. It is also
795612578SGlenn.Faden@Sun.COM * invoked to remove entries from user_attr corresponding to
795712578SGlenn.Faden@Sun.COM * removed admin assignments, using an empty auths string.
795812578SGlenn.Faden@Sun.COM *
795912578SGlenn.Faden@Sun.COM * Because the removed entries are no longer included in the
796012578SGlenn.Faden@Sun.COM * cofiguration that is being committed, a linked list of
796112578SGlenn.Faden@Sun.COM * removed admin entries is maintained to keep track of such
796212578SGlenn.Faden@Sun.COM * transactions. The head of the list is stored in the zone_dh_userauths
796312578SGlenn.Faden@Sun.COM * element of the handle strcture.
796412578SGlenn.Faden@Sun.COM */
796512578SGlenn.Faden@Sun.COM static int
zonecfg_authorize_user_impl(zone_dochandle_t handle,char * user,char * auths,char * zonename)796612578SGlenn.Faden@Sun.COM zonecfg_authorize_user_impl(zone_dochandle_t handle, char *user,
796712578SGlenn.Faden@Sun.COM char *auths, char *zonename)
796812578SGlenn.Faden@Sun.COM {
796912578SGlenn.Faden@Sun.COM char *right;
797012578SGlenn.Faden@Sun.COM char old_auths[MAXAUTHS];
797112578SGlenn.Faden@Sun.COM char new_auths[MAXAUTHS];
797212578SGlenn.Faden@Sun.COM char rbac_profs[MAXPROFS];
797312578SGlenn.Faden@Sun.COM char *lasts;
797412578SGlenn.Faden@Sun.COM userattr_t *u;
797512578SGlenn.Faden@Sun.COM boolean_t first = B_TRUE;
797612578SGlenn.Faden@Sun.COM boolean_t is_zone_admin = B_FALSE;
797712578SGlenn.Faden@Sun.COM char user_cmd[] = "/usr/sbin/usermod";
797812578SGlenn.Faden@Sun.COM char role_cmd[] = "/usr/sbin/rolemod";
797912635SGlenn.Faden@Sun.COM char *auths_cmd = user_cmd; /* either usermod or rolemod */
798012635SGlenn.Faden@Sun.COM char *new_auth_start; /* string containing the new auths */
798112635SGlenn.Faden@Sun.COM int new_auth_cnt = 0; /* delta of changed authorizations */
798212578SGlenn.Faden@Sun.COM
798312578SGlenn.Faden@Sun.COM /*
798412578SGlenn.Faden@Sun.COM * First get the existing authorizations for this user
798512578SGlenn.Faden@Sun.COM */
798612578SGlenn.Faden@Sun.COM
798712578SGlenn.Faden@Sun.COM bzero(&old_auths, sizeof (old_auths));
798812578SGlenn.Faden@Sun.COM bzero(&new_auths, sizeof (new_auths));
798912578SGlenn.Faden@Sun.COM bzero(&rbac_profs, sizeof (rbac_profs));
799012578SGlenn.Faden@Sun.COM if ((u = getusernam(user)) != NULL) {
799112578SGlenn.Faden@Sun.COM char *current_auths;
799212578SGlenn.Faden@Sun.COM char *current_profs;
799312578SGlenn.Faden@Sun.COM char *type;
799412578SGlenn.Faden@Sun.COM
799512578SGlenn.Faden@Sun.COM type = kva_match(u->attr, USERATTR_TYPE_KW);
799612578SGlenn.Faden@Sun.COM if (type != NULL) {
799712578SGlenn.Faden@Sun.COM if (strcmp(type, USERATTR_TYPE_NONADMIN_KW) == 0)
799812578SGlenn.Faden@Sun.COM auths_cmd = role_cmd;
799912578SGlenn.Faden@Sun.COM }
800012578SGlenn.Faden@Sun.COM
800112578SGlenn.Faden@Sun.COM current_auths = kva_match(u->attr, USERATTR_AUTHS_KW);
800212578SGlenn.Faden@Sun.COM if (current_auths != NULL) {
800312578SGlenn.Faden@Sun.COM char *cur_auth;
800412578SGlenn.Faden@Sun.COM char *delete_name;
800512578SGlenn.Faden@Sun.COM size_t offset;
800612578SGlenn.Faden@Sun.COM
800712578SGlenn.Faden@Sun.COM offset = strlen(ZONE_AUTH_PREFIX);
800812578SGlenn.Faden@Sun.COM
800912578SGlenn.Faden@Sun.COM (void) strlcpy(old_auths, current_auths, MAXAUTHS);
801012578SGlenn.Faden@Sun.COM cur_auth = strtok_r(current_auths, ",", &lasts);
801112578SGlenn.Faden@Sun.COM
801212578SGlenn.Faden@Sun.COM /*
801312578SGlenn.Faden@Sun.COM * Next, remove any existing authorizations
801412578SGlenn.Faden@Sun.COM * for this zone, and determine if the
801512578SGlenn.Faden@Sun.COM * user still needs the Zone Management Profile.
801612578SGlenn.Faden@Sun.COM */
801712578SGlenn.Faden@Sun.COM if (is_renaming(handle))
801812578SGlenn.Faden@Sun.COM delete_name = handle->zone_dh_delete_name;
801912578SGlenn.Faden@Sun.COM else
802012578SGlenn.Faden@Sun.COM delete_name = NULL;
802112578SGlenn.Faden@Sun.COM while (cur_auth != NULL) {
802212578SGlenn.Faden@Sun.COM if (!is_zone_auth(&cur_auth, zonename,
802312578SGlenn.Faden@Sun.COM delete_name)) {
802412578SGlenn.Faden@Sun.COM if (first) {
802512578SGlenn.Faden@Sun.COM first = B_FALSE;
802612578SGlenn.Faden@Sun.COM } else {
802712578SGlenn.Faden@Sun.COM (void) strlcat(new_auths, ",",
802812578SGlenn.Faden@Sun.COM MAXAUTHS);
802912578SGlenn.Faden@Sun.COM }
803012578SGlenn.Faden@Sun.COM (void) strlcat(new_auths, cur_auth,
803112578SGlenn.Faden@Sun.COM MAXAUTHS);
803212578SGlenn.Faden@Sun.COM /*
803312578SGlenn.Faden@Sun.COM * If the user has authorizations
803412578SGlenn.Faden@Sun.COM * for other zones, then set a
803512578SGlenn.Faden@Sun.COM * flag indicate that the Zone
803612578SGlenn.Faden@Sun.COM * Management profile should be
803712578SGlenn.Faden@Sun.COM * preserved in user_attr.
803812578SGlenn.Faden@Sun.COM */
803912578SGlenn.Faden@Sun.COM if (strncmp(cur_auth,
804012578SGlenn.Faden@Sun.COM ZONE_AUTH_PREFIX, offset) == 0)
804112578SGlenn.Faden@Sun.COM is_zone_admin = B_TRUE;
804212635SGlenn.Faden@Sun.COM } else {
804312635SGlenn.Faden@Sun.COM new_auth_cnt++;
804412578SGlenn.Faden@Sun.COM }
804512578SGlenn.Faden@Sun.COM cur_auth = strtok_r(NULL, ",", &lasts);
804612578SGlenn.Faden@Sun.COM }
804712578SGlenn.Faden@Sun.COM }
804812578SGlenn.Faden@Sun.COM current_profs = kva_match(u->attr, USERATTR_PROFILES_KW);
804912578SGlenn.Faden@Sun.COM if (current_profs != NULL) {
805012578SGlenn.Faden@Sun.COM (void) strlcpy(rbac_profs, current_profs, MAXPROFS);
805112578SGlenn.Faden@Sun.COM }
805212578SGlenn.Faden@Sun.COM free_userattr(u);
805312578SGlenn.Faden@Sun.COM }
805412578SGlenn.Faden@Sun.COM /*
805512578SGlenn.Faden@Sun.COM * The following is done to avoid revisiting the
805612578SGlenn.Faden@Sun.COM * user_attr entry for this user
805712578SGlenn.Faden@Sun.COM */
805812578SGlenn.Faden@Sun.COM (void) zonecfg_remove_userauths(handle, user, "", B_FALSE);
805912578SGlenn.Faden@Sun.COM
806012578SGlenn.Faden@Sun.COM /*
806112578SGlenn.Faden@Sun.COM * Convert each right into a properly formatted authorization
806212578SGlenn.Faden@Sun.COM */
806312635SGlenn.Faden@Sun.COM new_auth_start = new_auths + strlen(new_auths);
806412635SGlenn.Faden@Sun.COM if (!first)
806512635SGlenn.Faden@Sun.COM new_auth_start++;
806612578SGlenn.Faden@Sun.COM right = strtok_r(auths, ",", &lasts);
806712578SGlenn.Faden@Sun.COM while (right != NULL) {
806812578SGlenn.Faden@Sun.COM char auth[MAXAUTHS];
806912578SGlenn.Faden@Sun.COM
807012578SGlenn.Faden@Sun.COM (void) snprintf(auth, MAXAUTHS, "%s%s/%s",
807112578SGlenn.Faden@Sun.COM ZONE_AUTH_PREFIX, right, zonename);
807212578SGlenn.Faden@Sun.COM if (first) {
807312578SGlenn.Faden@Sun.COM first = B_FALSE;
807412578SGlenn.Faden@Sun.COM } else {
807512578SGlenn.Faden@Sun.COM (void) strlcat(new_auths, ",", MAXAUTHS);
807612578SGlenn.Faden@Sun.COM }
807712578SGlenn.Faden@Sun.COM (void) strlcat(new_auths, auth, MAXAUTHS);
807812578SGlenn.Faden@Sun.COM is_zone_admin = B_TRUE;
807912635SGlenn.Faden@Sun.COM new_auth_cnt--;
808012578SGlenn.Faden@Sun.COM right = strtok_r(NULL, ",", &lasts);
808112578SGlenn.Faden@Sun.COM }
808212578SGlenn.Faden@Sun.COM
808312578SGlenn.Faden@Sun.COM /*
808412635SGlenn.Faden@Sun.COM * Need to update the authorizations in user_attr unless
808512635SGlenn.Faden@Sun.COM * the number of old and new authorizations is unchanged
808612635SGlenn.Faden@Sun.COM * and the new auths are a substrings of the old auths.
808712635SGlenn.Faden@Sun.COM *
808812578SGlenn.Faden@Sun.COM * If the user's previous authorizations have changed
808912635SGlenn.Faden@Sun.COM * execute the usermod progam to update them in user_attr.
809012578SGlenn.Faden@Sun.COM */
809112635SGlenn.Faden@Sun.COM if ((new_auth_cnt != 0) ||
809212635SGlenn.Faden@Sun.COM (strstr(old_auths, new_auth_start) == NULL)) {
809312578SGlenn.Faden@Sun.COM char *cmdbuf;
809412578SGlenn.Faden@Sun.COM size_t cmd_len;
809512578SGlenn.Faden@Sun.COM
809612578SGlenn.Faden@Sun.COM update_profiles(rbac_profs, is_zone_admin);
809712578SGlenn.Faden@Sun.COM cmd_len = snprintf(NULL, 0, "%s -A \"%s\" -P \"%s\" %s",
809812578SGlenn.Faden@Sun.COM auths_cmd, new_auths, rbac_profs, user) + 1;
809912578SGlenn.Faden@Sun.COM if ((cmdbuf = malloc(cmd_len)) == NULL) {
810012578SGlenn.Faden@Sun.COM return (Z_NOMEM);
810112578SGlenn.Faden@Sun.COM }
810212578SGlenn.Faden@Sun.COM (void) snprintf(cmdbuf, cmd_len, "%s -A \"%s\" -P \"%s\" %s",
810312578SGlenn.Faden@Sun.COM auths_cmd, new_auths, rbac_profs, user);
810412578SGlenn.Faden@Sun.COM if (do_subproc(zonename, cmdbuf) != 0) {
810512578SGlenn.Faden@Sun.COM free(cmdbuf);
810612578SGlenn.Faden@Sun.COM return (Z_SYSTEM);
810712578SGlenn.Faden@Sun.COM }
810812578SGlenn.Faden@Sun.COM free(cmdbuf);
810912578SGlenn.Faden@Sun.COM }
811012578SGlenn.Faden@Sun.COM
811112578SGlenn.Faden@Sun.COM return (Z_OK);
811212578SGlenn.Faden@Sun.COM }
811312578SGlenn.Faden@Sun.COM
811412578SGlenn.Faden@Sun.COM int
zonecfg_authorize_users(zone_dochandle_t handle,char * zonename)811512578SGlenn.Faden@Sun.COM zonecfg_authorize_users(zone_dochandle_t handle, char *zonename)
811612578SGlenn.Faden@Sun.COM {
811712578SGlenn.Faden@Sun.COM xmlNodePtr cur;
811812578SGlenn.Faden@Sun.COM int err;
811912578SGlenn.Faden@Sun.COM char user[MAXUSERNAME];
812012578SGlenn.Faden@Sun.COM char auths[MAXAUTHS];
812112578SGlenn.Faden@Sun.COM
812212578SGlenn.Faden@Sun.COM if ((err = operation_prep(handle)) != Z_OK)
812312578SGlenn.Faden@Sun.COM return (err);
812412578SGlenn.Faden@Sun.COM
812512578SGlenn.Faden@Sun.COM cur = handle->zone_dh_cur;
812612578SGlenn.Faden@Sun.COM for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
812712578SGlenn.Faden@Sun.COM if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
812812578SGlenn.Faden@Sun.COM continue;
812912578SGlenn.Faden@Sun.COM if (fetchprop(cur, DTD_ATTR_USER, user,
813012578SGlenn.Faden@Sun.COM sizeof (user)) != Z_OK)
813112578SGlenn.Faden@Sun.COM continue;
813212578SGlenn.Faden@Sun.COM if (fetchprop(cur, DTD_ATTR_AUTHS, auths,
813312578SGlenn.Faden@Sun.COM sizeof (auths)) != Z_OK)
813412578SGlenn.Faden@Sun.COM continue;
813512578SGlenn.Faden@Sun.COM if (zonecfg_authorize_user_impl(handle, user, auths, zonename)
813612578SGlenn.Faden@Sun.COM != Z_OK)
813712578SGlenn.Faden@Sun.COM return (Z_SYSTEM);
813812578SGlenn.Faden@Sun.COM }
813912578SGlenn.Faden@Sun.COM (void) zonecfg_remove_userauths(handle, "", "", B_TRUE);
814012578SGlenn.Faden@Sun.COM
814112578SGlenn.Faden@Sun.COM return (Z_OK);
814212578SGlenn.Faden@Sun.COM }
814312578SGlenn.Faden@Sun.COM
814412578SGlenn.Faden@Sun.COM int
zonecfg_deauthorize_user(zone_dochandle_t handle,char * user,char * zonename)814512578SGlenn.Faden@Sun.COM zonecfg_deauthorize_user(zone_dochandle_t handle, char *user, char *zonename)
814612578SGlenn.Faden@Sun.COM {
814712578SGlenn.Faden@Sun.COM return (zonecfg_authorize_user_impl(handle, user, "", zonename));
814812578SGlenn.Faden@Sun.COM }
814912578SGlenn.Faden@Sun.COM
815012578SGlenn.Faden@Sun.COM int
zonecfg_deauthorize_users(zone_dochandle_t handle,char * zonename)815112578SGlenn.Faden@Sun.COM zonecfg_deauthorize_users(zone_dochandle_t handle, char *zonename)
815212578SGlenn.Faden@Sun.COM {
815312578SGlenn.Faden@Sun.COM xmlNodePtr cur;
815412578SGlenn.Faden@Sun.COM int err;
815512578SGlenn.Faden@Sun.COM char user[MAXUSERNAME];
815612578SGlenn.Faden@Sun.COM
815712578SGlenn.Faden@Sun.COM if ((err = operation_prep(handle)) != Z_OK)
815812578SGlenn.Faden@Sun.COM return (err);
815912578SGlenn.Faden@Sun.COM
816012578SGlenn.Faden@Sun.COM cur = handle->zone_dh_cur;
816112578SGlenn.Faden@Sun.COM for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
816212578SGlenn.Faden@Sun.COM if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
816312578SGlenn.Faden@Sun.COM continue;
816412578SGlenn.Faden@Sun.COM if (fetchprop(cur, DTD_ATTR_USER, user,
816512578SGlenn.Faden@Sun.COM sizeof (user)) != Z_OK)
816612578SGlenn.Faden@Sun.COM continue;
816712578SGlenn.Faden@Sun.COM if ((err = zonecfg_deauthorize_user(handle, user,
816812578SGlenn.Faden@Sun.COM zonename)) != Z_OK)
816912578SGlenn.Faden@Sun.COM return (err);
817012578SGlenn.Faden@Sun.COM }
817112578SGlenn.Faden@Sun.COM return (Z_OK);
817212578SGlenn.Faden@Sun.COM }
817312578SGlenn.Faden@Sun.COM
817412578SGlenn.Faden@Sun.COM int
zonecfg_insert_userauths(zone_dochandle_t handle,char * user,char * zonename)817512578SGlenn.Faden@Sun.COM zonecfg_insert_userauths(zone_dochandle_t handle, char *user, char *zonename)
817612578SGlenn.Faden@Sun.COM {
817712578SGlenn.Faden@Sun.COM zone_userauths_t *new, **prev, *next;
817812578SGlenn.Faden@Sun.COM
817912578SGlenn.Faden@Sun.COM prev = &handle->zone_dh_userauths;
818012578SGlenn.Faden@Sun.COM next = *prev;
818112578SGlenn.Faden@Sun.COM while (next) {
818212578SGlenn.Faden@Sun.COM if ((strncmp(next->user, user, MAXUSERNAME) == 0) &&
818312578SGlenn.Faden@Sun.COM (strncmp(next->zonename, zonename,
818412578SGlenn.Faden@Sun.COM ZONENAME_MAX) == 0)) {
818512578SGlenn.Faden@Sun.COM /*
818612578SGlenn.Faden@Sun.COM * user is already in list
818712578SGlenn.Faden@Sun.COM * which isn't supposed to happen!
818812578SGlenn.Faden@Sun.COM */
818912578SGlenn.Faden@Sun.COM return (Z_OK);
819012578SGlenn.Faden@Sun.COM }
819112578SGlenn.Faden@Sun.COM prev = &next->next;
819212578SGlenn.Faden@Sun.COM next = *prev;
819312578SGlenn.Faden@Sun.COM }
819412578SGlenn.Faden@Sun.COM new = (zone_userauths_t *)malloc(sizeof (zone_userauths_t));
819512578SGlenn.Faden@Sun.COM if (new == NULL)
819612578SGlenn.Faden@Sun.COM return (Z_NOMEM);
819712578SGlenn.Faden@Sun.COM
819812578SGlenn.Faden@Sun.COM (void) strlcpy(new->user, user, sizeof (new->user));
819912578SGlenn.Faden@Sun.COM (void) strlcpy(new->zonename, zonename, sizeof (new->zonename));
820012578SGlenn.Faden@Sun.COM new->next = NULL;
820112578SGlenn.Faden@Sun.COM *prev = new;
820212578SGlenn.Faden@Sun.COM return (Z_OK);
820312578SGlenn.Faden@Sun.COM }
820412578SGlenn.Faden@Sun.COM
820512578SGlenn.Faden@Sun.COM int
zonecfg_remove_userauths(zone_dochandle_t handle,char * user,char * zonename,boolean_t deauthorize)820612578SGlenn.Faden@Sun.COM zonecfg_remove_userauths(zone_dochandle_t handle, char *user, char *zonename,
820712578SGlenn.Faden@Sun.COM boolean_t deauthorize)
820812578SGlenn.Faden@Sun.COM {
820912578SGlenn.Faden@Sun.COM zone_userauths_t *new, **prev, *next;
821012578SGlenn.Faden@Sun.COM
821112578SGlenn.Faden@Sun.COM prev = &handle->zone_dh_userauths;
821212578SGlenn.Faden@Sun.COM next = *prev;
821312578SGlenn.Faden@Sun.COM
821412578SGlenn.Faden@Sun.COM while (next) {
821512578SGlenn.Faden@Sun.COM if ((strlen(user) == 0 ||
821612578SGlenn.Faden@Sun.COM strncmp(next->user, user, MAXUSERNAME) == 0) &&
821712578SGlenn.Faden@Sun.COM (strlen(zonename) == 0 ||
821812578SGlenn.Faden@Sun.COM (strncmp(next->zonename, zonename, ZONENAME_MAX) == 0))) {
821912578SGlenn.Faden@Sun.COM new = next;
822012578SGlenn.Faden@Sun.COM *prev = next->next;
822112578SGlenn.Faden@Sun.COM next = *prev;
822212578SGlenn.Faden@Sun.COM if (deauthorize)
822312578SGlenn.Faden@Sun.COM (void) zonecfg_deauthorize_user(handle,
822412578SGlenn.Faden@Sun.COM new->user, new->zonename);
822512578SGlenn.Faden@Sun.COM free(new);
822612578SGlenn.Faden@Sun.COM continue;
822712578SGlenn.Faden@Sun.COM }
822812578SGlenn.Faden@Sun.COM prev = &next->next;
822912578SGlenn.Faden@Sun.COM next = *prev;
823012578SGlenn.Faden@Sun.COM }
823112578SGlenn.Faden@Sun.COM return (Z_OK);
823212578SGlenn.Faden@Sun.COM }
8233