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