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