6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2014 Gary Mills
24 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
25 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
26 */
27
28 #include <libsysevent.h>
29 #include <pthread.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <fnmatch.h>
33 #include <strings.h>
34 #include <unistd.h>
35 #include <assert.h>
36 #include <libgen.h>
37 #include <libintl.h>
38 #include <alloca.h>
39 #include <ctype.h>
40 #include <sys/acl.h>
41 #include <sys/stat.h>
42 #include <sys/brand.h>
43 #include <sys/mntio.h>
44 #include <sys/mnttab.h>
45 #include <sys/nvpair.h>
46 #include <sys/types.h>
47 #include <sys/sockio.h>
48 #include <sys/systeminfo.h>
49 #include <ftw.h>
50 #include <pool.h>
51 #include <libscf.h>
52 #include <libproc.h>
53 #include <sys/priocntl.h>
54 #include <libuutil.h>
55 #include <wait.h>
56 #include <bsm/adt.h>
57 #include <auth_attr.h>
58 #include <auth_list.h>
59 #include <secdb.h>
60 #include <user_attr.h>
61 #include <prof_attr.h>
62
63 #include <arpa/inet.h>
64 #include <netdb.h>
65
66 #include <libxml/xmlmemory.h>
67 #include <libxml/parser.h>
68
69 #include <libdevinfo.h>
70 #include <uuid/uuid.h>
71 #include <dirent.h>
72 #include <libbrand.h>
73
74 #include <libzonecfg.h>
75 #include "zonecfg_impl.h"
76
77 #define _PATH_TMPFILE "/zonecfg.XXXXXX"
78 #define ZONE_CB_RETRY_COUNT 10
79 #define ZONE_EVENT_PING_SUBCLASS "ping"
80 #define ZONE_EVENT_PING_PUBLISHER "solaris"
81
82 /* Hard-code the DTD element/attribute/entity names just once, here. */
83 #define DTD_ELEM_ATTR (const xmlChar *) "attr"
84 #define DTD_ELEM_COMMENT (const xmlChar *) "comment"
85 #define DTD_ELEM_DEVICE (const xmlChar *) "device"
86 #define DTD_ELEM_FS (const xmlChar *) "filesystem"
87 #define DTD_ELEM_FSOPTION (const xmlChar *) "fsoption"
88 #define DTD_ELEM_NET (const xmlChar *) "network"
89 #define DTD_ELEM_RCTL (const xmlChar *) "rctl"
90 #define DTD_ELEM_RCTLVALUE (const xmlChar *) "rctl-value"
91 #define DTD_ELEM_ZONE (const xmlChar *) "zone"
92 #define DTD_ELEM_DATASET (const xmlChar *) "dataset"
93 #define DTD_ELEM_TMPPOOL (const xmlChar *) "tmp_pool"
94 #define DTD_ELEM_PSET (const xmlChar *) "pset"
95 #define DTD_ELEM_MCAP (const xmlChar *) "mcap"
96 #define DTD_ELEM_PACKAGE (const xmlChar *) "package"
97 #define DTD_ELEM_OBSOLETES (const xmlChar *) "obsoletes"
98 #define DTD_ELEM_DEV_PERM (const xmlChar *) "dev-perm"
99 #define DTD_ELEM_ADMIN (const xmlChar *) "admin"
100
101 #define DTD_ATTR_ACTION (const xmlChar *) "action"
102 #define DTD_ATTR_ADDRESS (const xmlChar *) "address"
103 #define DTD_ATTR_ALLOWED_ADDRESS (const xmlChar *) "allowed-address"
104 #define DTD_ATTR_AUTOBOOT (const xmlChar *) "autoboot"
105 #define DTD_ATTR_IPTYPE (const xmlChar *) "ip-type"
106 #define DTD_ATTR_DEFROUTER (const xmlChar *) "defrouter"
107 #define DTD_ATTR_DIR (const xmlChar *) "directory"
108 #define DTD_ATTR_LIMIT (const xmlChar *) "limit"
109 #define DTD_ATTR_LIMITPRIV (const xmlChar *) "limitpriv"
110 #define DTD_ATTR_BOOTARGS (const xmlChar *) "bootargs"
111 #define DTD_ATTR_SCHED (const xmlChar *) "scheduling-class"
112 #define DTD_ATTR_MATCH (const xmlChar *) "match"
113 #define DTD_ATTR_NAME (const xmlChar *) "name"
114 #define DTD_ATTR_PHYSICAL (const xmlChar *) "physical"
115 #define DTD_ATTR_POOL (const xmlChar *) "pool"
116 #define DTD_ATTR_PRIV (const xmlChar *) "priv"
117 #define DTD_ATTR_RAW (const xmlChar *) "raw"
118 #define DTD_ATTR_SPECIAL (const xmlChar *) "special"
119 #define DTD_ATTR_TYPE (const xmlChar *) "type"
120 #define DTD_ATTR_VALUE (const xmlChar *) "value"
121 #define DTD_ATTR_ZONEPATH (const xmlChar *) "zonepath"
122 #define DTD_ATTR_NCPU_MIN (const xmlChar *) "ncpu_min"
123 #define DTD_ATTR_NCPU_MAX (const xmlChar *) "ncpu_max"
124 #define DTD_ATTR_IMPORTANCE (const xmlChar *) "importance"
125 #define DTD_ATTR_PHYSCAP (const xmlChar *) "physcap"
126 #define DTD_ATTR_VERSION (const xmlChar *) "version"
127 #define DTD_ATTR_ID (const xmlChar *) "id"
128 #define DTD_ATTR_UID (const xmlChar *) "uid"
129 #define DTD_ATTR_GID (const xmlChar *) "gid"
130 #define DTD_ATTR_MODE (const xmlChar *) "mode"
131 #define DTD_ATTR_ACL (const xmlChar *) "acl"
132 #define DTD_ATTR_BRAND (const xmlChar *) "brand"
133 #define DTD_ATTR_HOSTID (const xmlChar *) "hostid"
134 #define DTD_ATTR_USER (const xmlChar *) "user"
135 #define DTD_ATTR_AUTHS (const xmlChar *) "auths"
136 #define DTD_ATTR_FS_ALLOWED (const xmlChar *) "fs-allowed"
137
138 #define DTD_ENTITY_BOOLEAN "boolean"
139 #define DTD_ENTITY_DEVPATH "devpath"
140 #define DTD_ENTITY_DRIVER "driver"
141 #define DTD_ENTITY_DRVMIN "drv_min"
142 #define DTD_ENTITY_FALSE "false"
143 #define DTD_ENTITY_INT "int"
144 #define DTD_ENTITY_STRING "string"
145 #define DTD_ENTITY_TRUE "true"
146 #define DTD_ENTITY_UINT "uint"
147
148 #define DTD_ENTITY_BOOL_LEN 6 /* "false" */
149
150 #define ATTACH_FORCED "SUNWattached.xml"
151
152 #define TMP_POOL_NAME "SUNWtmp_%s"
159 *
160 * This holds the alias, the full rctl name, the default priv value, action
161 * and lower limit. The functions that handle rctl aliases step through
162 * this table, matching on the alias, and using the full values for setting
163 * the rctl entry as well the limit for validation.
164 */
165 static struct alias {
166 char *shortname;
167 char *realname;
168 char *priv;
169 char *action;
170 uint64_t low_limit;
171 } aliases[] = {
172 {ALIAS_MAXLWPS, "zone.max-lwps", "privileged", "deny", 100},
173 {ALIAS_MAXSHMMEM, "zone.max-shm-memory", "privileged", "deny", 0},
174 {ALIAS_MAXSHMIDS, "zone.max-shm-ids", "privileged", "deny", 0},
175 {ALIAS_MAXMSGIDS, "zone.max-msg-ids", "privileged", "deny", 0},
176 {ALIAS_MAXSEMIDS, "zone.max-sem-ids", "privileged", "deny", 0},
177 {ALIAS_MAXLOCKEDMEM, "zone.max-locked-memory", "privileged", "deny", 0},
178 {ALIAS_MAXSWAP, "zone.max-swap", "privileged", "deny", 0},
179 {ALIAS_SHARES, "zone.cpu-shares", "privileged", "none", 0},
180 {ALIAS_CPUCAP, "zone.cpu-cap", "privileged", "deny", 0},
181 {ALIAS_MAXPROCS, "zone.max-processes", "privileged", "deny", 100},
182 {NULL, NULL, NULL, NULL, 0}
183 };
184
185 /*
186 * Structure for applying rctls to a running zone. It allows important
187 * process values to be passed together easily.
188 */
189 typedef struct pr_info_handle {
190 struct ps_prochandle *pr;
191 pid_t pid;
192 } pr_info_handle_t;
193
194 struct zone_dochandle {
195 char *zone_dh_rootdir;
196 xmlDocPtr zone_dh_doc;
197 xmlNodePtr zone_dh_cur;
198 xmlNodePtr zone_dh_top;
252 }
253
254 const char *
255 zonecfg_get_root(void)
256 {
257 return (zonecfg_root);
258 }
259
260 boolean_t
261 zonecfg_in_alt_root(void)
262 {
263 return (*zonecfg_root != '\0');
264 }
265
266 /*
267 * Callers of the _file_path() functions are expected to have the second
268 * parameter be a (char foo[MAXPATHLEN]).
269 */
270
271 static boolean_t
272 config_file_path(const char *zonename, char *answer)
273 {
274 return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root,
275 ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN);
276 }
277
278 static boolean_t
279 snap_file_path(const char *zonename, char *answer)
280 {
281 return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml",
282 zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN);
283 }
284
285 /*ARGSUSED*/
286 static void
287 zonecfg_error_func(void *ctx, const char *msg, ...)
288 {
289 /*
290 * This function does nothing by design. Its purpose is to prevent
291 * libxml from dumping unwanted messages to stdout/stderr.
292 */
293 }
294
295 zone_dochandle_t
296 zonecfg_init_handle(void)
297 {
298 zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle));
299 if (handle == NULL) {
300 errno = Z_NOMEM;
301 return (NULL);
302 }
303
304 /* generic libxml initialization */
333 zonecfg_destroy_impl(char *filename)
334 {
335 if (unlink(filename) == -1) {
336 if (errno == EACCES)
337 return (Z_ACCES);
338 if (errno == ENOENT)
339 return (Z_NO_ZONE);
340 return (Z_MISC_FS);
341 }
342 return (Z_OK);
343 }
344
345 int
346 zonecfg_destroy(const char *zonename, boolean_t force)
347 {
348 char path[MAXPATHLEN];
349 struct zoneent ze;
350 int err, state_err;
351 zone_state_t state;
352
353 if (!config_file_path(zonename, path))
354 return (Z_MISC_FS);
355
356 state_err = zone_get_state((char *)zonename, &state);
357 err = access(path, W_OK);
358
359 /*
360 * If there is no file, and no index entry, reliably indicate that no
361 * such zone exists.
362 */
363 if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT))
364 return (Z_NO_ZONE);
365
366 /*
367 * Handle any other filesystem related errors (except if the XML
368 * file is missing, which we treat silently), unless we're forcing,
369 * in which case we plow on.
370 */
371 if (err == -1 && errno != ENOENT) {
372 if (errno == EACCES)
373 return (Z_ACCES);
390 if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK)
391 if (!force)
392 return (err);
393
394 err = zonecfg_destroy_impl(path);
395
396 /*
397 * Treat failure to find the XML file silently, since, well, it's
398 * gone, and with the index file cleaned up, we're done.
399 */
400 if (err == Z_OK || err == Z_NO_ZONE)
401 return (Z_OK);
402 return (err);
403 }
404
405 int
406 zonecfg_destroy_snapshot(const char *zonename)
407 {
408 char path[MAXPATHLEN];
409
410 if (!snap_file_path(zonename, path))
411 return (Z_MISC_FS);
412 return (zonecfg_destroy_impl(path));
413 }
414
415 static int
416 getroot(zone_dochandle_t handle, xmlNodePtr *root)
417 {
418 if (zonecfg_check_handle(handle) == Z_BAD_HANDLE)
419 return (Z_BAD_HANDLE);
420
421 *root = xmlDocGetRootElement(handle->zone_dh_doc);
422
423 if (*root == NULL)
424 return (Z_EMPTY_DOCUMENT);
425
426 if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE))
427 return (Z_WRONG_DOC_TYPE);
428
429 return (Z_OK);
430 }
557 {
558 xmlNodePtr root, child, next;
559
560 root = xmlDocGetRootElement(handle->zone_dh_doc);
561 for (child = root->xmlChildrenNode; child != NULL; child = next) {
562 next = child->next;
563 if (child->name == NULL)
564 continue;
565 if (xmlStrcmp(child->name, DTD_ELEM_PACKAGE) == 0) {
566 next = child->next;
567 xmlUnlinkNode(child);
568 xmlFreeNode(child);
569 }
570 }
571 }
572
573 static int
574 zonecfg_get_handle_impl(const char *zonename, const char *filename,
575 zone_dochandle_t handle)
576 {
577 xmlValidCtxtPtr cvp;
578 struct stat statbuf;
579 int valid;
580
581 if (zonename == NULL)
582 return (Z_NO_ZONE);
583
584 if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) {
585 /* distinguish file not found vs. found but not parsed */
586 if (stat(filename, &statbuf) == 0)
587 return (Z_INVALID_DOCUMENT);
588 return (Z_NO_ZONE);
589 }
590 if ((cvp = xmlNewValidCtxt()) == NULL)
591 return (Z_NOMEM);
592 cvp->error = zonecfg_error_func;
593 cvp->warning = zonecfg_error_func;
594 valid = xmlValidateDocument(cvp, handle->zone_dh_doc);
595 xmlFreeValidCtxt(cvp);
596 if (valid == 0)
597 return (Z_INVALID_DOCUMENT);
598
599 /* delete any comments such as inherited Sun copyright / ident str */
600 stripcomments(handle);
601 return (Z_OK);
602 }
603
604 int
605 zonecfg_get_handle(const char *zonename, zone_dochandle_t handle)
606 {
607 char path[MAXPATHLEN];
608
609 if (!config_file_path(zonename, path))
610 return (Z_MISC_FS);
611 handle->zone_dh_newzone = B_FALSE;
612
613 return (zonecfg_get_handle_impl(zonename, path, handle));
614 }
615
616 int
617 zonecfg_get_attach_handle(const char *path, const char *fname,
618 const char *zonename, boolean_t preserve_sw, zone_dochandle_t handle)
619 {
620 char migpath[MAXPATHLEN];
621 int err;
622 struct stat buf;
623
624 if (snprintf(migpath, sizeof (migpath), "%s/root", path) >=
625 sizeof (migpath))
626 return (Z_NOMEM);
627
628 if (stat(migpath, &buf) == -1 || !S_ISDIR(buf.st_mode))
629 return (Z_NO_ZONE);
633 return (Z_NOMEM);
634
635 if ((err = zonecfg_get_handle_impl(zonename, migpath, handle)) != Z_OK)
636 return (err);
637
638 if (!preserve_sw)
639 strip_sw_inv(handle);
640
641 handle->zone_dh_newzone = B_TRUE;
642 if ((err = setrootattr(handle, DTD_ATTR_ZONEPATH, path)) != Z_OK)
643 return (err);
644
645 return (setrootattr(handle, DTD_ATTR_NAME, zonename));
646 }
647
648 int
649 zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle)
650 {
651 char path[MAXPATHLEN];
652
653 if (!snap_file_path(zonename, path))
654 return (Z_MISC_FS);
655 handle->zone_dh_newzone = B_FALSE;
656 return (zonecfg_get_handle_impl(zonename, path, handle));
657 }
658
659 int
660 zonecfg_get_template_handle(const char *template, const char *zonename,
661 zone_dochandle_t handle)
662 {
663 char path[MAXPATHLEN];
664 int err;
665
666 if (!config_file_path(template, path))
667 return (Z_MISC_FS);
668
669 if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK)
670 return (err);
671 handle->zone_dh_newzone = B_TRUE;
672 return (setrootattr(handle, DTD_ATTR_NAME, zonename));
673 }
674
675 int
676 zonecfg_get_xml_handle(const char *path, zone_dochandle_t handle)
677 {
678 struct stat buf;
679 int err;
680
681 if (stat(path, &buf) == -1)
682 return (Z_MISC_FS);
683
684 if ((err = zonecfg_get_handle_impl("xml", path, handle)) != Z_OK)
685 return (err);
686 handle->zone_dh_newzone = B_TRUE;
687 return (Z_OK);
688 }
689
690 /*
691 * Initialize two handles from the manifest read on fd. The rem_handle
692 * is initialized from the input file, including the sw inventory. The
693 * local_handle is initialized with the same zone configuration but with
694 * no sw inventory.
695 */
696 int
697 zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle,
698 zone_dochandle_t rem_handle)
699 {
700 xmlValidCtxtPtr cvp;
701 int valid;
702
703 /* load the manifest into the handle for the remote system */
704 if ((rem_handle->zone_dh_doc = xmlReadFd(fd, NULL, NULL, 0)) == NULL) {
705 return (Z_INVALID_DOCUMENT);
706 }
707 if ((cvp = xmlNewValidCtxt()) == NULL)
708 return (Z_NOMEM);
709 cvp->error = zonecfg_error_func;
710 cvp->warning = zonecfg_error_func;
711 valid = xmlValidateDocument(cvp, rem_handle->zone_dh_doc);
712 xmlFreeValidCtxt(cvp);
713 if (valid == 0)
714 return (Z_INVALID_DOCUMENT);
715
716 /* delete any comments such as inherited Sun copyright / ident str */
717 stripcomments(rem_handle);
718
719 rem_handle->zone_dh_newzone = B_TRUE;
720 rem_handle->zone_dh_sw_inv = B_TRUE;
721
722 /*
723 * Now use the remote system handle to generate a local system handle
724 * with an identical zones configuration but no sw inventory.
725 */
726 if ((local_handle->zone_dh_doc = xmlCopyDoc(rem_handle->zone_dh_doc,
727 1)) == NULL) {
728 return (Z_INVALID_DOCUMENT);
729 }
730
731 /*
732 * We need to re-run xmlValidateDocument on local_handle to properly
733 * update the in-core representation of the configuration.
734 */
735 if ((cvp = xmlNewValidCtxt()) == NULL)
736 return (Z_NOMEM);
737 cvp->error = zonecfg_error_func;
738 cvp->warning = zonecfg_error_func;
739 valid = xmlValidateDocument(cvp, local_handle->zone_dh_doc);
740 xmlFreeValidCtxt(cvp);
741 if (valid == 0)
742 return (Z_INVALID_DOCUMENT);
743
744 strip_sw_inv(local_handle);
745
746 local_handle->zone_dh_newzone = B_TRUE;
747 local_handle->zone_dh_sw_inv = B_FALSE;
748
749 return (Z_OK);
750 }
751
752 static boolean_t
753 is_renaming(zone_dochandle_t handle)
754 {
755 if (handle->zone_dh_newzone)
756 return (B_FALSE);
757 if (strlen(handle->zone_dh_delete_name) > 0)
758 return (B_TRUE);
759 return (B_FALSE);
760 }
761
762 static boolean_t
1176 * Save existing zone 'foo':
1177 * Make backup of foo.xml -> .backup
1178 * Create tmpfile (zonecfg.xxxxxx)
1179 * Write XML to tmpfile
1180 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
1181 * Modify index file as needed
1182 * If it fails, recover from .backup -> foo.xml
1183 *
1184 * Rename 'foo' to 'bar':
1185 * Create tmpfile (zonecfg.xxxxxx)
1186 * Write XML to tmpfile
1187 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml)
1188 * Add entry for 'bar' to index file, Remove entry for 'foo' (refresh)
1189 * If it fails, delete bar.xml; foo.xml is left behind.
1190 */
1191 static int
1192 zonecfg_save_impl(zone_dochandle_t handle, char *filename)
1193 {
1194 char tmpfile[MAXPATHLEN];
1195 char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN];
1196 int tmpfd, err, valid;
1197 xmlValidCtxt cvp = { NULL };
1198 boolean_t backup;
1199
1200 (void) strlcpy(tmpfile, filename, sizeof (tmpfile));
1201 (void) dirname(tmpfile);
1202 (void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile));
1203
1204 tmpfd = mkstemp(tmpfile);
1205 if (tmpfd == -1) {
1206 (void) unlink(tmpfile);
1207 return (Z_TEMP_FILE);
1208 }
1209 (void) close(tmpfd);
1210
1211 cvp.error = zonecfg_error_func;
1212 cvp.warning = zonecfg_error_func;
1213
1214 /*
1215 * We do a final validation of the document. Since the library has
1216 * malfunctioned if it fails to validate, we follow-up with an
1217 * assert() that the doc is valid.
1218 */
1219 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1220 assert(valid != 0);
1221
1222 if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0)
1223 goto err;
1224
1225 (void) chmod(tmpfile, 0644);
1226
1227 /*
1228 * In the event we are doing a standard save, hard link a copy of the
1229 * original file in .backup.<pid>.filename so we can restore it if
1230 * something goes wrong.
1231 */
1232 if (!is_new(handle) && !is_renaming(handle)) {
1233 backup = B_TRUE;
1234
1235 (void) strlcpy(bakdir, filename, sizeof (bakdir));
1236 (void) strlcpy(bakbase, filename, sizeof (bakbase));
1237 (void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s",
1238 dirname(bakdir), getpid(), basename(bakbase));
1239
1240 if (link(filename, bakfile) == -1) {
1255 (void) unlink(tmpfile);
1256 if (backup)
1257 (void) unlink(bakfile);
1258 if (err == EACCES)
1259 return (Z_ACCES);
1260 return (Z_MISC_FS);
1261 }
1262
1263 /*
1264 * If this is a snapshot, we're done-- don't add an index entry.
1265 */
1266 if (is_snapshot(handle))
1267 return (Z_OK);
1268
1269 /* now update the index file to reflect whatever we just did */
1270 if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) {
1271 if (backup) {
1272 /*
1273 * Try to restore from our backup.
1274 */
1275 (void) unlink(filename);
1276 (void) rename(bakfile, filename);
1277 } else {
1278 /*
1279 * Either the zone is new, in which case we can delete
1280 * new.xml, or we're doing a rename, so ditto.
1281 */
1282 assert(is_new(handle) || is_renaming(handle));
1283 (void) unlink(filename);
1284 }
1285 return (Z_UPDATING_INDEX);
1286 }
1287
1288 if (backup)
1289 (void) unlink(bakfile);
1290
1291 return (Z_OK);
1292
1293 err:
1294 (void) unlink(tmpfile);
1295 return (Z_SAVING_FILE);
1298 int
1299 zonecfg_save(zone_dochandle_t handle)
1300 {
1301 char zname[ZONENAME_MAX], path[MAXPATHLEN];
1302 char delpath[MAXPATHLEN];
1303 int err = Z_SAVING_FILE;
1304
1305 if (zonecfg_check_handle(handle) != Z_OK)
1306 return (Z_BAD_HANDLE);
1307
1308 /*
1309 * We don't support saving snapshots or a tree containing a sw
1310 * inventory at this time.
1311 */
1312 if (handle->zone_dh_snapshot || handle->zone_dh_sw_inv)
1313 return (Z_INVAL);
1314
1315 if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK)
1316 return (err);
1317
1318 if (!config_file_path(zname, path))
1319 return (Z_MISC_FS);
1320
1321 addcomment(handle, "\n DO NOT EDIT THIS "
1322 "FILE. Use zonecfg(1M) instead.\n");
1323
1324 /*
1325 * Update user_attr first so that it will be older
1326 * than the config file.
1327 */
1328 (void) zonecfg_authorize_users(handle, zname);
1329 err = zonecfg_save_impl(handle, path);
1330
1331 stripcomments(handle);
1332
1333 if (err != Z_OK)
1334 return (err);
1335
1336 handle->zone_dh_newzone = B_FALSE;
1337
1338 if (is_renaming(handle)) {
1339 if (config_file_path(handle->zone_dh_delete_name, delpath))
1340 (void) unlink(delpath);
1341 handle->zone_dh_delete_name[0] = '\0';
1342 }
1343
1344 return (Z_OK);
1345 }
1346
1347 int
1348 zonecfg_verify_save(zone_dochandle_t handle, char *filename)
1349 {
1350 int valid;
1351
1352 xmlValidCtxt cvp = { NULL };
1353
1354 if (zonecfg_check_handle(handle) != Z_OK)
1355 return (Z_BAD_HANDLE);
1356
1357 cvp.error = zonecfg_error_func;
1358 cvp.warning = zonecfg_error_func;
1359
1360 /*
1361 * We do a final validation of the document. Since the library has
1362 * malfunctioned if it fails to validate, we follow-up with an
1363 * assert() that the doc is valid.
1364 */
1365 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1366 assert(valid != 0);
1367
1368 if (xmlSaveFormatFile(filename, handle->zone_dh_doc, 1) <= 0)
1369 return (Z_SAVING_FILE);
1370
1371 return (Z_OK);
1372 }
1373
1374 int
1375 zonecfg_detach_save(zone_dochandle_t handle, uint_t flags)
1376 {
1377 char zname[ZONENAME_MAX];
1378 char path[MAXPATHLEN];
1379 char migpath[MAXPATHLEN];
1380 xmlValidCtxt cvp = { NULL };
1381 int err = Z_SAVING_FILE;
1382 int valid;
1383
1384 if (zonecfg_check_handle(handle) != Z_OK)
1385 return (Z_BAD_HANDLE);
1386
1387 if (flags & ZONE_DRY_RUN) {
1388 (void) strlcpy(migpath, "-", sizeof (migpath));
1389 } else {
1390 if ((err = zonecfg_get_name(handle, zname, sizeof (zname)))
1391 != Z_OK)
1392 return (err);
1393
1394 if ((err = zone_get_zonepath(zname, path, sizeof (path)))
1395 != Z_OK)
1396 return (err);
1397
1398 if (snprintf(migpath, sizeof (migpath), "%s/%s", path,
1399 ZONE_DETACHED) >= sizeof (migpath))
1400 return (Z_NOMEM);
1401 }
1402
1403 if ((err = operation_prep(handle)) != Z_OK)
1404 return (err);
1405
1406 addcomment(handle, "\n DO NOT EDIT THIS FILE. "
1407 "Use zonecfg(1M) and zoneadm(1M) attach.\n");
1408
1409 cvp.error = zonecfg_error_func;
1410 cvp.warning = zonecfg_error_func;
1411
1412 /*
1413 * We do a final validation of the document. Since the library has
1414 * malfunctioned if it fails to validate, we follow-up with an
1415 * assert() that the doc is valid.
1416 */
1417 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1418 assert(valid != 0);
1419
1420 if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0)
1421 return (Z_SAVING_FILE);
1422
1423 if (!(flags & ZONE_DRY_RUN))
1424 (void) chmod(migpath, 0644);
1425
1426 stripcomments(handle);
1427
1428 handle->zone_dh_newzone = B_FALSE;
1429
1430 return (Z_OK);
1431 }
1432
1433 boolean_t
1434 zonecfg_detached(const char *path)
1435 {
1436 char migpath[MAXPATHLEN];
1437 struct stat buf;
1438
1471 if (forced) {
1472 (void) rename(detached, attached);
1473 } else {
1474 (void) unlink(attached);
1475 (void) unlink(detached);
1476 }
1477 }
1478
1479 /*
1480 * Special case: if access(2) fails with ENOENT, then try again using
1481 * ZONE_CONFIG_ROOT instead of config_file_path(zonename). This is how we
1482 * work around the case of a config file which has not been created yet:
1483 * the user will need access to the directory so use that as a heuristic.
1484 */
1485
1486 int
1487 zonecfg_access(const char *zonename, int amode)
1488 {
1489 char path[MAXPATHLEN];
1490
1491 if (!config_file_path(zonename, path))
1492 return (Z_INVAL);
1493 if (access(path, amode) == 0)
1494 return (Z_OK);
1495 if (errno == ENOENT) {
1496 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1497 ZONE_CONFIG_ROOT) >= sizeof (path))
1498 return (Z_INVAL);
1499 if (access(path, amode) == 0)
1500 return (Z_OK);
1501 }
1502 if (errno == EACCES)
1503 return (Z_ACCES);
1504 if (errno == EINVAL)
1505 return (Z_INVAL);
1506 return (Z_MISC_FS);
1507 }
1508
1509 int
1510 zonecfg_create_snapshot(const char *zonename)
1511 {
1536 * save the resolved path in the snapshot, thus preventing any
1537 * potential problems down the line when zoneadmd goes to unmount
1538 * file systems and depends on initial string matches with resolved
1539 * paths.
1540 */
1541 rpath[res] = '\0';
1542 if (strcmp(zonepath, rpath) != 0) {
1543 if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK)
1544 goto out;
1545 }
1546 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1547 ZONE_SNAPSHOT_ROOT) >= sizeof (path)) {
1548 error = Z_MISC_FS;
1549 goto out;
1550 }
1551 if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) {
1552 error = Z_MISC_FS;
1553 goto out;
1554 }
1555
1556 if (!snap_file_path(zonename, path)) {
1557 error = Z_MISC_FS;
1558 goto out;
1559 }
1560
1561 addcomment(handle, "\n DO NOT EDIT THIS FILE. "
1562 "It is a snapshot of running zone state.\n");
1563
1564 error = zonecfg_save_impl(handle, path);
1565
1566 stripcomments(handle);
1567
1568 out:
1569 zonecfg_fini_handle(handle);
1570 return (error);
1571 }
1572
1573 int
1574 zonecfg_get_iptype(zone_dochandle_t handle, zone_iptype_t *iptypep)
1575 {
1576 char property[10]; /* 10 is big enough for "shared"/"exclusive" */
2067
2068 /*
2069 * Determines whether there is a net resource with the physical interface, IP
2070 * address, and default router specified by 'tabptr' in the zone configuration
2071 * to which 'handle' refers. 'tabptr' must have an interface, an address, a
2072 * default router, or a combination of the three. This function returns Z_OK
2073 * iff there is exactly one net resource matching the query specified by
2074 * 'tabptr'. The function returns Z_INSUFFICIENT_SPEC if there are multiple
2075 * matches or 'tabptr' does not specify a physical interface, address, or
2076 * default router. The function returns Z_NO_RESOURCE_ID if are no matches.
2077 *
2078 * Errors might also be returned if the entry that exactly matches the
2079 * query lacks critical network resource information.
2080 *
2081 * If there is a single match, then the matching entry's physical interface, IP
2082 * address, and default router information are stored in 'tabptr'.
2083 */
2084 int
2085 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2086 {
2087 xmlNodePtr cur;
2088 xmlNodePtr firstmatch;
2089 int err;
2090 char address[INET6_ADDRSTRLEN];
2091 char physical[LIFNAMSIZ];
2092 size_t addrspec; /* nonzero if tabptr has IP addr */
2093 size_t physspec; /* nonzero if tabptr has interface */
2094 size_t defrouterspec; /* nonzero if tabptr has def. router */
2095 size_t allowed_addrspec;
2096 zone_iptype_t iptype;
2097
2098 if (tabptr == NULL)
2099 return (Z_INVAL);
2100
2101 /*
2102 * Determine the fields that will be searched. There must be at least
2103 * one.
2104 *
2105 * zone_nwif_address, zone_nwif_physical, and zone_nwif_defrouter are
2106 * arrays, so no NULL checks are necessary.
2107 */
2108 addrspec = strlen(tabptr->zone_nwif_address);
2109 physspec = strlen(tabptr->zone_nwif_physical);
2110 defrouterspec = strlen(tabptr->zone_nwif_defrouter);
2111 allowed_addrspec = strlen(tabptr->zone_nwif_allowed_address);
2112 if (addrspec != 0 && allowed_addrspec != 0)
2113 return (Z_INVAL); /* can't specify both */
2114 if (addrspec == 0 && physspec == 0 && defrouterspec == 0 &&
2115 allowed_addrspec == 0)
2116 return (Z_INSUFFICIENT_SPEC);
2117
2118 if ((err = operation_prep(handle)) != Z_OK)
2119 return (err);
2120
2121 if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK)
2122 return (err);
2123 /*
2124 * Iterate over the configuration's elements and look for net elements
2125 * that match the query.
2126 */
2127 firstmatch = NULL;
2128 cur = handle->zone_dh_cur;
2129 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2130 /* Skip non-net elements */
2131 if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2132 continue;
2133
2134 /*
2135 * If any relevant fields don't match the query, then skip
2136 * the current net element.
2137 */
2138 if (physspec != 0 && (fetchprop(cur, DTD_ATTR_PHYSICAL,
2139 physical, sizeof (physical)) != Z_OK ||
2140 strcmp(tabptr->zone_nwif_physical, physical) != 0))
2141 continue;
2142 if (iptype == ZS_SHARED && addrspec != 0 &&
2143 (fetchprop(cur, DTD_ATTR_ADDRESS, address,
2144 sizeof (address)) != Z_OK ||
2145 !zonecfg_same_net_address(tabptr->zone_nwif_address,
2146 address)))
2147 continue;
2148 if (iptype == ZS_EXCLUSIVE && allowed_addrspec != 0 &&
2149 (fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS, address,
2150 sizeof (address)) != Z_OK ||
2151 !zonecfg_same_net_address(tabptr->zone_nwif_allowed_address,
2152 address)))
2153 continue;
2154 if (defrouterspec != 0 && (fetchprop(cur, DTD_ATTR_DEFROUTER,
2155 address, sizeof (address)) != Z_OK ||
2156 !zonecfg_same_net_address(tabptr->zone_nwif_defrouter,
2157 address)))
2158 continue;
2159
2160 /*
2161 * The current net element matches the query. Select it if
2164 if (firstmatch == NULL)
2165 firstmatch = cur;
2166 else
2167 return (Z_INSUFFICIENT_SPEC);
2168 }
2169 if (firstmatch == NULL)
2170 return (Z_NO_RESOURCE_ID);
2171
2172 cur = firstmatch;
2173
2174 if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
2175 sizeof (tabptr->zone_nwif_physical))) != Z_OK)
2176 return (err);
2177
2178 if (iptype == ZS_SHARED &&
2179 (err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
2180 sizeof (tabptr->zone_nwif_address))) != Z_OK)
2181 return (err);
2182
2183 if (iptype == ZS_EXCLUSIVE &&
2184 (err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
2185 tabptr->zone_nwif_allowed_address,
2186 sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK)
2187 return (err);
2188
2189 if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
2190 tabptr->zone_nwif_defrouter,
2191 sizeof (tabptr->zone_nwif_defrouter))) != Z_OK)
2192 return (err);
2193
2194 return (Z_OK);
2195 }
2196
2197 static int
2198 zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2199 {
2200 xmlNodePtr newnode, cur = handle->zone_dh_cur;
2201 int err;
2202
2203 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL);
2204 if (strlen(tabptr->zone_nwif_address) > 0 &&
2205 (err = newprop(newnode, DTD_ATTR_ADDRESS,
2206 tabptr->zone_nwif_address)) != Z_OK)
2207 return (err);
2208 if (strlen(tabptr->zone_nwif_allowed_address) > 0 &&
2209 (err = newprop(newnode, DTD_ATTR_ALLOWED_ADDRESS,
2210 tabptr->zone_nwif_allowed_address)) != Z_OK)
2211 return (err);
2212 if ((err = newprop(newnode, DTD_ATTR_PHYSICAL,
2213 tabptr->zone_nwif_physical)) != Z_OK)
2214 return (err);
2215 /*
2216 * Do not add this property when it is not set, for backwards
2217 * compatibility and because it is optional.
2218 */
2219 if ((strlen(tabptr->zone_nwif_defrouter) > 0) &&
2220 ((err = newprop(newnode, DTD_ATTR_DEFROUTER,
2221 tabptr->zone_nwif_defrouter)) != Z_OK))
2222 return (err);
2223 return (Z_OK);
2224 }
2225
2226 int
2227 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2228 {
2229 int err;
2230
2231 if (tabptr == NULL)
2232 return (Z_INVAL);
2233
2234 if ((err = operation_prep(handle)) != Z_OK)
2235 return (err);
2236
2237 if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK)
2238 return (err);
2239
2240 return (Z_OK);
2241 }
2242
2243 static int
2244 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2245 {
2246 xmlNodePtr cur = handle->zone_dh_cur;
2247 boolean_t addr_match, phys_match, allowed_addr_match;
2248
2249 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2250 if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2251 continue;
2252
2253 addr_match = match_prop(cur, DTD_ATTR_ADDRESS,
2254 tabptr->zone_nwif_address);
2255 allowed_addr_match = match_prop(cur, DTD_ATTR_ALLOWED_ADDRESS,
2256 tabptr->zone_nwif_allowed_address);
2257 phys_match = match_prop(cur, DTD_ATTR_PHYSICAL,
2258 tabptr->zone_nwif_physical);
2259
2260 if (addr_match && allowed_addr_match && phys_match) {
2261 xmlUnlinkNode(cur);
2262 xmlFreeNode(cur);
2263 return (Z_OK);
2264 }
2265 }
2266 return (Z_NO_RESOURCE_ID);
2267 }
2268
2269 int
2270 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2271 {
2272 int err;
2273
2274 if (tabptr == NULL)
2275 return (Z_INVAL);
2276
2277 if ((err = operation_prep(handle)) != Z_OK)
2278 return (err);
2279
2280 if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK)
2289 struct zone_nwiftab *oldtabptr,
2290 struct zone_nwiftab *newtabptr)
2291 {
2292 int err;
2293
2294 if (oldtabptr == NULL || newtabptr == NULL)
2295 return (Z_INVAL);
2296
2297 if ((err = operation_prep(handle)) != Z_OK)
2298 return (err);
2299
2300 if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK)
2301 return (err);
2302
2303 if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK)
2304 return (err);
2305
2306 return (Z_OK);
2307 }
2308
2309 /*
2310 * Must be a comma-separated list of alpha-numeric file system names.
2311 */
2312 static int
2313 zonecfg_valid_fs_allowed(const char *fsallowedp)
2314 {
2315 char tmp[ZONE_FS_ALLOWED_MAX];
2316 char *cp = tmp;
2317 char *p;
2318
2319 if (strlen(fsallowedp) > ZONE_FS_ALLOWED_MAX)
2320 return (Z_TOO_BIG);
2321
2322 (void) strlcpy(tmp, fsallowedp, sizeof (tmp));
2323
2324 while (*cp != '\0') {
2325 p = cp;
2326 while (*p != '\0' && *p != ',') {
2327 if (!isalnum(*p) && *p != '-')
2328 return (Z_INVALID_PROPERTY);
2438 * attribute is cleared. Non-NULL hostids are validated. This function returns
2439 * Z_OK on success. Any other return value indicates failure.
2440 */
2441 int
2442 zonecfg_set_hostid(zone_dochandle_t handle, const char *hostidp)
2443 {
2444 int err;
2445
2446 /*
2447 * A NULL hostid string is interpreted as a request to clear the
2448 * hostid.
2449 */
2450 if (hostidp == NULL || (err = zonecfg_valid_hostid(hostidp)) == Z_OK)
2451 return (setrootattr(handle, DTD_ATTR_HOSTID, hostidp));
2452 return (err);
2453 }
2454
2455 int
2456 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2457 {
2458 xmlNodePtr cur, firstmatch;
2459 int err;
2460 char match[MAXPATHLEN];
2461
2462 if (tabptr == NULL)
2463 return (Z_INVAL);
2464
2465 if ((err = operation_prep(handle)) != Z_OK)
2466 return (err);
2467
2468 cur = handle->zone_dh_cur;
2469 firstmatch = NULL;
2470 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2471 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2472 continue;
2473 if (strlen(tabptr->zone_dev_match) == 0)
2474 continue;
2475
2476 if ((fetchprop(cur, DTD_ATTR_MATCH, match,
2477 sizeof (match)) == Z_OK)) {
2478 if (strcmp(tabptr->zone_dev_match,
2483 return (Z_INSUFFICIENT_SPEC);
2484 } else {
2485 /*
2486 * If another property matched but this
2487 * one doesn't then reset firstmatch.
2488 */
2489 if (firstmatch == cur)
2490 firstmatch = NULL;
2491 }
2492 }
2493 }
2494 if (firstmatch == NULL)
2495 return (Z_NO_RESOURCE_ID);
2496
2497 cur = firstmatch;
2498
2499 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
2500 sizeof (tabptr->zone_dev_match))) != Z_OK)
2501 return (err);
2502
2503 return (Z_OK);
2504 }
2505
2506 static int
2507 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
2508 {
2509 xmlNodePtr newnode, cur = handle->zone_dh_cur;
2510 int err;
2511
2512 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL);
2513
2514 if ((err = newprop(newnode, DTD_ATTR_MATCH,
2515 tabptr->zone_dev_match)) != Z_OK)
2516 return (err);
2517
2518 return (Z_OK);
2519 }
2520
2521 int
2522 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2523 {
2524 int err;
2525
2526 if (tabptr == NULL)
2527 return (Z_INVAL);
2528
2529 if ((err = operation_prep(handle)) != Z_OK)
2530 return (err);
2531
2532 if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK)
2533 return (err);
2534
2535 return (Z_OK);
2536 }
2537
4695
4696 handle->zone_dh_cur = cur->next;
4697 return (Z_OK);
4698 }
4699
4700 int
4701 zonecfg_endfsent(zone_dochandle_t handle)
4702 {
4703 return (zonecfg_endent(handle));
4704 }
4705
4706 int
4707 zonecfg_setnwifent(zone_dochandle_t handle)
4708 {
4709 return (zonecfg_setent(handle));
4710 }
4711
4712 int
4713 zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
4714 {
4715 xmlNodePtr cur;
4716 int err;
4717
4718 if (handle == NULL)
4719 return (Z_INVAL);
4720
4721 if ((cur = handle->zone_dh_cur) == NULL)
4722 return (Z_NO_ENTRY);
4723
4724 for (; cur != NULL; cur = cur->next)
4725 if (!xmlStrcmp(cur->name, DTD_ELEM_NET))
4726 break;
4727 if (cur == NULL) {
4728 handle->zone_dh_cur = handle->zone_dh_top;
4729 return (Z_NO_ENTRY);
4730 }
4731
4732 if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
4733 sizeof (tabptr->zone_nwif_address))) != Z_OK) {
4734 handle->zone_dh_cur = handle->zone_dh_top;
4735 return (err);
4736 }
4737
4738 if ((err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
4739 tabptr->zone_nwif_allowed_address,
4740 sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK) {
4741 handle->zone_dh_cur = handle->zone_dh_top;
4742 return (err);
4743 }
4744
4745 if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
4746 sizeof (tabptr->zone_nwif_physical))) != Z_OK) {
4747 handle->zone_dh_cur = handle->zone_dh_top;
4748 return (err);
4749 }
4750
4751 if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
4752 tabptr->zone_nwif_defrouter,
4753 sizeof (tabptr->zone_nwif_defrouter))) != Z_OK) {
4754 handle->zone_dh_cur = handle->zone_dh_top;
4755 return (err);
4756 }
4757
4758 handle->zone_dh_cur = cur->next;
4759 return (Z_OK);
4760 }
4761
4762 int
4763 zonecfg_endnwifent(zone_dochandle_t handle)
4764 {
4765 return (zonecfg_endent(handle));
4766 }
4767
4768 int
4769 zonecfg_setdevent(zone_dochandle_t handle)
4770 {
4771 return (zonecfg_setent(handle));
4772 }
4773
4774 int
4775 zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr)
4776 {
4777 xmlNodePtr cur;
4778 int err;
4779
4780 if (handle == NULL)
4781 return (Z_INVAL);
4782
4783 if ((cur = handle->zone_dh_cur) == NULL)
4784 return (Z_NO_ENTRY);
4785
4786 for (; cur != NULL; cur = cur->next)
4787 if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
4788 break;
4789 if (cur == NULL) {
4790 handle->zone_dh_cur = handle->zone_dh_top;
4791 return (Z_NO_ENTRY);
4792 }
4793
4794 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
4795 sizeof (tabptr->zone_dev_match))) != Z_OK) {
4796 handle->zone_dh_cur = handle->zone_dh_top;
4797 return (err);
4798 }
4799
4800 handle->zone_dh_cur = cur->next;
4801 return (Z_OK);
4802 }
4803
4804 int
4805 zonecfg_enddevent(zone_dochandle_t handle)
4806 {
4807 return (zonecfg_endent(handle));
4808 }
4809
4810 int
4811 zonecfg_setrctlent(zone_dochandle_t handle)
4812 {
4813 return (zonecfg_setent(handle));
4814 }
4815
4816 int
4817 zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr)
4818 {
4819 xmlNodePtr cur, val;
5508 return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL);
5509
5510 return (Z_OK);
5511 }
5512
5513 if (strcmp(zone_name, "global") == 0)
5514 return (zonecfg_default_brand(brandname, rp_sz));
5515
5516 if ((handle = zonecfg_init_handle()) == NULL)
5517 return (Z_NOMEM);
5518
5519 err = zonecfg_get_handle((char *)zone_name, handle);
5520 if (err == Z_OK)
5521 err = zonecfg_get_brand(handle, brandname, rp_sz);
5522
5523 zonecfg_fini_handle(handle);
5524 return (err);
5525 }
5526
5527 /*
5528 * Return the appropriate root for the active /dev.
5529 * For normal zone, the path is $ZONEPATH/root;
5530 * for scratch zone, the dev path is $ZONEPATH/lu.
5531 */
5532 int
5533 zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz)
5534 {
5535 int err;
5536 char *suffix;
5537 zone_state_t state;
5538
5539 /* This function makes sense for non-global zones only. */
5540 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
5541 return (Z_BOGUS_ZONE_NAME);
5542 if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK)
5543 return (err);
5544
5545 if (zone_get_state(zone_name, &state) == Z_OK &&
5546 state == ZONE_STATE_MOUNTED)
5547 suffix = "/lu";
6822 }
6823
6824 return (res);
6825 }
6826
6827 int
6828 zonecfg_getpsetent(zone_dochandle_t handle, struct zone_psettab *tabptr)
6829 {
6830 int err;
6831
6832 if ((err = zonecfg_setent(handle)) != Z_OK)
6833 return (err);
6834
6835 err = zonecfg_lookup_pset(handle, tabptr);
6836
6837 (void) zonecfg_endent(handle);
6838
6839 return (err);
6840 }
6841
6842 static int
6843 add_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6844 {
6845 xmlNodePtr newnode, cur = handle->zone_dh_cur;
6846 int err;
6847
6848 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_MCAP, NULL);
6849 if ((err = newprop(newnode, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap))
6850 != Z_OK)
6851 return (err);
6852
6853 return (Z_OK);
6854 }
6855
6856 int
6857 zonecfg_delete_mcap(zone_dochandle_t handle)
6858 {
6859 int err;
6860 xmlNodePtr cur = handle->zone_dh_cur;
6861
6862 if ((err = operation_prep(handle)) != Z_OK)
6863 return (err);
6864
6865 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6866 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
6867 continue;
6868
6869 xmlUnlinkNode(cur);
6870 xmlFreeNode(cur);
6871 return (Z_OK);
6872 }
6873 return (Z_NO_RESOURCE_ID);
6874 }
6875
6876 int
6877 zonecfg_modify_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6878 {
6879 int err;
6880
6881 if (tabptr == NULL)
6882 return (Z_INVAL);
6883
6884 err = zonecfg_delete_mcap(handle);
6885 /* it is ok if there is no mcap entry */
6886 if (err != Z_OK && err != Z_NO_RESOURCE_ID)
6887 return (err);
6888
6889 if ((err = add_mcap(handle, tabptr)) != Z_OK)
6890 return (err);
6891
6892 return (Z_OK);
6893 }
6894
6895 int
6896 zonecfg_lookup_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6897 {
6898 xmlNodePtr cur;
6899 int err;
6900
6901 if (tabptr == NULL)
6902 return (Z_INVAL);
6903
6904 if ((err = operation_prep(handle)) != Z_OK)
6905 return (err);
6906
6907 cur = handle->zone_dh_cur;
6908 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
6909 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
6910 continue;
6911 if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP,
6912 tabptr->zone_physmem_cap,
6913 sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
6914 handle->zone_dh_cur = handle->zone_dh_top;
6915 return (err);
6916 }
6917
6918 return (Z_OK);
6919 }
6920
6921 return (Z_NO_ENTRY);
6922 }
6923
6924 static int
6925 getmcapent_core(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6926 {
6927 xmlNodePtr cur;
6928 int err;
6929
6930 if (handle == NULL)
6931 return (Z_INVAL);
6932
6933 if ((cur = handle->zone_dh_cur) == NULL)
6934 return (Z_NO_ENTRY);
6935
6936 for (; cur != NULL; cur = cur->next)
6937 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) == 0)
6938 break;
6939 if (cur == NULL) {
6940 handle->zone_dh_cur = handle->zone_dh_top;
6941 return (Z_NO_ENTRY);
6942 }
6943
6944 if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap,
6945 sizeof (tabptr->zone_physmem_cap))) != Z_OK) {
6946 handle->zone_dh_cur = handle->zone_dh_top;
6947 return (err);
6948 }
6949
6950 handle->zone_dh_cur = cur->next;
6951 return (Z_OK);
6952 }
6953
6954 int
6955 zonecfg_getmcapent(zone_dochandle_t handle, struct zone_mcaptab *tabptr)
6956 {
6957 int err;
6958
6959 if ((err = zonecfg_setent(handle)) != Z_OK)
6960 return (err);
6961
6962 err = getmcapent_core(handle, tabptr);
6963
6964 (void) zonecfg_endent(handle);
6965
6966 return (err);
6967 }
6968
6969 /*
6970 * Get the full tree of pkg metadata in a set of nested AVL trees.
6971 * pkgs_avl is an AVL tree of pkgs.
6972 *
6973 * The zone xml data contains DTD_ELEM_PACKAGE elements.
6974 */
6975 int
6976 zonecfg_getpkgdata(zone_dochandle_t handle, uu_avl_pool_t *pkg_pool,
6977 uu_avl_t *pkgs_avl)
6978 {
6979 xmlNodePtr cur;
6980 int res;
6981 zone_pkg_entry_t *pkg;
6982 char name[MAXNAMELEN];
6983 char version[ZONE_PKG_VERSMAX];
6984
6985 if (handle == NULL)
6986 return (Z_INVAL);
6987
6988 if ((res = zonecfg_setent(handle)) != Z_OK)
7614 struct stat config_st, ua_st;
7615 char config_file[MAXPATHLEN];
7616 boolean_t changed = B_FALSE;
7617 int err;
7618
7619 if ((uaf = fopen(USERATTR_FILENAME, "r")) == NULL) {
7620 zerror(zonename, gettext("could not open file %s: %s"),
7621 USERATTR_FILENAME, strerror(errno));
7622 if (errno == EACCES)
7623 return (Z_ACCES);
7624 if (errno == ENOENT)
7625 return (Z_NO_ZONE);
7626 return (Z_MISC_FS);
7627 }
7628 if ((err = fstat(fileno(uaf), &ua_st)) != 0) {
7629 zerror(zonename, gettext("could not stat file %s: %s"),
7630 USERATTR_FILENAME, strerror(errno));
7631 (void) fclose(uaf);
7632 return (Z_MISC_FS);
7633 }
7634 if (!config_file_path(zonename, config_file)) {
7635 (void) fclose(uaf);
7636 return (Z_MISC_FS);
7637 }
7638
7639 if ((err = stat(config_file, &config_st)) != 0) {
7640 zerror(zonename, gettext("could not stat file %s: %s"),
7641 config_file, strerror(errno));
7642 (void) fclose(uaf);
7643 return (Z_MISC_FS);
7644 }
7645 if (config_st.st_mtime >= ua_st.st_mtime) {
7646 (void) fclose(uaf);
7647 return (Z_NO_ENTRY);
7648 }
7649 if ((err = zonecfg_delete_admins(handle, zonename)) == Z_OK) {
7650 changed = B_TRUE;
7651 } else if (err != Z_NO_ENTRY) {
7652 (void) fclose(uaf);
7653 return (err);
7654 }
|
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2014 Gary Mills
24 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
25 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
26 * Copyright 2015 Joyent Inc.
27 */
28
29 #include <libsysevent.h>
30 #include <pthread.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <fnmatch.h>
34 #include <strings.h>
35 #include <unistd.h>
36 #include <assert.h>
37 #include <libgen.h>
38 #include <libintl.h>
39 #include <alloca.h>
40 #include <ctype.h>
41 #include <sys/acl.h>
42 #include <sys/stat.h>
43 #include <sys/brand.h>
44 #include <sys/mntio.h>
45 #include <sys/mnttab.h>
46 #include <sys/nvpair.h>
47 #include <sys/types.h>
48 #include <sys/sockio.h>
49 #include <sys/systeminfo.h>
50 #include <ftw.h>
51 #include <pool.h>
52 #include <libscf.h>
53 #include <libproc.h>
54 #include <sys/priocntl.h>
55 #include <libuutil.h>
56 #include <wait.h>
57 #include <bsm/adt.h>
58 #include <auth_attr.h>
59 #include <auth_list.h>
60 #include <secdb.h>
61 #include <user_attr.h>
62 #include <prof_attr.h>
63 #include <sys/debug.h>
64 #include <os_dtd.h>
65
66 #include <arpa/inet.h>
67 #include <netdb.h>
68
69 #include <libxml/xmlmemory.h>
70 #include <libxml/parser.h>
71
72 #include <libdevinfo.h>
73 #include <uuid/uuid.h>
74 #include <dirent.h>
75 #include <libbrand.h>
76
77 #include <libzonecfg.h>
78 #include "zonecfg_impl.h"
79
80 #define _PATH_TMPFILE "/zonecfg.XXXXXX"
81 #define ZONE_CB_RETRY_COUNT 10
82 #define ZONE_EVENT_PING_SUBCLASS "ping"
83 #define ZONE_EVENT_PING_PUBLISHER "solaris"
84
85 #define DEBUGID_FILE "/etc/zones/did.txt"
86
87 /* Hard-code the DTD element/attribute/entity names just once, here. */
88 #define DTD_ELEM_ATTR (const xmlChar *) "attr"
89 #define DTD_ELEM_COMMENT (const xmlChar *) "comment"
90 #define DTD_ELEM_DEVICE (const xmlChar *) "device"
91 #define DTD_ELEM_FS (const xmlChar *) "filesystem"
92 #define DTD_ELEM_FSOPTION (const xmlChar *) "fsoption"
93 #define DTD_ELEM_NET (const xmlChar *) "network"
94 #define DTD_ELEM_NETATTR (const xmlChar *) "net-attr"
95 #define DTD_ELEM_RCTL (const xmlChar *) "rctl"
96 #define DTD_ELEM_RCTLVALUE (const xmlChar *) "rctl-value"
97 #define DTD_ELEM_ZONE (const xmlChar *) "zone"
98 #define DTD_ELEM_DATASET (const xmlChar *) "dataset"
99 #define DTD_ELEM_TMPPOOL (const xmlChar *) "tmp_pool"
100 #define DTD_ELEM_PSET (const xmlChar *) "pset"
101 #define DTD_ELEM_MCAP (const xmlChar *) "mcap"
102 #define DTD_ELEM_PACKAGE (const xmlChar *) "package"
103 #define DTD_ELEM_OBSOLETES (const xmlChar *) "obsoletes"
104 #define DTD_ELEM_DEV_PERM (const xmlChar *) "dev-perm"
105 #define DTD_ELEM_ADMIN (const xmlChar *) "admin"
106
107 #define DTD_ATTR_ACTION (const xmlChar *) "action"
108 #define DTD_ATTR_ADDRESS (const xmlChar *) "address"
109 #define DTD_ATTR_ALLOWED_ADDRESS (const xmlChar *) "allowed-address"
110 #define DTD_ATTR_AUTOBOOT (const xmlChar *) "autoboot"
111 #define DTD_ATTR_IPTYPE (const xmlChar *) "ip-type"
112 #define DTD_ATTR_DEFROUTER (const xmlChar *) "defrouter"
113 #define DTD_ATTR_DIR (const xmlChar *) "directory"
114 #define DTD_ATTR_GNIC (const xmlChar *) "global-nic"
115 #define DTD_ATTR_LIMIT (const xmlChar *) "limit"
116 #define DTD_ATTR_LIMITPRIV (const xmlChar *) "limitpriv"
117 #define DTD_ATTR_BOOTARGS (const xmlChar *) "bootargs"
118 #define DTD_ATTR_SCHED (const xmlChar *) "scheduling-class"
119 #define DTD_ATTR_MAC (const xmlChar *) "mac-addr"
120 #define DTD_ATTR_MATCH (const xmlChar *) "match"
121 #define DTD_ATTR_NAME (const xmlChar *) "name"
122 #define DTD_ATTR_PHYSICAL (const xmlChar *) "physical"
123 #define DTD_ATTR_POOL (const xmlChar *) "pool"
124 #define DTD_ATTR_PRIV (const xmlChar *) "priv"
125 #define DTD_ATTR_RAW (const xmlChar *) "raw"
126 #define DTD_ATTR_SPECIAL (const xmlChar *) "special"
127 #define DTD_ATTR_TYPE (const xmlChar *) "type"
128 #define DTD_ATTR_VALUE (const xmlChar *) "value"
129 #define DTD_ATTR_VLANID (const xmlChar *) "vlan-id"
130 #define DTD_ATTR_ZONEPATH (const xmlChar *) "zonepath"
131 #define DTD_ATTR_NCPU_MIN (const xmlChar *) "ncpu_min"
132 #define DTD_ATTR_NCPU_MAX (const xmlChar *) "ncpu_max"
133 #define DTD_ATTR_IMPORTANCE (const xmlChar *) "importance"
134 #define DTD_ATTR_PHYSCAP (const xmlChar *) "physcap"
135 #define DTD_ATTR_VERSION (const xmlChar *) "version"
136 #define DTD_ATTR_ID (const xmlChar *) "id"
137 #define DTD_ATTR_UID (const xmlChar *) "uid"
138 #define DTD_ATTR_GID (const xmlChar *) "gid"
139 #define DTD_ATTR_MODE (const xmlChar *) "mode"
140 #define DTD_ATTR_ACL (const xmlChar *) "acl"
141 #define DTD_ATTR_BRAND (const xmlChar *) "brand"
142 #define DTD_ATTR_DID (const xmlChar *) "debugid"
143 #define DTD_ATTR_HOSTID (const xmlChar *) "hostid"
144 #define DTD_ATTR_USER (const xmlChar *) "user"
145 #define DTD_ATTR_AUTHS (const xmlChar *) "auths"
146 #define DTD_ATTR_FS_ALLOWED (const xmlChar *) "fs-allowed"
147
148 #define DTD_ENTITY_BOOLEAN "boolean"
149 #define DTD_ENTITY_DEVPATH "devpath"
150 #define DTD_ENTITY_DRIVER "driver"
151 #define DTD_ENTITY_DRVMIN "drv_min"
152 #define DTD_ENTITY_FALSE "false"
153 #define DTD_ENTITY_INT "int"
154 #define DTD_ENTITY_STRING "string"
155 #define DTD_ENTITY_TRUE "true"
156 #define DTD_ENTITY_UINT "uint"
157
158 #define DTD_ENTITY_BOOL_LEN 6 /* "false" */
159
160 #define ATTACH_FORCED "SUNWattached.xml"
161
162 #define TMP_POOL_NAME "SUNWtmp_%s"
169 *
170 * This holds the alias, the full rctl name, the default priv value, action
171 * and lower limit. The functions that handle rctl aliases step through
172 * this table, matching on the alias, and using the full values for setting
173 * the rctl entry as well the limit for validation.
174 */
175 static struct alias {
176 char *shortname;
177 char *realname;
178 char *priv;
179 char *action;
180 uint64_t low_limit;
181 } aliases[] = {
182 {ALIAS_MAXLWPS, "zone.max-lwps", "privileged", "deny", 100},
183 {ALIAS_MAXSHMMEM, "zone.max-shm-memory", "privileged", "deny", 0},
184 {ALIAS_MAXSHMIDS, "zone.max-shm-ids", "privileged", "deny", 0},
185 {ALIAS_MAXMSGIDS, "zone.max-msg-ids", "privileged", "deny", 0},
186 {ALIAS_MAXSEMIDS, "zone.max-sem-ids", "privileged", "deny", 0},
187 {ALIAS_MAXLOCKEDMEM, "zone.max-locked-memory", "privileged", "deny", 0},
188 {ALIAS_MAXSWAP, "zone.max-swap", "privileged", "deny", 0},
189 {ALIAS_MAXPHYSMEM, "zone.max-physical-memory", "privileged", "deny",
190 1048576},
191 {ALIAS_SHARES, "zone.cpu-shares", "privileged", "none", 0},
192 {ALIAS_CPUCAP, "zone.cpu-cap", "privileged", "deny", 0},
193 {ALIAS_MAXPROCS, "zone.max-processes", "privileged", "deny", 100},
194 {NULL, NULL, NULL, NULL, 0}
195 };
196
197 /*
198 * Structure for applying rctls to a running zone. It allows important
199 * process values to be passed together easily.
200 */
201 typedef struct pr_info_handle {
202 struct ps_prochandle *pr;
203 pid_t pid;
204 } pr_info_handle_t;
205
206 struct zone_dochandle {
207 char *zone_dh_rootdir;
208 xmlDocPtr zone_dh_doc;
209 xmlNodePtr zone_dh_cur;
210 xmlNodePtr zone_dh_top;
264 }
265
266 const char *
267 zonecfg_get_root(void)
268 {
269 return (zonecfg_root);
270 }
271
272 boolean_t
273 zonecfg_in_alt_root(void)
274 {
275 return (*zonecfg_root != '\0');
276 }
277
278 /*
279 * Callers of the _file_path() functions are expected to have the second
280 * parameter be a (char foo[MAXPATHLEN]).
281 */
282
283 static boolean_t
284 file_path_common(const char *zonename, const char *subdir, const char *stem,
285 char *answer, size_t answer_size)
286 {
287 const char *native_root = zone_get_nroot();
288
289 if (native_root == NULL || zonecfg_in_alt_root()) {
290 /*
291 * Do not prepend the native system root (e.g. "/native") if an
292 * alternative configuration root has been selected.
293 */
294 native_root = "";
295 }
296
297 return (snprintf(answer, answer_size, "%s%s%s/%s.%s", native_root,
298 zonecfg_root, subdir, zonename, stem) < answer_size);
299 }
300
301 static boolean_t
302 config_file_path(const char *zonename, char *answer, size_t answer_size)
303 {
304 return (file_path_common(zonename, ZONE_CONFIG_ROOT, "xml", answer,
305 answer_size));
306 }
307
308 static boolean_t
309 snap_file_path(const char *zonename, char *answer, size_t answer_size)
310 {
311 return (file_path_common(zonename, ZONE_SNAPSHOT_ROOT, "snapshot.xml",
312 answer, answer_size));
313 }
314
315 /*ARGSUSED*/
316 static void
317 zonecfg_error_func(void *ctx, const char *msg, ...)
318 {
319 /*
320 * This function does nothing by design. Its purpose is to prevent
321 * libxml from dumping unwanted messages to stdout/stderr.
322 */
323 }
324
325 zone_dochandle_t
326 zonecfg_init_handle(void)
327 {
328 zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle));
329 if (handle == NULL) {
330 errno = Z_NOMEM;
331 return (NULL);
332 }
333
334 /* generic libxml initialization */
363 zonecfg_destroy_impl(char *filename)
364 {
365 if (unlink(filename) == -1) {
366 if (errno == EACCES)
367 return (Z_ACCES);
368 if (errno == ENOENT)
369 return (Z_NO_ZONE);
370 return (Z_MISC_FS);
371 }
372 return (Z_OK);
373 }
374
375 int
376 zonecfg_destroy(const char *zonename, boolean_t force)
377 {
378 char path[MAXPATHLEN];
379 struct zoneent ze;
380 int err, state_err;
381 zone_state_t state;
382
383 if (!config_file_path(zonename, path, sizeof (path)))
384 return (Z_MISC_FS);
385
386 state_err = zone_get_state((char *)zonename, &state);
387 err = access(path, W_OK);
388
389 /*
390 * If there is no file, and no index entry, reliably indicate that no
391 * such zone exists.
392 */
393 if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT))
394 return (Z_NO_ZONE);
395
396 /*
397 * Handle any other filesystem related errors (except if the XML
398 * file is missing, which we treat silently), unless we're forcing,
399 * in which case we plow on.
400 */
401 if (err == -1 && errno != ENOENT) {
402 if (errno == EACCES)
403 return (Z_ACCES);
420 if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK)
421 if (!force)
422 return (err);
423
424 err = zonecfg_destroy_impl(path);
425
426 /*
427 * Treat failure to find the XML file silently, since, well, it's
428 * gone, and with the index file cleaned up, we're done.
429 */
430 if (err == Z_OK || err == Z_NO_ZONE)
431 return (Z_OK);
432 return (err);
433 }
434
435 int
436 zonecfg_destroy_snapshot(const char *zonename)
437 {
438 char path[MAXPATHLEN];
439
440 if (!snap_file_path(zonename, path, sizeof (path)))
441 return (Z_MISC_FS);
442 return (zonecfg_destroy_impl(path));
443 }
444
445 static int
446 getroot(zone_dochandle_t handle, xmlNodePtr *root)
447 {
448 if (zonecfg_check_handle(handle) == Z_BAD_HANDLE)
449 return (Z_BAD_HANDLE);
450
451 *root = xmlDocGetRootElement(handle->zone_dh_doc);
452
453 if (*root == NULL)
454 return (Z_EMPTY_DOCUMENT);
455
456 if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE))
457 return (Z_WRONG_DOC_TYPE);
458
459 return (Z_OK);
460 }
587 {
588 xmlNodePtr root, child, next;
589
590 root = xmlDocGetRootElement(handle->zone_dh_doc);
591 for (child = root->xmlChildrenNode; child != NULL; child = next) {
592 next = child->next;
593 if (child->name == NULL)
594 continue;
595 if (xmlStrcmp(child->name, DTD_ELEM_PACKAGE) == 0) {
596 next = child->next;
597 xmlUnlinkNode(child);
598 xmlFreeNode(child);
599 }
600 }
601 }
602
603 static int
604 zonecfg_get_handle_impl(const char *zonename, const char *filename,
605 zone_dochandle_t handle)
606 {
607 struct stat statbuf;
608 boolean_t valid;
609
610 if (zonename == NULL)
611 return (Z_NO_ZONE);
612
613 if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) {
614 /* distinguish file not found vs. found but not parsed */
615 if (stat(filename, &statbuf) == 0)
616 return (Z_INVALID_DOCUMENT);
617 return (Z_NO_ZONE);
618 }
619
620 if (os_dtd_validate(handle->zone_dh_doc, B_FALSE, &valid) != 0) {
621 return (Z_NOMEM);
622 }
623 if (!valid) {
624 return (Z_INVALID_DOCUMENT);
625 }
626
627 /* delete any comments such as inherited Sun copyright / ident str */
628 stripcomments(handle);
629 return (Z_OK);
630 }
631
632 int
633 zonecfg_get_handle(const char *zonename, zone_dochandle_t handle)
634 {
635 char path[MAXPATHLEN];
636
637 if (!config_file_path(zonename, path, sizeof (path)))
638 return (Z_MISC_FS);
639 handle->zone_dh_newzone = B_FALSE;
640
641 return (zonecfg_get_handle_impl(zonename, path, handle));
642 }
643
644 int
645 zonecfg_get_attach_handle(const char *path, const char *fname,
646 const char *zonename, boolean_t preserve_sw, zone_dochandle_t handle)
647 {
648 char migpath[MAXPATHLEN];
649 int err;
650 struct stat buf;
651
652 if (snprintf(migpath, sizeof (migpath), "%s/root", path) >=
653 sizeof (migpath))
654 return (Z_NOMEM);
655
656 if (stat(migpath, &buf) == -1 || !S_ISDIR(buf.st_mode))
657 return (Z_NO_ZONE);
661 return (Z_NOMEM);
662
663 if ((err = zonecfg_get_handle_impl(zonename, migpath, handle)) != Z_OK)
664 return (err);
665
666 if (!preserve_sw)
667 strip_sw_inv(handle);
668
669 handle->zone_dh_newzone = B_TRUE;
670 if ((err = setrootattr(handle, DTD_ATTR_ZONEPATH, path)) != Z_OK)
671 return (err);
672
673 return (setrootattr(handle, DTD_ATTR_NAME, zonename));
674 }
675
676 int
677 zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle)
678 {
679 char path[MAXPATHLEN];
680
681 if (!snap_file_path(zonename, path, sizeof (path)))
682 return (Z_MISC_FS);
683 handle->zone_dh_newzone = B_FALSE;
684 return (zonecfg_get_handle_impl(zonename, path, handle));
685 }
686
687 int
688 zonecfg_get_template_handle(const char *template, const char *zonename,
689 zone_dochandle_t handle)
690 {
691 char path[MAXPATHLEN];
692 int err;
693
694 if (!config_file_path(template, path, sizeof (path)))
695 return (Z_MISC_FS);
696
697 if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK)
698 return (err);
699 handle->zone_dh_newzone = B_TRUE;
700 return (setrootattr(handle, DTD_ATTR_NAME, zonename));
701 }
702
703 int
704 zonecfg_get_xml_handle(const char *path, zone_dochandle_t handle)
705 {
706 struct stat buf;
707 int err;
708
709 if (stat(path, &buf) == -1)
710 return (Z_MISC_FS);
711
712 if ((err = zonecfg_get_handle_impl("xml", path, handle)) != Z_OK)
713 return (err);
714 handle->zone_dh_newzone = B_TRUE;
715 return (Z_OK);
716 }
717
718 /*
719 * Initialize two handles from the manifest read on fd. The rem_handle
720 * is initialized from the input file, including the sw inventory. The
721 * local_handle is initialized with the same zone configuration but with
722 * no sw inventory.
723 */
724 int
725 zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle,
726 zone_dochandle_t rem_handle)
727 {
728 boolean_t valid;
729
730 /* load the manifest into the handle for the remote system */
731 if ((rem_handle->zone_dh_doc = xmlReadFd(fd, NULL, NULL, 0)) == NULL) {
732 return (Z_INVALID_DOCUMENT);
733 }
734
735 if (os_dtd_validate(rem_handle->zone_dh_doc, B_FALSE, &valid) != 0) {
736 return (Z_NOMEM);
737 }
738 if (!valid) {
739 return (Z_INVALID_DOCUMENT);
740 }
741
742 /* delete any comments such as inherited Sun copyright / ident str */
743 stripcomments(rem_handle);
744
745 rem_handle->zone_dh_newzone = B_TRUE;
746 rem_handle->zone_dh_sw_inv = B_TRUE;
747
748 /*
749 * Now use the remote system handle to generate a local system handle
750 * with an identical zones configuration but no sw inventory.
751 */
752 if ((local_handle->zone_dh_doc = xmlCopyDoc(rem_handle->zone_dh_doc,
753 1)) == NULL) {
754 return (Z_INVALID_DOCUMENT);
755 }
756
757 /*
758 * We need to re-run xmlValidateDocument on local_handle to properly
759 * update the in-core representation of the configuration.
760 */
761 if (os_dtd_validate(local_handle->zone_dh_doc, B_FALSE, &valid) != 0) {
762 return (Z_NOMEM);
763 }
764 if (!valid) {
765 return (Z_INVALID_DOCUMENT);
766 }
767
768 strip_sw_inv(local_handle);
769
770 local_handle->zone_dh_newzone = B_TRUE;
771 local_handle->zone_dh_sw_inv = B_FALSE;
772
773 return (Z_OK);
774 }
775
776 static boolean_t
777 is_renaming(zone_dochandle_t handle)
778 {
779 if (handle->zone_dh_newzone)
780 return (B_FALSE);
781 if (strlen(handle->zone_dh_delete_name) > 0)
782 return (B_TRUE);
783 return (B_FALSE);
784 }
785
786 static boolean_t
1200 * Save existing zone 'foo':
1201 * Make backup of foo.xml -> .backup
1202 * Create tmpfile (zonecfg.xxxxxx)
1203 * Write XML to tmpfile
1204 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
1205 * Modify index file as needed
1206 * If it fails, recover from .backup -> foo.xml
1207 *
1208 * Rename 'foo' to 'bar':
1209 * Create tmpfile (zonecfg.xxxxxx)
1210 * Write XML to tmpfile
1211 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml)
1212 * Add entry for 'bar' to index file, Remove entry for 'foo' (refresh)
1213 * If it fails, delete bar.xml; foo.xml is left behind.
1214 */
1215 static int
1216 zonecfg_save_impl(zone_dochandle_t handle, char *filename)
1217 {
1218 char tmpfile[MAXPATHLEN];
1219 char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN];
1220 int tmpfd, err;
1221 boolean_t backup;
1222 boolean_t valid;
1223
1224 (void) strlcpy(tmpfile, filename, sizeof (tmpfile));
1225 (void) dirname(tmpfile);
1226 (void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile));
1227
1228 tmpfd = mkstemp(tmpfile);
1229 if (tmpfd == -1) {
1230 (void) unlink(tmpfile);
1231 return (Z_TEMP_FILE);
1232 }
1233 (void) close(tmpfd);
1234
1235 /*
1236 * We do a final validation of the document. Since the library has
1237 * malfunctioned if it fails to validate, we follow-up with an
1238 * assert() that the doc is valid.
1239 */
1240 VERIFY0(os_dtd_validate(handle->zone_dh_doc, B_FALSE, &valid));
1241 VERIFY(valid == B_TRUE);
1242
1243 if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0)
1244 goto err;
1245
1246 (void) chmod(tmpfile, 0644);
1247
1248 /*
1249 * In the event we are doing a standard save, hard link a copy of the
1250 * original file in .backup.<pid>.filename so we can restore it if
1251 * something goes wrong.
1252 */
1253 if (!is_new(handle) && !is_renaming(handle)) {
1254 backup = B_TRUE;
1255
1256 (void) strlcpy(bakdir, filename, sizeof (bakdir));
1257 (void) strlcpy(bakbase, filename, sizeof (bakbase));
1258 (void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s",
1259 dirname(bakdir), getpid(), basename(bakbase));
1260
1261 if (link(filename, bakfile) == -1) {
1276 (void) unlink(tmpfile);
1277 if (backup)
1278 (void) unlink(bakfile);
1279 if (err == EACCES)
1280 return (Z_ACCES);
1281 return (Z_MISC_FS);
1282 }
1283
1284 /*
1285 * If this is a snapshot, we're done-- don't add an index entry.
1286 */
1287 if (is_snapshot(handle))
1288 return (Z_OK);
1289
1290 /* now update the index file to reflect whatever we just did */
1291 if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) {
1292 if (backup) {
1293 /*
1294 * Try to restore from our backup.
1295 */
1296 (void) rename(bakfile, filename);
1297 } else {
1298 /*
1299 * Either the zone is new, in which case we can delete
1300 * new.xml, or we're doing a rename, so ditto.
1301 */
1302 assert(is_new(handle) || is_renaming(handle));
1303 (void) unlink(filename);
1304 }
1305 return (Z_UPDATING_INDEX);
1306 }
1307
1308 if (backup)
1309 (void) unlink(bakfile);
1310
1311 return (Z_OK);
1312
1313 err:
1314 (void) unlink(tmpfile);
1315 return (Z_SAVING_FILE);
1318 int
1319 zonecfg_save(zone_dochandle_t handle)
1320 {
1321 char zname[ZONENAME_MAX], path[MAXPATHLEN];
1322 char delpath[MAXPATHLEN];
1323 int err = Z_SAVING_FILE;
1324
1325 if (zonecfg_check_handle(handle) != Z_OK)
1326 return (Z_BAD_HANDLE);
1327
1328 /*
1329 * We don't support saving snapshots or a tree containing a sw
1330 * inventory at this time.
1331 */
1332 if (handle->zone_dh_snapshot || handle->zone_dh_sw_inv)
1333 return (Z_INVAL);
1334
1335 if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK)
1336 return (err);
1337
1338 if (!config_file_path(zname, path, sizeof (path)))
1339 return (Z_MISC_FS);
1340
1341 addcomment(handle, "\n DO NOT EDIT THIS "
1342 "FILE. Use zonecfg(1M) instead.\n");
1343
1344 /*
1345 * Update user_attr first so that it will be older
1346 * than the config file.
1347 */
1348 (void) zonecfg_authorize_users(handle, zname);
1349 err = zonecfg_save_impl(handle, path);
1350
1351 stripcomments(handle);
1352
1353 if (err != Z_OK)
1354 return (err);
1355
1356 handle->zone_dh_newzone = B_FALSE;
1357
1358 if (is_renaming(handle)) {
1359 if (config_file_path(handle->zone_dh_delete_name, delpath,
1360 sizeof (delpath))) {
1361 (void) unlink(delpath);
1362 }
1363 handle->zone_dh_delete_name[0] = '\0';
1364 }
1365
1366 return (Z_OK);
1367 }
1368
1369 int
1370 zonecfg_verify_save(zone_dochandle_t handle, char *filename)
1371 {
1372 boolean_t valid;
1373
1374 if (zonecfg_check_handle(handle) != Z_OK)
1375 return (Z_BAD_HANDLE);
1376
1377 /*
1378 * We do a final validation of the document. Since the library has
1379 * malfunctioned if it fails to validate, we follow-up with an
1380 * assert() that the doc is valid.
1381 */
1382 VERIFY0(os_dtd_validate(handle->zone_dh_doc, B_FALSE, &valid));
1383 VERIFY(valid == B_TRUE);
1384
1385 if (xmlSaveFormatFile(filename, handle->zone_dh_doc, 1) <= 0)
1386 return (Z_SAVING_FILE);
1387
1388 return (Z_OK);
1389 }
1390
1391 int
1392 zonecfg_detach_save(zone_dochandle_t handle, uint_t flags)
1393 {
1394 char zname[ZONENAME_MAX];
1395 char path[MAXPATHLEN];
1396 char migpath[MAXPATHLEN];
1397 int err = Z_SAVING_FILE;
1398 boolean_t valid;
1399
1400 if (zonecfg_check_handle(handle) != Z_OK)
1401 return (Z_BAD_HANDLE);
1402
1403 if (flags & ZONE_DRY_RUN) {
1404 (void) strlcpy(migpath, "-", sizeof (migpath));
1405 } else {
1406 if ((err = zonecfg_get_name(handle, zname, sizeof (zname)))
1407 != Z_OK)
1408 return (err);
1409
1410 if ((err = zone_get_zonepath(zname, path, sizeof (path)))
1411 != Z_OK)
1412 return (err);
1413
1414 if (snprintf(migpath, sizeof (migpath), "%s/%s", path,
1415 ZONE_DETACHED) >= sizeof (migpath))
1416 return (Z_NOMEM);
1417 }
1418
1419 if ((err = operation_prep(handle)) != Z_OK)
1420 return (err);
1421
1422 addcomment(handle, "\n DO NOT EDIT THIS FILE. "
1423 "Use zonecfg(1M) and zoneadm(1M) attach.\n");
1424
1425 /*
1426 * We do a final validation of the document. Since the library has
1427 * malfunctioned if it fails to validate, we follow-up with an
1428 * assert() that the doc is valid.
1429 */
1430 VERIFY0(os_dtd_validate(handle->zone_dh_doc, B_FALSE, &valid));
1431 VERIFY(valid == B_TRUE);
1432
1433 if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0)
1434 return (Z_SAVING_FILE);
1435
1436 if (!(flags & ZONE_DRY_RUN))
1437 (void) chmod(migpath, 0644);
1438
1439 stripcomments(handle);
1440
1441 handle->zone_dh_newzone = B_FALSE;
1442
1443 return (Z_OK);
1444 }
1445
1446 boolean_t
1447 zonecfg_detached(const char *path)
1448 {
1449 char migpath[MAXPATHLEN];
1450 struct stat buf;
1451
1484 if (forced) {
1485 (void) rename(detached, attached);
1486 } else {
1487 (void) unlink(attached);
1488 (void) unlink(detached);
1489 }
1490 }
1491
1492 /*
1493 * Special case: if access(2) fails with ENOENT, then try again using
1494 * ZONE_CONFIG_ROOT instead of config_file_path(zonename). This is how we
1495 * work around the case of a config file which has not been created yet:
1496 * the user will need access to the directory so use that as a heuristic.
1497 */
1498
1499 int
1500 zonecfg_access(const char *zonename, int amode)
1501 {
1502 char path[MAXPATHLEN];
1503
1504 if (!config_file_path(zonename, path, sizeof (path)))
1505 return (Z_INVAL);
1506 if (access(path, amode) == 0)
1507 return (Z_OK);
1508 if (errno == ENOENT) {
1509 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1510 ZONE_CONFIG_ROOT) >= sizeof (path))
1511 return (Z_INVAL);
1512 if (access(path, amode) == 0)
1513 return (Z_OK);
1514 }
1515 if (errno == EACCES)
1516 return (Z_ACCES);
1517 if (errno == EINVAL)
1518 return (Z_INVAL);
1519 return (Z_MISC_FS);
1520 }
1521
1522 int
1523 zonecfg_create_snapshot(const char *zonename)
1524 {
1549 * save the resolved path in the snapshot, thus preventing any
1550 * potential problems down the line when zoneadmd goes to unmount
1551 * file systems and depends on initial string matches with resolved
1552 * paths.
1553 */
1554 rpath[res] = '\0';
1555 if (strcmp(zonepath, rpath) != 0) {
1556 if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK)
1557 goto out;
1558 }
1559 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1560 ZONE_SNAPSHOT_ROOT) >= sizeof (path)) {
1561 error = Z_MISC_FS;
1562 goto out;
1563 }
1564 if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) {
1565 error = Z_MISC_FS;
1566 goto out;
1567 }
1568
1569 if (!snap_file_path(zonename, path, sizeof (path))) {
1570 error = Z_MISC_FS;
1571 goto out;
1572 }
1573
1574 addcomment(handle, "\n DO NOT EDIT THIS FILE. "
1575 "It is a snapshot of running zone state.\n");
1576
1577 error = zonecfg_save_impl(handle, path);
1578
1579 stripcomments(handle);
1580
1581 out:
1582 zonecfg_fini_handle(handle);
1583 return (error);
1584 }
1585
1586 int
1587 zonecfg_get_iptype(zone_dochandle_t handle, zone_iptype_t *iptypep)
1588 {
1589 char property[10]; /* 10 is big enough for "shared"/"exclusive" */
2080
2081 /*
2082 * Determines whether there is a net resource with the physical interface, IP
2083 * address, and default router specified by 'tabptr' in the zone configuration
2084 * to which 'handle' refers. 'tabptr' must have an interface, an address, a
2085 * default router, or a combination of the three. This function returns Z_OK
2086 * iff there is exactly one net resource matching the query specified by
2087 * 'tabptr'. The function returns Z_INSUFFICIENT_SPEC if there are multiple
2088 * matches or 'tabptr' does not specify a physical interface, address, or
2089 * default router. The function returns Z_NO_RESOURCE_ID if are no matches.
2090 *
2091 * Errors might also be returned if the entry that exactly matches the
2092 * query lacks critical network resource information.
2093 *
2094 * If there is a single match, then the matching entry's physical interface, IP
2095 * address, and default router information are stored in 'tabptr'.
2096 */
2097 int
2098 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2099 {
2100 xmlNodePtr cur, val;
2101 xmlNodePtr firstmatch;
2102 int err;
2103 char address[INET6_ADDRSTRLEN];
2104 char physical[LIFNAMSIZ];
2105 char mac[MAXMACADDRLEN];
2106 char gnic[LIFNAMSIZ];
2107 size_t addrspec; /* nonzero if tabptr has IP addr */
2108 size_t physspec; /* nonzero if tabptr has interface */
2109 size_t macspec; /* nonzero if tabptr has mac addr */
2110 size_t gnicspec; /* nonzero if tabptr has gnic */
2111 size_t defrouterspec; /* nonzero if tabptr has def. router */
2112 size_t allowed_addrspec;
2113 zone_iptype_t iptype;
2114
2115 if (tabptr == NULL)
2116 return (Z_INVAL);
2117
2118 /*
2119 * Determine the fields that will be searched. There must be at least
2120 * one.
2121 *
2122 * zone_nwif_address, zone_nwif_physical, zone_nwif_defrouter,
2123 * zone_nwif_mac, zone_nwif_vlan_id and zone_nwif_gnic are
2124 * arrays, so no NULL checks are necessary.
2125 */
2126 addrspec = strlen(tabptr->zone_nwif_address);
2127 physspec = strlen(tabptr->zone_nwif_physical);
2128 macspec = strlen(tabptr->zone_nwif_mac);
2129 gnicspec = strlen(tabptr->zone_nwif_gnic);
2130 defrouterspec = strlen(tabptr->zone_nwif_defrouter);
2131 allowed_addrspec = strlen(tabptr->zone_nwif_allowed_address);
2132 if (addrspec != 0 && allowed_addrspec != 0)
2133 return (Z_INVAL); /* can't specify both */
2134 if (addrspec == 0 && physspec == 0 && defrouterspec == 0 &&
2135 allowed_addrspec == 0 && macspec == 0 && gnicspec == 0)
2136 return (Z_INSUFFICIENT_SPEC);
2137
2138 if ((err = operation_prep(handle)) != Z_OK)
2139 return (err);
2140
2141 if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK)
2142 return (err);
2143 /*
2144 * Iterate over the configuration's elements and look for net elements
2145 * that match the query.
2146 */
2147 firstmatch = NULL;
2148 cur = handle->zone_dh_cur;
2149 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2150 /* Skip non-net elements */
2151 if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2152 continue;
2153
2154 /*
2155 * If any relevant fields don't match the query, then skip
2156 * the current net element.
2157 */
2158 if (physspec != 0 && (fetchprop(cur, DTD_ATTR_PHYSICAL,
2159 physical, sizeof (physical)) != Z_OK ||
2160 strcmp(tabptr->zone_nwif_physical, physical) != 0))
2161 continue;
2162 if (iptype == ZS_EXCLUSIVE && macspec != 0 &&
2163 (fetchprop(cur, DTD_ATTR_MAC, mac, sizeof (mac)) != Z_OK ||
2164 strcmp(tabptr->zone_nwif_mac, mac) != 0))
2165 continue;
2166 if (iptype == ZS_EXCLUSIVE && gnicspec != 0 &&
2167 (fetchprop(cur, DTD_ATTR_GNIC, gnic,
2168 sizeof (gnic)) != Z_OK ||
2169 strcmp(tabptr->zone_nwif_gnic, gnic) != 0))
2170 continue;
2171 if (iptype == ZS_SHARED && addrspec != 0 &&
2172 (fetchprop(cur, DTD_ATTR_ADDRESS, address,
2173 sizeof (address)) != Z_OK ||
2174 !zonecfg_same_net_address(tabptr->zone_nwif_address,
2175 address)))
2176 continue;
2177 if (iptype == ZS_EXCLUSIVE && allowed_addrspec != 0 &&
2178 (fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS, address,
2179 sizeof (address)) != Z_OK ||
2180 !zonecfg_same_net_address(tabptr->zone_nwif_allowed_address,
2181 address)))
2182 continue;
2183 if (defrouterspec != 0 && (fetchprop(cur, DTD_ATTR_DEFROUTER,
2184 address, sizeof (address)) != Z_OK ||
2185 !zonecfg_same_net_address(tabptr->zone_nwif_defrouter,
2186 address)))
2187 continue;
2188
2189 /*
2190 * The current net element matches the query. Select it if
2193 if (firstmatch == NULL)
2194 firstmatch = cur;
2195 else
2196 return (Z_INSUFFICIENT_SPEC);
2197 }
2198 if (firstmatch == NULL)
2199 return (Z_NO_RESOURCE_ID);
2200
2201 cur = firstmatch;
2202
2203 if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
2204 sizeof (tabptr->zone_nwif_physical))) != Z_OK)
2205 return (err);
2206
2207 if (iptype == ZS_SHARED &&
2208 (err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
2209 sizeof (tabptr->zone_nwif_address))) != Z_OK)
2210 return (err);
2211
2212 if (iptype == ZS_EXCLUSIVE &&
2213 (err = fetchprop(cur, DTD_ATTR_MAC, tabptr->zone_nwif_mac,
2214 sizeof (tabptr->zone_nwif_mac))) != Z_OK)
2215 return (err);
2216
2217 if (iptype == ZS_EXCLUSIVE &&
2218 (err = fetchprop(cur, DTD_ATTR_VLANID, tabptr->zone_nwif_vlan_id,
2219 sizeof (tabptr->zone_nwif_vlan_id))) != Z_OK)
2220 return (err);
2221
2222 if (iptype == ZS_EXCLUSIVE &&
2223 (err = fetchprop(cur, DTD_ATTR_GNIC, tabptr->zone_nwif_gnic,
2224 sizeof (tabptr->zone_nwif_gnic))) != Z_OK)
2225 return (err);
2226
2227 if (iptype == ZS_EXCLUSIVE &&
2228 (err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
2229 tabptr->zone_nwif_allowed_address,
2230 sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK)
2231 return (err);
2232
2233 if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
2234 tabptr->zone_nwif_defrouter,
2235 sizeof (tabptr->zone_nwif_defrouter))) != Z_OK)
2236 return (err);
2237
2238 tabptr->zone_nwif_attrp = NULL;
2239 for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
2240 struct zone_res_attrtab *valptr;
2241
2242 valptr = (struct zone_res_attrtab *)malloc(
2243 sizeof (struct zone_res_attrtab));
2244 if (valptr == NULL)
2245 return (Z_NOMEM);
2246
2247 valptr->zone_res_attr_name[0] =
2248 valptr->zone_res_attr_value[0] = '\0';
2249 if (zonecfg_add_res_attr(&(tabptr->zone_nwif_attrp), valptr)
2250 != Z_OK) {
2251 free(valptr);
2252 break;
2253 }
2254
2255 if ((fetchprop(val, DTD_ATTR_NAME, valptr->zone_res_attr_name,
2256 sizeof (valptr->zone_res_attr_name)) != Z_OK))
2257 break;
2258 if ((fetchprop(val, DTD_ATTR_VALUE,
2259 valptr->zone_res_attr_value,
2260 sizeof (valptr->zone_res_attr_value)) != Z_OK))
2261 break;
2262 }
2263
2264 return (Z_OK);
2265 }
2266
2267 static int
2268 zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2269 {
2270 xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode;
2271 struct zone_res_attrtab *valptr;
2272 int err;
2273
2274 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL);
2275 if (strlen(tabptr->zone_nwif_address) > 0 &&
2276 (err = newprop(newnode, DTD_ATTR_ADDRESS,
2277 tabptr->zone_nwif_address)) != Z_OK)
2278 return (err);
2279 if (strlen(tabptr->zone_nwif_allowed_address) > 0 &&
2280 (err = newprop(newnode, DTD_ATTR_ALLOWED_ADDRESS,
2281 tabptr->zone_nwif_allowed_address)) != Z_OK)
2282 return (err);
2283 if ((err = newprop(newnode, DTD_ATTR_PHYSICAL,
2284 tabptr->zone_nwif_physical)) != Z_OK)
2285 return (err);
2286 /*
2287 * Do not add these properties when they are not set, for backwards
2288 * compatibility and because they are optional.
2289 */
2290 if ((strlen(tabptr->zone_nwif_defrouter) > 0) &&
2291 ((err = newprop(newnode, DTD_ATTR_DEFROUTER,
2292 tabptr->zone_nwif_defrouter)) != Z_OK))
2293 return (err);
2294 if (strlen(tabptr->zone_nwif_mac) > 0 &&
2295 (err = newprop(newnode, DTD_ATTR_MAC,
2296 tabptr->zone_nwif_mac)) != Z_OK)
2297 return (err);
2298 if (strlen(tabptr->zone_nwif_vlan_id) > 0 &&
2299 (err = newprop(newnode, DTD_ATTR_VLANID,
2300 tabptr->zone_nwif_vlan_id)) != Z_OK)
2301 return (err);
2302 if (strlen(tabptr->zone_nwif_gnic) > 0 &&
2303 (err = newprop(newnode, DTD_ATTR_GNIC,
2304 tabptr->zone_nwif_gnic)) != Z_OK)
2305 return (err);
2306
2307 for (valptr = tabptr->zone_nwif_attrp; valptr != NULL;
2308 valptr = valptr->zone_res_attr_next) {
2309 valnode = xmlNewTextChild(newnode, NULL, DTD_ELEM_NETATTR,
2310 NULL);
2311 err = newprop(valnode, DTD_ATTR_NAME,
2312 valptr->zone_res_attr_name);
2313 if (err != Z_OK)
2314 return (err);
2315 err = newprop(valnode, DTD_ATTR_VALUE,
2316 valptr->zone_res_attr_value);
2317 if (err != Z_OK)
2318 return (err);
2319 }
2320
2321 return (Z_OK);
2322 }
2323
2324 int
2325 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2326 {
2327 int err;
2328
2329 if (tabptr == NULL)
2330 return (Z_INVAL);
2331
2332 if ((err = operation_prep(handle)) != Z_OK)
2333 return (err);
2334
2335 if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK)
2336 return (err);
2337
2338 return (Z_OK);
2339 }
2340
2341 static int
2342 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2343 {
2344 xmlNodePtr cur = handle->zone_dh_cur;
2345 boolean_t addr_match, phys_match, allowed_addr_match, mac_match,
2346 gnic_match;
2347
2348 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2349 if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2350 continue;
2351
2352 addr_match = match_prop(cur, DTD_ATTR_ADDRESS,
2353 tabptr->zone_nwif_address);
2354 allowed_addr_match = match_prop(cur, DTD_ATTR_ALLOWED_ADDRESS,
2355 tabptr->zone_nwif_allowed_address);
2356 phys_match = match_prop(cur, DTD_ATTR_PHYSICAL,
2357 tabptr->zone_nwif_physical);
2358 mac_match = match_prop(cur, DTD_ATTR_MAC,
2359 tabptr->zone_nwif_mac);
2360 gnic_match = match_prop(cur, DTD_ATTR_GNIC,
2361 tabptr->zone_nwif_gnic);
2362
2363 if ((addr_match || allowed_addr_match || mac_match ||
2364 gnic_match) && phys_match) {
2365 xmlUnlinkNode(cur);
2366 xmlFreeNode(cur);
2367 return (Z_OK);
2368 }
2369 }
2370 return (Z_NO_RESOURCE_ID);
2371 }
2372
2373 int
2374 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2375 {
2376 int err;
2377
2378 if (tabptr == NULL)
2379 return (Z_INVAL);
2380
2381 if ((err = operation_prep(handle)) != Z_OK)
2382 return (err);
2383
2384 if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK)
2393 struct zone_nwiftab *oldtabptr,
2394 struct zone_nwiftab *newtabptr)
2395 {
2396 int err;
2397
2398 if (oldtabptr == NULL || newtabptr == NULL)
2399 return (Z_INVAL);
2400
2401 if ((err = operation_prep(handle)) != Z_OK)
2402 return (err);
2403
2404 if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK)
2405 return (err);
2406
2407 if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK)
2408 return (err);
2409
2410 return (Z_OK);
2411 }
2412
2413 void
2414 zonecfg_free_res_attr_list(struct zone_res_attrtab *valtab)
2415 {
2416 if (valtab == NULL)
2417 return;
2418 zonecfg_free_res_attr_list(valtab->zone_res_attr_next);
2419 free(valtab);
2420 }
2421
2422 int
2423 zonecfg_add_res_attr(struct zone_res_attrtab **headptr,
2424 struct zone_res_attrtab *valtabptr)
2425 {
2426 struct zone_res_attrtab *last, *old, *new;
2427
2428 last = *headptr;
2429 for (old = last; old != NULL; old = old->zone_res_attr_next)
2430 last = old; /* walk to the end of the list */
2431 new = valtabptr; /* alloc'd by caller */
2432 new->zone_res_attr_next = NULL;
2433 if (last == NULL)
2434 *headptr = new;
2435 else
2436 last->zone_res_attr_next = new;
2437 return (Z_OK);
2438 }
2439
2440 int
2441 zonecfg_remove_res_attr(struct zone_res_attrtab **headptr,
2442 struct zone_res_attrtab *valtabptr)
2443 {
2444 struct zone_res_attrtab *last, *this, *next;
2445
2446 last = *headptr;
2447 for (this = last; this != NULL; this = this->zone_res_attr_next) {
2448 if (strcmp(this->zone_res_attr_name,
2449 valtabptr->zone_res_attr_name) == 0 &&
2450 strcmp(this->zone_res_attr_value,
2451 valtabptr->zone_res_attr_value) == 0) {
2452 next = this->zone_res_attr_next;
2453 if (this == *headptr)
2454 *headptr = next;
2455 else
2456 last->zone_res_attr_next = next;
2457 free(this);
2458 return (Z_OK);
2459 } else
2460 last = this;
2461 }
2462 return (Z_NO_PROPERTY_ID);
2463 }
2464
2465 /*
2466 * Must be a comma-separated list of alpha-numeric file system names.
2467 */
2468 static int
2469 zonecfg_valid_fs_allowed(const char *fsallowedp)
2470 {
2471 char tmp[ZONE_FS_ALLOWED_MAX];
2472 char *cp = tmp;
2473 char *p;
2474
2475 if (strlen(fsallowedp) > ZONE_FS_ALLOWED_MAX)
2476 return (Z_TOO_BIG);
2477
2478 (void) strlcpy(tmp, fsallowedp, sizeof (tmp));
2479
2480 while (*cp != '\0') {
2481 p = cp;
2482 while (*p != '\0' && *p != ',') {
2483 if (!isalnum(*p) && *p != '-')
2484 return (Z_INVALID_PROPERTY);
2594 * attribute is cleared. Non-NULL hostids are validated. This function returns
2595 * Z_OK on success. Any other return value indicates failure.
2596 */
2597 int
2598 zonecfg_set_hostid(zone_dochandle_t handle, const char *hostidp)
2599 {
2600 int err;
2601
2602 /*
2603 * A NULL hostid string is interpreted as a request to clear the
2604 * hostid.
2605 */
2606 if (hostidp == NULL || (err = zonecfg_valid_hostid(hostidp)) == Z_OK)
2607 return (setrootattr(handle, DTD_ATTR_HOSTID, hostidp));
2608 return (err);
2609 }
2610
2611 int
2612 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2613 {
2614 xmlNodePtr cur, val, firstmatch;
2615 int err;
2616 char match[MAXPATHLEN];
2617
2618 if (tabptr == NULL)
2619 return (Z_INVAL);
2620
2621 if ((err = operation_prep(handle)) != Z_OK)
2622 return (err);
2623
2624 cur = handle->zone_dh_cur;
2625 firstmatch = NULL;
2626 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2627 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2628 continue;
2629 if (strlen(tabptr->zone_dev_match) == 0)
2630 continue;
2631
2632 if ((fetchprop(cur, DTD_ATTR_MATCH, match,
2633 sizeof (match)) == Z_OK)) {
2634 if (strcmp(tabptr->zone_dev_match,
2639 return (Z_INSUFFICIENT_SPEC);
2640 } else {
2641 /*
2642 * If another property matched but this
2643 * one doesn't then reset firstmatch.
2644 */
2645 if (firstmatch == cur)
2646 firstmatch = NULL;
2647 }
2648 }
2649 }
2650 if (firstmatch == NULL)
2651 return (Z_NO_RESOURCE_ID);
2652
2653 cur = firstmatch;
2654
2655 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
2656 sizeof (tabptr->zone_dev_match))) != Z_OK)
2657 return (err);
2658
2659 tabptr->zone_dev_attrp = NULL;
2660 for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
2661 struct zone_res_attrtab *valptr;
2662
2663 valptr = (struct zone_res_attrtab *)malloc(
2664 sizeof (struct zone_res_attrtab));
2665 if (valptr == NULL)
2666 return (Z_NOMEM);
2667
2668 valptr->zone_res_attr_name[0] =
2669 valptr->zone_res_attr_value[0] = '\0';
2670 if (zonecfg_add_res_attr(&(tabptr->zone_dev_attrp), valptr)
2671 != Z_OK) {
2672 free(valptr);
2673 break;
2674 }
2675
2676 if ((fetchprop(val, DTD_ATTR_NAME, valptr->zone_res_attr_name,
2677 sizeof (valptr->zone_res_attr_name)) != Z_OK))
2678 break;
2679 if ((fetchprop(val, DTD_ATTR_VALUE,
2680 valptr->zone_res_attr_value,
2681 sizeof (valptr->zone_res_attr_value)) != Z_OK))
2682 break;
2683 }
2684
2685 return (Z_OK);
2686 }
2687
2688 static int
2689 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
2690 {
2691 xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode;
2692 struct zone_res_attrtab *valptr;
2693 int err;
2694
2695 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL);
2696
2697 if ((err = newprop(newnode, DTD_ATTR_MATCH,
2698 tabptr->zone_dev_match)) != Z_OK)
2699 return (err);
2700
2701 for (valptr = tabptr->zone_dev_attrp; valptr != NULL;
2702 valptr = valptr->zone_res_attr_next) {
2703 valnode = xmlNewTextChild(newnode, NULL, DTD_ELEM_NETATTR,
2704 NULL);
2705 err = newprop(valnode, DTD_ATTR_NAME,
2706 valptr->zone_res_attr_name);
2707 if (err != Z_OK)
2708 return (err);
2709 err = newprop(valnode, DTD_ATTR_VALUE,
2710 valptr->zone_res_attr_value);
2711 if (err != Z_OK)
2712 return (err);
2713 }
2714
2715
2716 return (Z_OK);
2717 }
2718
2719 int
2720 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2721 {
2722 int err;
2723
2724 if (tabptr == NULL)
2725 return (Z_INVAL);
2726
2727 if ((err = operation_prep(handle)) != Z_OK)
2728 return (err);
2729
2730 if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK)
2731 return (err);
2732
2733 return (Z_OK);
2734 }
2735
4893
4894 handle->zone_dh_cur = cur->next;
4895 return (Z_OK);
4896 }
4897
4898 int
4899 zonecfg_endfsent(zone_dochandle_t handle)
4900 {
4901 return (zonecfg_endent(handle));
4902 }
4903
4904 int
4905 zonecfg_setnwifent(zone_dochandle_t handle)
4906 {
4907 return (zonecfg_setent(handle));
4908 }
4909
4910 int
4911 zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
4912 {
4913 xmlNodePtr cur, val;
4914 struct zone_res_attrtab *valptr;
4915 int err;
4916
4917 if (handle == NULL)
4918 return (Z_INVAL);
4919
4920 if ((cur = handle->zone_dh_cur) == NULL)
4921 return (Z_NO_ENTRY);
4922
4923 for (; cur != NULL; cur = cur->next)
4924 if (!xmlStrcmp(cur->name, DTD_ELEM_NET))
4925 break;
4926 if (cur == NULL) {
4927 handle->zone_dh_cur = handle->zone_dh_top;
4928 return (Z_NO_ENTRY);
4929 }
4930
4931 if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
4932 sizeof (tabptr->zone_nwif_address))) != Z_OK) {
4933 handle->zone_dh_cur = handle->zone_dh_top;
4934 return (err);
4935 }
4936
4937 if ((err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
4938 tabptr->zone_nwif_allowed_address,
4939 sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK) {
4940 handle->zone_dh_cur = handle->zone_dh_top;
4941 return (err);
4942 }
4943
4944 if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
4945 sizeof (tabptr->zone_nwif_physical))) != Z_OK) {
4946 handle->zone_dh_cur = handle->zone_dh_top;
4947 return (err);
4948 }
4949
4950 if ((err = fetchprop(cur, DTD_ATTR_MAC, tabptr->zone_nwif_mac,
4951 sizeof (tabptr->zone_nwif_mac))) != Z_OK) {
4952 handle->zone_dh_cur = handle->zone_dh_top;
4953 return (err);
4954 }
4955
4956 if ((err = fetchprop(cur, DTD_ATTR_VLANID, tabptr->zone_nwif_vlan_id,
4957 sizeof (tabptr->zone_nwif_vlan_id))) != Z_OK) {
4958 handle->zone_dh_cur = handle->zone_dh_top;
4959 return (err);
4960 }
4961
4962 if ((err = fetchprop(cur, DTD_ATTR_GNIC, tabptr->zone_nwif_gnic,
4963 sizeof (tabptr->zone_nwif_gnic))) != Z_OK) {
4964 handle->zone_dh_cur = handle->zone_dh_top;
4965 return (err);
4966 }
4967
4968 if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
4969 tabptr->zone_nwif_defrouter,
4970 sizeof (tabptr->zone_nwif_defrouter))) != Z_OK) {
4971 handle->zone_dh_cur = handle->zone_dh_top;
4972 return (err);
4973 }
4974
4975 tabptr->zone_nwif_attrp = NULL;
4976 for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
4977 valptr = (struct zone_res_attrtab *)malloc(
4978 sizeof (struct zone_res_attrtab));
4979 if (valptr == NULL)
4980 return (Z_NOMEM);
4981
4982 valptr->zone_res_attr_name[0] =
4983 valptr->zone_res_attr_value[0] = '\0';
4984 if (zonecfg_add_res_attr(&(tabptr->zone_nwif_attrp), valptr)
4985 != Z_OK) {
4986 free(valptr);
4987 break;
4988 }
4989
4990 if (fetchprop(val, DTD_ATTR_NAME, valptr->zone_res_attr_name,
4991 sizeof (valptr->zone_res_attr_name)) != Z_OK)
4992 break;
4993 if (fetchprop(val, DTD_ATTR_VALUE, valptr->zone_res_attr_value,
4994 sizeof (valptr->zone_res_attr_value)) != Z_OK)
4995 break;
4996 }
4997
4998 handle->zone_dh_cur = cur->next;
4999 return (Z_OK);
5000 }
5001
5002 int
5003 zonecfg_endnwifent(zone_dochandle_t handle)
5004 {
5005 return (zonecfg_endent(handle));
5006 }
5007
5008 int
5009 zonecfg_setdevent(zone_dochandle_t handle)
5010 {
5011 return (zonecfg_setent(handle));
5012 }
5013
5014 int
5015 zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr)
5016 {
5017 xmlNodePtr cur, val;
5018 int err;
5019
5020 if (handle == NULL)
5021 return (Z_INVAL);
5022
5023 if ((cur = handle->zone_dh_cur) == NULL)
5024 return (Z_NO_ENTRY);
5025
5026 for (; cur != NULL; cur = cur->next)
5027 if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
5028 break;
5029 if (cur == NULL) {
5030 handle->zone_dh_cur = handle->zone_dh_top;
5031 return (Z_NO_ENTRY);
5032 }
5033
5034 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
5035 sizeof (tabptr->zone_dev_match))) != Z_OK) {
5036 handle->zone_dh_cur = handle->zone_dh_top;
5037 return (err);
5038 }
5039
5040 tabptr->zone_dev_attrp = NULL;
5041 for (val = cur->xmlChildrenNode; val != NULL; val = val->next) {
5042 struct zone_res_attrtab *valptr;
5043
5044 valptr = (struct zone_res_attrtab *)malloc(
5045 sizeof (struct zone_res_attrtab));
5046 if (valptr == NULL)
5047 return (Z_NOMEM);
5048
5049 valptr->zone_res_attr_name[0] =
5050 valptr->zone_res_attr_value[0] = '\0';
5051 if (zonecfg_add_res_attr(&(tabptr->zone_dev_attrp), valptr)
5052 != Z_OK) {
5053 free(valptr);
5054 break;
5055 }
5056
5057 if ((fetchprop(val, DTD_ATTR_NAME, valptr->zone_res_attr_name,
5058 sizeof (valptr->zone_res_attr_name)) != Z_OK))
5059 break;
5060 if ((fetchprop(val, DTD_ATTR_VALUE, valptr->zone_res_attr_value,
5061 sizeof (valptr->zone_res_attr_value)) != Z_OK))
5062 break;
5063 }
5064
5065 handle->zone_dh_cur = cur->next;
5066 return (Z_OK);
5067 }
5068
5069 int
5070 zonecfg_enddevent(zone_dochandle_t handle)
5071 {
5072 return (zonecfg_endent(handle));
5073 }
5074
5075 int
5076 zonecfg_setrctlent(zone_dochandle_t handle)
5077 {
5078 return (zonecfg_setent(handle));
5079 }
5080
5081 int
5082 zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr)
5083 {
5084 xmlNodePtr cur, val;
5773 return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL);
5774
5775 return (Z_OK);
5776 }
5777
5778 if (strcmp(zone_name, "global") == 0)
5779 return (zonecfg_default_brand(brandname, rp_sz));
5780
5781 if ((handle = zonecfg_init_handle()) == NULL)
5782 return (Z_NOMEM);
5783
5784 err = zonecfg_get_handle((char *)zone_name, handle);
5785 if (err == Z_OK)
5786 err = zonecfg_get_brand(handle, brandname, rp_sz);
5787
5788 zonecfg_fini_handle(handle);
5789 return (err);
5790 }
5791
5792 /*
5793 * Atomically get a new zone_did value. The currently allocated value
5794 * is stored in /etc/zones/did.txt. Lock the file, read the current value,
5795 * increment, save the new value and unlock the file. Return the new value
5796 * or -1 if there was an error. The ID namespace is large enough that we
5797 * don't worry about recycling an ID when a zone is deleted.
5798 */
5799 static zoneid_t
5800 new_zone_did()
5801 {
5802 int fd;
5803 int len;
5804 int val;
5805 struct flock lck;
5806 char buf[80];
5807
5808 if ((fd = open(DEBUGID_FILE, O_RDWR | O_CREAT,
5809 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
5810 perror("new_zone_did open failed");
5811 return (-1);
5812 }
5813
5814 /* Initialize the lock. */
5815 lck.l_whence = SEEK_SET;
5816 lck.l_start = 0;
5817 lck.l_len = 0;
5818
5819 /* Wait until we acquire an exclusive lock on the file. */
5820 lck.l_type = F_WRLCK;
5821 if (fcntl(fd, F_SETLKW, &lck) == -1) {
5822 perror("new_zone_did lock failed");
5823 (void) close(fd);
5824 return (-1);
5825 }
5826
5827 /* Get currently allocated value */
5828 len = read(fd, buf, sizeof (buf));
5829 if (len == -1) {
5830 perror("new_zone_did read failed");
5831 val = -1;
5832 } else {
5833 if (lseek(fd, 0L, SEEK_SET) == -1) {
5834 perror("new_zone_did seek failed");
5835 val = -1;
5836 } else {
5837 if (len == 0) {
5838 /* Just created the file, initialize at 1 */
5839 val = 1;
5840 } else {
5841 val = atoi(buf);
5842 val++;
5843 }
5844
5845 (void) snprintf(buf, sizeof (buf), "%d\n", val);
5846 len = strlen(buf);
5847
5848 /* Save newly allocated value */
5849 if (write(fd, buf, len) == -1) {
5850 perror("new_zone_did write failed");
5851 val = -1;
5852 }
5853 }
5854 }
5855
5856 /* Release the file lock. */
5857 lck.l_type = F_UNLCK;
5858 if (fcntl(fd, F_SETLK, &lck) == -1) {
5859 perror("new_zone_did unlock failed");
5860 val = -1;
5861 }
5862
5863 if (close(fd) != 0)
5864 perror("new_zone_did close failed");
5865
5866 return (val);
5867 }
5868
5869 /*
5870 * Called by zoneadmd to get the zone's debug ID.
5871 * If the zone doesn't already have an ID, a new one is generated and
5872 * persistently saved onto the zone. Normally either zoneadm or zonecfg
5873 * will assign a new ID for the zone, so zoneadmd should never have to
5874 * generate one, but we also handle that here just to be paranoid.
5875 */
5876 zoneid_t
5877 zone_get_did(char *zone_name)
5878 {
5879 int res;
5880 zoneid_t new_did;
5881 zone_dochandle_t handle;
5882 char did_str[80];
5883
5884 if ((handle = zonecfg_init_handle()) == NULL)
5885 return (getpid());
5886
5887 if (zonecfg_get_handle((char *)zone_name, handle) != Z_OK)
5888 return (getpid());
5889
5890 res = getrootattr(handle, DTD_ATTR_DID, did_str, sizeof (did_str));
5891
5892 /* If the zone already has an assigned debug ID, return it. */
5893 if (res == Z_OK && did_str[0] != '\0') {
5894 zonecfg_fini_handle(handle);
5895 return (atoi(did_str));
5896 }
5897
5898 /*
5899 * The zone doesn't have an assigned debug ID yet, generate one and
5900 * save it as part of the zone definition.
5901 */
5902 if ((new_did = new_zone_did()) == -1) {
5903 /*
5904 * We should really never hit this block of code.
5905 * Generating a new ID failed for some reason. Use the current
5906 * pid as a temporary ID so that the zone can continue to boot
5907 * but we don't persistently save this temporary ID on the zone.
5908 */
5909 zonecfg_fini_handle(handle);
5910 return (getpid());
5911 }
5912
5913 /* Now persistently save this new ID onto the zone. */
5914 (void) snprintf(did_str, sizeof (did_str), "%d", new_did);
5915 (void) setrootattr(handle, DTD_ATTR_DID, did_str);
5916 (void) zonecfg_save(handle);
5917
5918 zonecfg_fini_handle(handle);
5919 return (new_did);
5920 }
5921
5922 zoneid_t
5923 zonecfg_get_did(zone_dochandle_t handle)
5924 {
5925 char did_str[80];
5926 int err;
5927 zoneid_t did;
5928
5929 err = getrootattr(handle, DTD_ATTR_DID, did_str, sizeof (did_str));
5930 if (err == Z_OK && did_str[0] != '\0')
5931 did = atoi(did_str);
5932 else
5933 did = -1;
5934
5935 return (did);
5936 }
5937
5938 void
5939 zonecfg_set_did(zone_dochandle_t handle)
5940 {
5941 zoneid_t new_did;
5942 char did_str[80];
5943
5944 if ((new_did = new_zone_did()) == -1)
5945 return;
5946 (void) snprintf(did_str, sizeof (did_str), "%d", new_did);
5947 (void) setrootattr(handle, DTD_ATTR_DID, did_str);
5948 }
5949
5950 /*
5951 * Return the appropriate root for the active /dev.
5952 * For normal zone, the path is $ZONEPATH/root;
5953 * for scratch zone, the dev path is $ZONEPATH/lu.
5954 */
5955 int
5956 zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz)
5957 {
5958 int err;
5959 char *suffix;
5960 zone_state_t state;
5961
5962 /* This function makes sense for non-global zones only. */
5963 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0)
5964 return (Z_BOGUS_ZONE_NAME);
5965 if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK)
5966 return (err);
5967
5968 if (zone_get_state(zone_name, &state) == Z_OK &&
5969 state == ZONE_STATE_MOUNTED)
5970 suffix = "/lu";
7245 }
7246
7247 return (res);
7248 }
7249
7250 int
7251 zonecfg_getpsetent(zone_dochandle_t handle, struct zone_psettab *tabptr)
7252 {
7253 int err;
7254
7255 if ((err = zonecfg_setent(handle)) != Z_OK)
7256 return (err);
7257
7258 err = zonecfg_lookup_pset(handle, tabptr);
7259
7260 (void) zonecfg_endent(handle);
7261
7262 return (err);
7263 }
7264
7265 /*
7266 * Cleanup obsolete constructs in the configuration.
7267 * Return true of the config has been updated and must be commited.
7268 */
7269 int
7270 zonecfg_fix_obsolete(zone_dochandle_t handle)
7271 {
7272 int res = 0;
7273 int add_physmem_rctl = 0;
7274 xmlNodePtr cur;
7275 char zone_physmem_cap[MAXNAMELEN];
7276
7277 if (operation_prep(handle) != Z_OK)
7278 return (res);
7279
7280 /*
7281 * If an obsolete mcap entry exists, convert it to the rctl.
7282 */
7283 cur = handle->zone_dh_cur;
7284 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
7285 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0)
7286 continue;
7287
7288 if (fetchprop(cur, DTD_ATTR_PHYSCAP,
7289 zone_physmem_cap, sizeof (zone_physmem_cap)) == Z_OK) {
7290 res = 1;
7291 add_physmem_rctl = 1;
7292 }
7293
7294 xmlUnlinkNode(cur);
7295 xmlFreeNode(cur);
7296 break;
7297 }
7298
7299 if (add_physmem_rctl) {
7300 uint64_t cap;
7301 char *endp;
7302
7303 cap = strtoull(zone_physmem_cap, &endp, 10);
7304 (void) zonecfg_set_aliased_rctl(handle, ALIAS_MAXPHYSMEM, cap);
7305 }
7306
7307 return (res);
7308 }
7309
7310 /*
7311 * Get the full tree of pkg metadata in a set of nested AVL trees.
7312 * pkgs_avl is an AVL tree of pkgs.
7313 *
7314 * The zone xml data contains DTD_ELEM_PACKAGE elements.
7315 */
7316 int
7317 zonecfg_getpkgdata(zone_dochandle_t handle, uu_avl_pool_t *pkg_pool,
7318 uu_avl_t *pkgs_avl)
7319 {
7320 xmlNodePtr cur;
7321 int res;
7322 zone_pkg_entry_t *pkg;
7323 char name[MAXNAMELEN];
7324 char version[ZONE_PKG_VERSMAX];
7325
7326 if (handle == NULL)
7327 return (Z_INVAL);
7328
7329 if ((res = zonecfg_setent(handle)) != Z_OK)
7955 struct stat config_st, ua_st;
7956 char config_file[MAXPATHLEN];
7957 boolean_t changed = B_FALSE;
7958 int err;
7959
7960 if ((uaf = fopen(USERATTR_FILENAME, "r")) == NULL) {
7961 zerror(zonename, gettext("could not open file %s: %s"),
7962 USERATTR_FILENAME, strerror(errno));
7963 if (errno == EACCES)
7964 return (Z_ACCES);
7965 if (errno == ENOENT)
7966 return (Z_NO_ZONE);
7967 return (Z_MISC_FS);
7968 }
7969 if ((err = fstat(fileno(uaf), &ua_st)) != 0) {
7970 zerror(zonename, gettext("could not stat file %s: %s"),
7971 USERATTR_FILENAME, strerror(errno));
7972 (void) fclose(uaf);
7973 return (Z_MISC_FS);
7974 }
7975 if (!config_file_path(zonename, config_file, sizeof (config_file))) {
7976 (void) fclose(uaf);
7977 return (Z_MISC_FS);
7978 }
7979
7980 if ((err = stat(config_file, &config_st)) != 0) {
7981 zerror(zonename, gettext("could not stat file %s: %s"),
7982 config_file, strerror(errno));
7983 (void) fclose(uaf);
7984 return (Z_MISC_FS);
7985 }
7986 if (config_st.st_mtime >= ua_st.st_mtime) {
7987 (void) fclose(uaf);
7988 return (Z_NO_ENTRY);
7989 }
7990 if ((err = zonecfg_delete_admins(handle, zonename)) == Z_OK) {
7991 changed = B_TRUE;
7992 } else if (err != Z_NO_ENTRY) {
7993 (void) fclose(uaf);
7994 return (err);
7995 }
|