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 (c) 2018, Joyent, Inc.
26 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
27 * Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
28 */
29
30 #include <libsysevent.h>
31 #include <pthread.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <fnmatch.h>
35 #include <strings.h>
36 #include <unistd.h>
37 #include <assert.h>
38 #include <libgen.h>
39 #include <libintl.h>
40 #include <alloca.h>
41 #include <ctype.h>
42 #include <sys/acl.h>
43 #include <sys/stat.h>
44 #include <sys/brand.h>
45 #include <sys/mntio.h>
46 #include <sys/mnttab.h>
47 #include <sys/nvpair.h>
48 #include <sys/types.h>
49 #include <sys/sockio.h>
50 #include <sys/systeminfo.h>
51 #include <ftw.h>
52 #include <pool.h>
53 #include <libscf.h>
54 #include <libproc.h>
55 #include <sys/priocntl.h>
56 #include <libuutil.h>
57 #include <wait.h>
58 #include <bsm/adt.h>
59 #include <auth_attr.h>
60 #include <auth_list.h>
61 #include <secdb.h>
62 #include <user_attr.h>
63 #include <prof_attr.h>
64 #include <definit.h>
65
66 #include <arpa/inet.h>
67 #include <netdb.h>
68
69 #include <libxml/xmlmemory.h>
70 #include <libxml/parser.h>
71
72 #include <libdevinfo.h>
73 #include <uuid/uuid.h>
74 #include <dirent.h>
75 #include <libbrand.h>
76
77 #include <libzonecfg.h>
78 #include "zonecfg_impl.h"
79
80 #define _PATH_TMPFILE "/zonecfg.XXXXXX"
81 #define ZONE_CB_RETRY_COUNT 10
82 #define ZONE_EVENT_PING_SUBCLASS "ping"
83 #define ZONE_EVENT_PING_PUBLISHER "solaris"
84
85 /* Hard-code the DTD element/attribute/entity names just once, here. */
86 #define DTD_ELEM_ATTR (const xmlChar *) "attr"
87 #define DTD_ELEM_COMMENT (const xmlChar *) "comment"
88 #define DTD_ELEM_DEVICE (const xmlChar *) "device"
89 #define DTD_ELEM_FS (const xmlChar *) "filesystem"
90 #define DTD_ELEM_FSOPTION (const xmlChar *) "fsoption"
91 #define DTD_ELEM_NET (const xmlChar *) "network"
92 #define DTD_ELEM_RCTL (const xmlChar *) "rctl"
93 #define DTD_ELEM_RCTLVALUE (const xmlChar *) "rctl-value"
94 #define DTD_ELEM_ZONE (const xmlChar *) "zone"
95 #define DTD_ELEM_DATASET (const xmlChar *) "dataset"
96 #define DTD_ELEM_TMPPOOL (const xmlChar *) "tmp_pool"
97 #define DTD_ELEM_PSET (const xmlChar *) "pset"
98 #define DTD_ELEM_MCAP (const xmlChar *) "mcap"
99 #define DTD_ELEM_PACKAGE (const xmlChar *) "package"
100 #define DTD_ELEM_OBSOLETES (const xmlChar *) "obsoletes"
101 #define DTD_ELEM_DEV_PERM (const xmlChar *) "dev-perm"
102 #define DTD_ELEM_ADMIN (const xmlChar *) "admin"
103 #define DTD_ELEM_SECFLAGS (const xmlChar *) "security-flags"
104
105 #define DTD_ATTR_ACTION (const xmlChar *) "action"
106 #define DTD_ATTR_ADDRESS (const xmlChar *) "address"
107 #define DTD_ATTR_ALLOWED_ADDRESS (const xmlChar *) "allowed-address"
108 #define DTD_ATTR_AUTOBOOT (const xmlChar *) "autoboot"
109 #define DTD_ATTR_IPTYPE (const xmlChar *) "ip-type"
110 #define DTD_ATTR_DEFROUTER (const xmlChar *) "defrouter"
111 #define DTD_ATTR_DIR (const xmlChar *) "directory"
112 #define DTD_ATTR_LIMIT (const xmlChar *) "limit"
113 #define DTD_ATTR_LIMITPRIV (const xmlChar *) "limitpriv"
114 #define DTD_ATTR_BOOTARGS (const xmlChar *) "bootargs"
115 #define DTD_ATTR_SCHED (const xmlChar *) "scheduling-class"
116 #define DTD_ATTR_MATCH (const xmlChar *) "match"
117 #define DTD_ATTR_NAME (const xmlChar *) "name"
118 #define DTD_ATTR_PHYSICAL (const xmlChar *) "physical"
119 #define DTD_ATTR_POOL (const xmlChar *) "pool"
120 #define DTD_ATTR_PRIV (const xmlChar *) "priv"
121 #define DTD_ATTR_RAW (const xmlChar *) "raw"
122 #define DTD_ATTR_SPECIAL (const xmlChar *) "special"
123 #define DTD_ATTR_TYPE (const xmlChar *) "type"
124 #define DTD_ATTR_VALUE (const xmlChar *) "value"
125 #define DTD_ATTR_ZONEPATH (const xmlChar *) "zonepath"
126 #define DTD_ATTR_NCPU_MIN (const xmlChar *) "ncpu_min"
127 #define DTD_ATTR_NCPU_MAX (const xmlChar *) "ncpu_max"
128 #define DTD_ATTR_IMPORTANCE (const xmlChar *) "importance"
129 #define DTD_ATTR_PHYSCAP (const xmlChar *) "physcap"
130 #define DTD_ATTR_VERSION (const xmlChar *) "version"
131 #define DTD_ATTR_ID (const xmlChar *) "id"
132 #define DTD_ATTR_UID (const xmlChar *) "uid"
133 #define DTD_ATTR_GID (const xmlChar *) "gid"
134 #define DTD_ATTR_MODE (const xmlChar *) "mode"
135 #define DTD_ATTR_ACL (const xmlChar *) "acl"
136 #define DTD_ATTR_BRAND (const xmlChar *) "brand"
137 #define DTD_ATTR_HOSTID (const xmlChar *) "hostid"
138 #define DTD_ATTR_USER (const xmlChar *) "user"
139 #define DTD_ATTR_AUTHS (const xmlChar *) "auths"
140 #define DTD_ATTR_FS_ALLOWED (const xmlChar *) "fs-allowed"
141 #define DTD_ATTR_DEFAULT (const xmlChar *) "default"
142 #define DTD_ATTR_LOWER (const xmlChar *) "lower"
143 #define DTD_ATTR_UPPER (const xmlChar *) "upper"
144
145
146 #define DTD_ENTITY_BOOLEAN "boolean"
147 #define DTD_ENTITY_DEVPATH "devpath"
148 #define DTD_ENTITY_DRIVER "driver"
149 #define DTD_ENTITY_DRVMIN "drv_min"
150 #define DTD_ENTITY_FALSE "false"
151 #define DTD_ENTITY_INT "int"
152 #define DTD_ENTITY_STRING "string"
153 #define DTD_ENTITY_TRUE "true"
154 #define DTD_ENTITY_UINT "uint"
155
156 #define DTD_ENTITY_BOOL_LEN 6 /* "false" */
157
158 #define ATTACH_FORCED "SUNWattached.xml"
159
160 #define TMP_POOL_NAME "SUNWtmp_%s"
161 #define MAX_TMP_POOL_NAME (ZONENAME_MAX + 9)
162 #define RCAP_SERVICE "system/rcap:default"
163 #define POOLD_SERVICE "system/pools/dynamic:default"
164
165 /*
166 * rctl alias definitions
167 *
168 * This holds the alias, the full rctl name, the default priv value, action
169 * and lower limit. The functions that handle rctl aliases step through
170 * this table, matching on the alias, and using the full values for setting
171 * the rctl entry as well the limit for validation.
172 */
173 static struct alias {
174 char *shortname;
175 char *realname;
176 char *priv;
177 char *action;
178 uint64_t low_limit;
179 } aliases[] = {
180 {ALIAS_MAXLWPS, "zone.max-lwps", "privileged", "deny", 100},
181 {ALIAS_MAXSHMMEM, "zone.max-shm-memory", "privileged", "deny", 0},
182 {ALIAS_MAXSHMIDS, "zone.max-shm-ids", "privileged", "deny", 0},
183 {ALIAS_MAXMSGIDS, "zone.max-msg-ids", "privileged", "deny", 0},
184 {ALIAS_MAXSEMIDS, "zone.max-sem-ids", "privileged", "deny", 0},
185 {ALIAS_MAXLOCKEDMEM, "zone.max-locked-memory", "privileged", "deny", 0},
186 {ALIAS_MAXSWAP, "zone.max-swap", "privileged", "deny", 0},
187 {ALIAS_SHARES, "zone.cpu-shares", "privileged", "none", 0},
188 {ALIAS_CPUCAP, "zone.cpu-cap", "privileged", "deny", 0},
189 {ALIAS_MAXPROCS, "zone.max-processes", "privileged", "deny", 100},
190 {NULL, NULL, NULL, NULL, 0}
191 };
192
193 /*
194 * Structure for applying rctls to a running zone. It allows important
195 * process values to be passed together easily.
196 */
197 typedef struct pr_info_handle {
198 struct ps_prochandle *pr;
199 pid_t pid;
200 } pr_info_handle_t;
201
202 struct zone_dochandle {
203 char *zone_dh_rootdir;
204 xmlDocPtr zone_dh_doc;
205 xmlNodePtr zone_dh_cur;
206 xmlNodePtr zone_dh_top;
207 boolean_t zone_dh_newzone;
208 boolean_t zone_dh_snapshot;
209 boolean_t zone_dh_sw_inv;
210 zone_userauths_t *zone_dh_userauths;
211 char zone_dh_delete_name[ZONENAME_MAX];
212 };
213
214 struct znotify {
215 void * zn_private;
216 evchan_t *zn_eventchan;
217 int (*zn_callback)(const char *zonename, zoneid_t zid,
218 const char *newstate, const char *oldstate, hrtime_t when, void *p);
219 pthread_mutex_t zn_mutex;
220 pthread_cond_t zn_cond;
221 pthread_mutex_t zn_bigmutex;
222 volatile enum {ZN_UNLOCKED, ZN_LOCKED, ZN_PING_INFLIGHT,
223 ZN_PING_RECEIVED} zn_state;
224 char zn_subscriber_id[MAX_SUBID_LEN];
225 volatile boolean_t zn_failed;
226 int zn_failure_count;
227 };
228
229 /* used to track nested zone-lock operations */
230 static int zone_lock_cnt = 0;
231
232 /* used to communicate lock status to children */
233 #define LOCK_ENV_VAR "_ZONEADM_LOCK_HELD"
234 static char zoneadm_lock_held[] = LOCK_ENV_VAR"=1";
235 static char zoneadm_lock_not_held[] = LOCK_ENV_VAR"=0";
236
237 char *zonecfg_root = "";
238
239 /*
240 * For functions which return int, which is most of the functions herein,
241 * the return values should be from the Z_foo set defined in <libzonecfg.h>.
242 * In some instances, we take pains mapping some libc errno values to Z_foo
243 * values from this set.
244 */
245
246 /*
247 * Set the root (/) path for all zonecfg configuration files. This is a
248 * private interface used by Live Upgrade extensions to access zone
249 * configuration inside mounted alternate boot environments.
250 * This interface is also used by zoneadm mount and unmount subcommands.
251 */
252 void
zonecfg_set_root(const char * rootpath)253 zonecfg_set_root(const char *rootpath)
254 {
255 if (*zonecfg_root != '\0')
256 free(zonecfg_root);
257 if (rootpath == NULL || rootpath[0] == '\0' || rootpath[1] == '\0' ||
258 (zonecfg_root = strdup(rootpath)) == NULL)
259 zonecfg_root = "";
260 }
261
262 const char *
zonecfg_get_root(void)263 zonecfg_get_root(void)
264 {
265 return (zonecfg_root);
266 }
267
268 boolean_t
zonecfg_in_alt_root(void)269 zonecfg_in_alt_root(void)
270 {
271 return (*zonecfg_root != '\0');
272 }
273
274 /*
275 * Callers of the _file_path() functions are expected to have the second
276 * parameter be a (char foo[MAXPATHLEN]).
277 */
278
279 static boolean_t
config_file_path(const char * zonename,char * answer)280 config_file_path(const char *zonename, char *answer)
281 {
282 return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root,
283 ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN);
284 }
285
286 static boolean_t
snap_file_path(const char * zonename,char * answer)287 snap_file_path(const char *zonename, char *answer)
288 {
289 return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml",
290 zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN);
291 }
292
293 /*ARGSUSED*/
294 static void
zonecfg_error_func(void * ctx,const char * msg,...)295 zonecfg_error_func(void *ctx, const char *msg, ...)
296 {
297 /*
298 * This function does nothing by design. Its purpose is to prevent
299 * libxml from dumping unwanted messages to stdout/stderr.
300 */
301 }
302
303 zone_dochandle_t
zonecfg_init_handle(void)304 zonecfg_init_handle(void)
305 {
306 zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle));
307 if (handle == NULL) {
308 errno = Z_NOMEM;
309 return (NULL);
310 }
311
312 /* generic libxml initialization */
313 (void) xmlLineNumbersDefault(1);
314 xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS;
315 xmlDoValidityCheckingDefaultValue = 1;
316 (void) xmlKeepBlanksDefault(0);
317 xmlGetWarningsDefaultValue = 0;
318 xmlSetGenericErrorFunc(NULL, zonecfg_error_func);
319
320 return (handle);
321 }
322
323 int
zonecfg_check_handle(zone_dochandle_t handle)324 zonecfg_check_handle(zone_dochandle_t handle)
325 {
326 if (handle == NULL || handle->zone_dh_doc == NULL)
327 return (Z_BAD_HANDLE);
328 return (Z_OK);
329 }
330
331 void
zonecfg_fini_handle(zone_dochandle_t handle)332 zonecfg_fini_handle(zone_dochandle_t handle)
333 {
334 if (zonecfg_check_handle(handle) == Z_OK)
335 xmlFreeDoc(handle->zone_dh_doc);
336 if (handle != NULL)
337 free(handle);
338 }
339
340 static int
zonecfg_destroy_impl(char * filename)341 zonecfg_destroy_impl(char *filename)
342 {
343 if (unlink(filename) == -1) {
344 if (errno == EACCES)
345 return (Z_ACCES);
346 if (errno == ENOENT)
347 return (Z_NO_ZONE);
348 return (Z_MISC_FS);
349 }
350 return (Z_OK);
351 }
352
353 int
zonecfg_destroy(const char * zonename,boolean_t force)354 zonecfg_destroy(const char *zonename, boolean_t force)
355 {
356 char path[MAXPATHLEN];
357 struct zoneent ze;
358 int err, state_err;
359 zone_state_t state;
360
361 if (!config_file_path(zonename, path))
362 return (Z_MISC_FS);
363
364 state_err = zone_get_state((char *)zonename, &state);
365 err = access(path, W_OK);
366
367 /*
368 * If there is no file, and no index entry, reliably indicate that no
369 * such zone exists.
370 */
371 if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT))
372 return (Z_NO_ZONE);
373
374 /*
375 * Handle any other filesystem related errors (except if the XML
376 * file is missing, which we treat silently), unless we're forcing,
377 * in which case we plow on.
378 */
379 if (err == -1 && errno != ENOENT) {
380 if (errno == EACCES)
381 return (Z_ACCES);
382 else if (!force)
383 return (Z_MISC_FS);
384 }
385
386 if (state > ZONE_STATE_INSTALLED)
387 return (Z_BAD_ZONE_STATE);
388
389 if (!force && state > ZONE_STATE_CONFIGURED)
390 return (Z_BAD_ZONE_STATE);
391
392 /*
393 * Index deletion succeeds even if the entry doesn't exist. So this
394 * will fail only if we've had some more severe problem.
395 */
396 bzero(&ze, sizeof (ze));
397 (void) strlcpy(ze.zone_name, zonename, sizeof (ze.zone_name));
398 if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK)
399 if (!force)
400 return (err);
401
402 err = zonecfg_destroy_impl(path);
403
404 /*
405 * Treat failure to find the XML file silently, since, well, it's
406 * gone, and with the index file cleaned up, we're done.
407 */
408 if (err == Z_OK || err == Z_NO_ZONE)
409 return (Z_OK);
410 return (err);
411 }
412
413 int
zonecfg_destroy_snapshot(const char * zonename)414 zonecfg_destroy_snapshot(const char *zonename)
415 {
416 char path[MAXPATHLEN];
417
418 if (!snap_file_path(zonename, path))
419 return (Z_MISC_FS);
420 return (zonecfg_destroy_impl(path));
421 }
422
423 static int
getroot(zone_dochandle_t handle,xmlNodePtr * root)424 getroot(zone_dochandle_t handle, xmlNodePtr *root)
425 {
426 if (zonecfg_check_handle(handle) == Z_BAD_HANDLE)
427 return (Z_BAD_HANDLE);
428
429 *root = xmlDocGetRootElement(handle->zone_dh_doc);
430
431 if (*root == NULL)
432 return (Z_EMPTY_DOCUMENT);
433
434 if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE))
435 return (Z_WRONG_DOC_TYPE);
436
437 return (Z_OK);
438 }
439
440 static int
operation_prep(zone_dochandle_t handle)441 operation_prep(zone_dochandle_t handle)
442 {
443 xmlNodePtr root;
444 int err;
445
446 if ((err = getroot(handle, &root)) != 0)
447 return (err);
448
449 handle->zone_dh_cur = root;
450 handle->zone_dh_top = root;
451 return (Z_OK);
452 }
453
454 static int
fetchprop(xmlNodePtr cur,const xmlChar * propname,char * dst,size_t dstsize)455 fetchprop(xmlNodePtr cur, const xmlChar *propname, char *dst, size_t dstsize)
456 {
457 xmlChar *property;
458 size_t srcsize;
459
460 if ((property = xmlGetProp(cur, propname)) == NULL)
461 return (Z_BAD_PROPERTY);
462 srcsize = strlcpy(dst, (char *)property, dstsize);
463 xmlFree(property);
464 if (srcsize >= dstsize)
465 return (Z_TOO_BIG);
466 return (Z_OK);
467 }
468
469 static int
fetch_alloc_prop(xmlNodePtr cur,const xmlChar * propname,char ** dst)470 fetch_alloc_prop(xmlNodePtr cur, const xmlChar *propname, char **dst)
471 {
472 xmlChar *property;
473
474 if ((property = xmlGetProp(cur, propname)) == NULL)
475 return (Z_BAD_PROPERTY);
476 if ((*dst = strdup((char *)property)) == NULL) {
477 xmlFree(property);
478 return (Z_NOMEM);
479 }
480 xmlFree(property);
481 return (Z_OK);
482 }
483
484 static int
getrootattr(zone_dochandle_t handle,const xmlChar * propname,char * propval,size_t propsize)485 getrootattr(zone_dochandle_t handle, const xmlChar *propname,
486 char *propval, size_t propsize)
487 {
488 xmlNodePtr root;
489 int err;
490
491 if ((err = getroot(handle, &root)) != 0)
492 return (err);
493
494 return (fetchprop(root, propname, propval, propsize));
495 }
496
497 static int
get_alloc_rootattr(zone_dochandle_t handle,const xmlChar * propname,char ** propval)498 get_alloc_rootattr(zone_dochandle_t handle, const xmlChar *propname,
499 char **propval)
500 {
501 xmlNodePtr root;
502 int err;
503
504 if ((err = getroot(handle, &root)) != 0)
505 return (err);
506
507 return (fetch_alloc_prop(root, propname, propval));
508 }
509
510 static int
setrootattr(zone_dochandle_t handle,const xmlChar * propname,const char * propval)511 setrootattr(zone_dochandle_t handle, const xmlChar *propname,
512 const char *propval)
513 {
514 int err;
515 xmlNodePtr root;
516
517 if ((err = getroot(handle, &root)) != Z_OK)
518 return (err);
519
520 /*
521 * If we get a null propval remove the property (ignore return since it
522 * may not be set to begin with).
523 */
524 if (propval == NULL) {
525 (void) xmlUnsetProp(root, propname);
526 } else {
527 if (xmlSetProp(root, propname, (const xmlChar *) propval)
528 == NULL)
529 return (Z_INVAL);
530 }
531 return (Z_OK);
532 }
533
534 static void
addcomment(zone_dochandle_t handle,const char * comment)535 addcomment(zone_dochandle_t handle, const char *comment)
536 {
537 xmlNodePtr node;
538 node = xmlNewComment((xmlChar *) comment);
539
540 if (node != NULL)
541 (void) xmlAddPrevSibling(handle->zone_dh_top, node);
542 }
543
544 static void
stripcomments(zone_dochandle_t handle)545 stripcomments(zone_dochandle_t handle)
546 {
547 xmlDocPtr top;
548 xmlNodePtr child, next;
549
550 top = handle->zone_dh_doc;
551 for (child = top->xmlChildrenNode; child != NULL; child = next) {
552 next = child->next;
553 if (child->name == NULL)
554 continue;
555 if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) {
556 next = child->next;
557 xmlUnlinkNode(child);
558 xmlFreeNode(child);
559 }
560 }
561 }
562
563 static void
strip_sw_inv(zone_dochandle_t handle)564 strip_sw_inv(zone_dochandle_t handle)
565 {
566 xmlNodePtr root, child, next;
567
568 root = xmlDocGetRootElement(handle->zone_dh_doc);
569 for (child = root->xmlChildrenNode; child != NULL; child = next) {
570 next = child->next;
571 if (child->name == NULL)
572 continue;
573 if (xmlStrcmp(child->name, DTD_ELEM_PACKAGE) == 0) {
574 next = child->next;
575 xmlUnlinkNode(child);
576 xmlFreeNode(child);
577 }
578 }
579 }
580
581 static int
zonecfg_get_handle_impl(const char * zonename,const char * filename,zone_dochandle_t handle)582 zonecfg_get_handle_impl(const char *zonename, const char *filename,
583 zone_dochandle_t handle)
584 {
585 xmlValidCtxtPtr cvp;
586 struct stat statbuf;
587 int valid;
588
589 if (zonename == NULL)
590 return (Z_NO_ZONE);
591
592 if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) {
593 /* distinguish file not found vs. found but not parsed */
594 if (stat(filename, &statbuf) == 0)
595 return (Z_INVALID_DOCUMENT);
596 return (Z_NO_ZONE);
597 }
598 if ((cvp = xmlNewValidCtxt()) == NULL)
599 return (Z_NOMEM);
600 cvp->error = zonecfg_error_func;
601 cvp->warning = zonecfg_error_func;
602 valid = xmlValidateDocument(cvp, handle->zone_dh_doc);
603 xmlFreeValidCtxt(cvp);
604 if (valid == 0)
605 return (Z_INVALID_DOCUMENT);
606
607 /* delete any comments such as inherited Sun copyright / ident str */
608 stripcomments(handle);
609 return (Z_OK);
610 }
611
612 int
zonecfg_get_handle(const char * zonename,zone_dochandle_t handle)613 zonecfg_get_handle(const char *zonename, zone_dochandle_t handle)
614 {
615 char path[MAXPATHLEN];
616
617 if (!config_file_path(zonename, path))
618 return (Z_MISC_FS);
619 handle->zone_dh_newzone = B_FALSE;
620
621 return (zonecfg_get_handle_impl(zonename, path, handle));
622 }
623
624 int
zonecfg_get_attach_handle(const char * path,const char * fname,const char * zonename,boolean_t preserve_sw,zone_dochandle_t handle)625 zonecfg_get_attach_handle(const char *path, const char *fname,
626 const char *zonename, boolean_t preserve_sw, zone_dochandle_t handle)
627 {
628 char migpath[MAXPATHLEN];
629 int err;
630 struct stat buf;
631
632 if (snprintf(migpath, sizeof (migpath), "%s/root", path) >=
633 sizeof (migpath))
634 return (Z_NOMEM);
635
636 if (stat(migpath, &buf) == -1 || !S_ISDIR(buf.st_mode))
637 return (Z_NO_ZONE);
638
639 if (snprintf(migpath, sizeof (migpath), "%s/%s", path, fname) >=
640 sizeof (migpath))
641 return (Z_NOMEM);
642
643 if ((err = zonecfg_get_handle_impl(zonename, migpath, handle)) != Z_OK)
644 return (err);
645
646 if (!preserve_sw)
647 strip_sw_inv(handle);
648
649 handle->zone_dh_newzone = B_TRUE;
650 if ((err = setrootattr(handle, DTD_ATTR_ZONEPATH, path)) != Z_OK)
651 return (err);
652
653 return (setrootattr(handle, DTD_ATTR_NAME, zonename));
654 }
655
656 int
zonecfg_get_snapshot_handle(const char * zonename,zone_dochandle_t handle)657 zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle)
658 {
659 char path[MAXPATHLEN];
660
661 if (!snap_file_path(zonename, path))
662 return (Z_MISC_FS);
663 handle->zone_dh_newzone = B_FALSE;
664 return (zonecfg_get_handle_impl(zonename, path, handle));
665 }
666
667 int
zonecfg_get_template_handle(const char * template,const char * zonename,zone_dochandle_t handle)668 zonecfg_get_template_handle(const char *template, const char *zonename,
669 zone_dochandle_t handle)
670 {
671 char path[MAXPATHLEN];
672 int err;
673
674 if (!config_file_path(template, path))
675 return (Z_MISC_FS);
676
677 if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK)
678 return (err);
679 handle->zone_dh_newzone = B_TRUE;
680 return (setrootattr(handle, DTD_ATTR_NAME, zonename));
681 }
682
683 int
zonecfg_get_xml_handle(const char * path,zone_dochandle_t handle)684 zonecfg_get_xml_handle(const char *path, zone_dochandle_t handle)
685 {
686 struct stat buf;
687 int err;
688
689 if (stat(path, &buf) == -1)
690 return (Z_MISC_FS);
691
692 if ((err = zonecfg_get_handle_impl("xml", path, handle)) != Z_OK)
693 return (err);
694 handle->zone_dh_newzone = B_TRUE;
695 return (Z_OK);
696 }
697
698 /*
699 * Initialize two handles from the manifest read on fd. The rem_handle
700 * is initialized from the input file, including the sw inventory. The
701 * local_handle is initialized with the same zone configuration but with
702 * no sw inventory.
703 */
704 int
zonecfg_attach_manifest(int fd,zone_dochandle_t local_handle,zone_dochandle_t rem_handle)705 zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle,
706 zone_dochandle_t rem_handle)
707 {
708 xmlValidCtxtPtr cvp;
709 int valid;
710
711 /* load the manifest into the handle for the remote system */
712 if ((rem_handle->zone_dh_doc = xmlReadFd(fd, NULL, NULL, 0)) == NULL) {
713 return (Z_INVALID_DOCUMENT);
714 }
715 if ((cvp = xmlNewValidCtxt()) == NULL)
716 return (Z_NOMEM);
717 cvp->error = zonecfg_error_func;
718 cvp->warning = zonecfg_error_func;
719 valid = xmlValidateDocument(cvp, rem_handle->zone_dh_doc);
720 xmlFreeValidCtxt(cvp);
721 if (valid == 0)
722 return (Z_INVALID_DOCUMENT);
723
724 /* delete any comments such as inherited Sun copyright / ident str */
725 stripcomments(rem_handle);
726
727 rem_handle->zone_dh_newzone = B_TRUE;
728 rem_handle->zone_dh_sw_inv = B_TRUE;
729
730 /*
731 * Now use the remote system handle to generate a local system handle
732 * with an identical zones configuration but no sw inventory.
733 */
734 if ((local_handle->zone_dh_doc = xmlCopyDoc(rem_handle->zone_dh_doc,
735 1)) == NULL) {
736 return (Z_INVALID_DOCUMENT);
737 }
738
739 /*
740 * We need to re-run xmlValidateDocument on local_handle to properly
741 * update the in-core representation of the configuration.
742 */
743 if ((cvp = xmlNewValidCtxt()) == NULL)
744 return (Z_NOMEM);
745 cvp->error = zonecfg_error_func;
746 cvp->warning = zonecfg_error_func;
747 valid = xmlValidateDocument(cvp, local_handle->zone_dh_doc);
748 xmlFreeValidCtxt(cvp);
749 if (valid == 0)
750 return (Z_INVALID_DOCUMENT);
751
752 strip_sw_inv(local_handle);
753
754 local_handle->zone_dh_newzone = B_TRUE;
755 local_handle->zone_dh_sw_inv = B_FALSE;
756
757 return (Z_OK);
758 }
759
760 static boolean_t
is_renaming(zone_dochandle_t handle)761 is_renaming(zone_dochandle_t handle)
762 {
763 if (handle->zone_dh_newzone)
764 return (B_FALSE);
765 if (strlen(handle->zone_dh_delete_name) > 0)
766 return (B_TRUE);
767 return (B_FALSE);
768 }
769
770 static boolean_t
is_new(zone_dochandle_t handle)771 is_new(zone_dochandle_t handle)
772 {
773 return (handle->zone_dh_newzone || handle->zone_dh_snapshot);
774 }
775
776 static boolean_t
is_snapshot(zone_dochandle_t handle)777 is_snapshot(zone_dochandle_t handle)
778 {
779 return (handle->zone_dh_snapshot);
780 }
781
782 /*
783 * It would be great to be able to use libc's ctype(3c) macros, but we
784 * can't, as they are locale sensitive, and it would break our limited thread
785 * safety if this routine had to change the app locale on the fly.
786 */
787 int
zonecfg_validate_zonename(const char * zone)788 zonecfg_validate_zonename(const char *zone)
789 {
790 int i;
791
792 if (strcmp(zone, GLOBAL_ZONENAME) == 0)
793 return (Z_BOGUS_ZONE_NAME);
794
795 if (strlen(zone) >= ZONENAME_MAX)
796 return (Z_BOGUS_ZONE_NAME);
797
798 if (!((zone[0] >= 'a' && zone[0] <= 'z') ||
799 (zone[0] >= 'A' && zone[0] <= 'Z') ||
800 (zone[0] >= '0' && zone[0] <= '9')))
801 return (Z_BOGUS_ZONE_NAME);
802
803 for (i = 1; zone[i] != '\0'; i++) {
804 if (!((zone[i] >= 'a' && zone[i] <= 'z') ||
805 (zone[i] >= 'A' && zone[i] <= 'Z') ||
806 (zone[i] >= '0' && zone[i] <= '9') ||
807 (zone[i] == '-') || (zone[i] == '_') || (zone[i] == '.')))
808 return (Z_BOGUS_ZONE_NAME);
809 }
810
811 return (Z_OK);
812 }
813
814 /*
815 * Changing the zone name requires us to track both the old and new
816 * name of the zone until commit time.
817 */
818 int
zonecfg_get_name(zone_dochandle_t handle,char * name,size_t namesize)819 zonecfg_get_name(zone_dochandle_t handle, char *name, size_t namesize)
820 {
821 return (getrootattr(handle, DTD_ATTR_NAME, name, namesize));
822 }
823
824 static int
insert_admins(zone_dochandle_t handle,char * zonename)825 insert_admins(zone_dochandle_t handle, char *zonename)
826 {
827 int err;
828 struct zone_admintab admintab;
829
830 if ((err = zonecfg_setadminent(handle)) != Z_OK) {
831 return (err);
832 }
833 while (zonecfg_getadminent(handle, &admintab) == Z_OK) {
834 err = zonecfg_insert_userauths(handle,
835 admintab.zone_admin_user, zonename);
836 if (err != Z_OK) {
837 (void) zonecfg_endadminent(handle);
838 return (err);
839 }
840 }
841 (void) zonecfg_endadminent(handle);
842 return (Z_OK);
843 }
844
845 int
zonecfg_set_name(zone_dochandle_t handle,char * name)846 zonecfg_set_name(zone_dochandle_t handle, char *name)
847 {
848 zone_state_t state;
849 char curname[ZONENAME_MAX], old_delname[ZONENAME_MAX];
850 int err;
851
852 if ((err = getrootattr(handle, DTD_ATTR_NAME, curname,
853 sizeof (curname))) != Z_OK)
854 return (err);
855
856 if (strcmp(name, curname) == 0)
857 return (Z_OK);
858
859 /*
860 * Switching zone names to one beginning with SUNW is not permitted.
861 */
862 if (strncmp(name, "SUNW", 4) == 0)
863 return (Z_BOGUS_ZONE_NAME);
864
865 if ((err = zonecfg_validate_zonename(name)) != Z_OK)
866 return (err);
867
868 /*
869 * Setting the name back to the original name (effectively a revert of
870 * the name) is fine. But if we carry on, we'll falsely identify the
871 * name as "in use," so special case here.
872 */
873 if (strcmp(name, handle->zone_dh_delete_name) == 0) {
874 err = setrootattr(handle, DTD_ATTR_NAME, name);
875 handle->zone_dh_delete_name[0] = '\0';
876 return (err);
877 }
878
879 /* Check to see if new name chosen is already in use */
880 if (zone_get_state(name, &state) != Z_NO_ZONE)
881 return (Z_NAME_IN_USE);
882
883 /*
884 * If this isn't already "new" or in a renaming transition, then
885 * we're initiating a rename here; so stash the "delete name"
886 * (i.e. the name of the zone we'll be removing) for the rename.
887 */
888 (void) strlcpy(old_delname, handle->zone_dh_delete_name,
889 sizeof (old_delname));
890 if (!is_new(handle) && !is_renaming(handle)) {
891 /*
892 * Name change is allowed only when the zone we're altering
893 * is not ready or running.
894 */
895 err = zone_get_state(curname, &state);
896 if (err == Z_OK) {
897 if (state > ZONE_STATE_INSTALLED)
898 return (Z_BAD_ZONE_STATE);
899 } else if (err != Z_NO_ZONE) {
900 return (err);
901 }
902
903 (void) strlcpy(handle->zone_dh_delete_name, curname,
904 sizeof (handle->zone_dh_delete_name));
905 assert(is_renaming(handle));
906 } else if (is_renaming(handle)) {
907 err = zone_get_state(handle->zone_dh_delete_name, &state);
908 if (err == Z_OK) {
909 if (state > ZONE_STATE_INSTALLED)
910 return (Z_BAD_ZONE_STATE);
911 } else if (err != Z_NO_ZONE) {
912 return (err);
913 }
914 }
915
916 if ((err = setrootattr(handle, DTD_ATTR_NAME, name)) != Z_OK) {
917 /*
918 * Restore the deletename to whatever it was at the
919 * top of the routine, since we've had a failure.
920 */
921 (void) strlcpy(handle->zone_dh_delete_name, old_delname,
922 sizeof (handle->zone_dh_delete_name));
923 return (err);
924 }
925
926 /*
927 * Record the old admins from the old zonename
928 * so that they can be deleted when the operation is committed.
929 */
930 if ((err = insert_admins(handle, curname)) != Z_OK)
931 return (err);
932 else
933 return (Z_OK);
934 }
935
936 int
zonecfg_get_zonepath(zone_dochandle_t handle,char * path,size_t pathsize)937 zonecfg_get_zonepath(zone_dochandle_t handle, char *path, size_t pathsize)
938 {
939 size_t len;
940
941 if ((len = strlcpy(path, zonecfg_root, pathsize)) >= pathsize)
942 return (Z_TOO_BIG);
943 return (getrootattr(handle, DTD_ATTR_ZONEPATH, path + len,
944 pathsize - len));
945 }
946
947 int
zonecfg_set_zonepath(zone_dochandle_t handle,char * zonepath)948 zonecfg_set_zonepath(zone_dochandle_t handle, char *zonepath)
949 {
950 size_t len;
951 char *modpath, *copy_mp, *curr_mp; /* modified path ptrs */
952 char last_copied;
953 int ret;
954
955 /*
956 * Collapse multiple contiguous slashes and remove trailing slash.
957 */
958 modpath = strdup(zonepath);
959 if (modpath == NULL)
960 return (Z_NOMEM);
961 last_copied = '\0';
962 for (copy_mp = curr_mp = modpath; *curr_mp != '\0'; curr_mp++) {
963 if (*curr_mp != '/' || last_copied != '/') {
964 last_copied = *copy_mp = *curr_mp;
965 copy_mp++;
966 }
967 }
968 if (last_copied == '/')
969 copy_mp--;
970 *copy_mp = '\0';
971
972 /*
973 * The user deals in absolute paths in the running global zone, but the
974 * internal configuration files deal with boot environment relative
975 * paths. Strip out the alternate root when specified.
976 */
977 len = strlen(zonecfg_root);
978 if (strncmp(modpath, zonecfg_root, len) != 0 || modpath[len] != '/') {
979 free(modpath);
980 return (Z_BAD_PROPERTY);
981 }
982 curr_mp = modpath + len;
983 ret = setrootattr(handle, DTD_ATTR_ZONEPATH, curr_mp);
984 free(modpath);
985 return (ret);
986 }
987
988 static int
i_zonecfg_get_brand(zone_dochandle_t handle,char * brand,size_t brandsize,boolean_t default_query)989 i_zonecfg_get_brand(zone_dochandle_t handle, char *brand, size_t brandsize,
990 boolean_t default_query)
991 {
992 int ret, sz;
993
994 ret = getrootattr(handle, DTD_ATTR_BRAND, brand, brandsize);
995
996 /*
997 * If the lookup failed, or succeeded in finding a non-null brand
998 * string then return.
999 */
1000 if (ret != Z_OK || brand[0] != '\0')
1001 return (ret);
1002
1003 if (!default_query) {
1004 /* If the zone has no brand, it is the default brand. */
1005 return (zonecfg_default_brand(brand, brandsize));
1006 }
1007
1008 /* if SUNWdefault didn't specify a brand, fallback to "native" */
1009 sz = strlcpy(brand, NATIVE_BRAND_NAME, brandsize);
1010 if (sz >= brandsize)
1011 return (Z_TOO_BIG);
1012 return (Z_OK);
1013 }
1014
1015 int
zonecfg_get_brand(zone_dochandle_t handle,char * brand,size_t brandsize)1016 zonecfg_get_brand(zone_dochandle_t handle, char *brand, size_t brandsize)
1017 {
1018 return (i_zonecfg_get_brand(handle, brand, brandsize, B_FALSE));
1019 }
1020
1021 int
zonecfg_set_brand(zone_dochandle_t handle,char * brand)1022 zonecfg_set_brand(zone_dochandle_t handle, char *brand)
1023 {
1024 return (setrootattr(handle, DTD_ATTR_BRAND, brand));
1025 }
1026
1027 int
zonecfg_get_autoboot(zone_dochandle_t handle,boolean_t * autoboot)1028 zonecfg_get_autoboot(zone_dochandle_t handle, boolean_t *autoboot)
1029 {
1030 char autobootstr[DTD_ENTITY_BOOL_LEN];
1031 int ret;
1032
1033 if ((ret = getrootattr(handle, DTD_ATTR_AUTOBOOT, autobootstr,
1034 sizeof (autobootstr))) != Z_OK)
1035 return (ret);
1036
1037 if (strcmp(autobootstr, DTD_ENTITY_TRUE) == 0)
1038 *autoboot = B_TRUE;
1039 else if (strcmp(autobootstr, DTD_ENTITY_FALSE) == 0)
1040 *autoboot = B_FALSE;
1041 else
1042 ret = Z_BAD_PROPERTY;
1043 return (ret);
1044 }
1045
1046 int
zonecfg_set_autoboot(zone_dochandle_t handle,boolean_t autoboot)1047 zonecfg_set_autoboot(zone_dochandle_t handle, boolean_t autoboot)
1048 {
1049 return (setrootattr(handle, DTD_ATTR_AUTOBOOT,
1050 autoboot ? DTD_ENTITY_TRUE : DTD_ENTITY_FALSE));
1051 }
1052
1053 int
zonecfg_get_pool(zone_dochandle_t handle,char * pool,size_t poolsize)1054 zonecfg_get_pool(zone_dochandle_t handle, char *pool, size_t poolsize)
1055 {
1056 return (getrootattr(handle, DTD_ATTR_POOL, pool, poolsize));
1057 }
1058
1059 int
zonecfg_set_pool(zone_dochandle_t handle,char * pool)1060 zonecfg_set_pool(zone_dochandle_t handle, char *pool)
1061 {
1062 return (setrootattr(handle, DTD_ATTR_POOL, pool));
1063 }
1064
1065 int
zonecfg_get_limitpriv(zone_dochandle_t handle,char ** limitpriv)1066 zonecfg_get_limitpriv(zone_dochandle_t handle, char **limitpriv)
1067 {
1068 return (get_alloc_rootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv));
1069 }
1070
1071 int
zonecfg_set_limitpriv(zone_dochandle_t handle,char * limitpriv)1072 zonecfg_set_limitpriv(zone_dochandle_t handle, char *limitpriv)
1073 {
1074 return (setrootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv));
1075 }
1076
1077 int
zonecfg_get_bootargs(zone_dochandle_t handle,char * bargs,size_t bargssize)1078 zonecfg_get_bootargs(zone_dochandle_t handle, char *bargs, size_t bargssize)
1079 {
1080 return (getrootattr(handle, DTD_ATTR_BOOTARGS, bargs, bargssize));
1081 }
1082
1083 int
zonecfg_set_bootargs(zone_dochandle_t handle,char * bargs)1084 zonecfg_set_bootargs(zone_dochandle_t handle, char *bargs)
1085 {
1086 return (setrootattr(handle, DTD_ATTR_BOOTARGS, bargs));
1087 }
1088
1089 int
zonecfg_get_sched_class(zone_dochandle_t handle,char * sched,size_t schedsize)1090 zonecfg_get_sched_class(zone_dochandle_t handle, char *sched, size_t schedsize)
1091 {
1092 return (getrootattr(handle, DTD_ATTR_SCHED, sched, schedsize));
1093 }
1094
1095 int
zonecfg_set_sched(zone_dochandle_t handle,char * sched)1096 zonecfg_set_sched(zone_dochandle_t handle, char *sched)
1097 {
1098 return (setrootattr(handle, DTD_ATTR_SCHED, sched));
1099 }
1100
1101 /*
1102 * /etc/zones/index caches a vital piece of information which is also
1103 * in the <zonename>.xml file: the path to the zone. This is for performance,
1104 * since we need to walk all zonepath's in order to be able to detect conflicts
1105 * (see crosscheck_zonepaths() in the zoneadm command).
1106 *
1107 * An additional complexity is that when doing a rename, we'd like the entire
1108 * index update operation (rename, and potential state changes) to be atomic.
1109 * In general, the operation of this function should succeed or fail as
1110 * a unit.
1111 */
1112 int
zonecfg_refresh_index_file(zone_dochandle_t handle)1113 zonecfg_refresh_index_file(zone_dochandle_t handle)
1114 {
1115 char name[ZONENAME_MAX], zonepath[MAXPATHLEN];
1116 struct zoneent ze;
1117 int err;
1118 int opcode;
1119 char *zn;
1120
1121 bzero(&ze, sizeof (ze));
1122 ze.zone_state = -1; /* Preserve existing state in index */
1123
1124 if ((err = zonecfg_get_name(handle, name, sizeof (name))) != Z_OK)
1125 return (err);
1126 (void) strlcpy(ze.zone_name, name, sizeof (ze.zone_name));
1127
1128 if ((err = zonecfg_get_zonepath(handle, zonepath,
1129 sizeof (zonepath))) != Z_OK)
1130 return (err);
1131 (void) strlcpy(ze.zone_path, zonepath + strlen(zonecfg_root),
1132 sizeof (ze.zone_path));
1133
1134 if (is_renaming(handle)) {
1135 opcode = PZE_MODIFY;
1136 (void) strlcpy(ze.zone_name, handle->zone_dh_delete_name,
1137 sizeof (ze.zone_name));
1138 (void) strlcpy(ze.zone_newname, name, sizeof (ze.zone_newname));
1139 } else if (is_new(handle)) {
1140 FILE *cookie;
1141 /*
1142 * Be tolerant of the zone already existing in the index file,
1143 * since we might be forcibly overwriting an existing
1144 * configuration with a new one (for example 'create -F'
1145 * in zonecfg).
1146 */
1147 opcode = PZE_ADD;
1148 cookie = setzoneent();
1149 while ((zn = getzoneent(cookie)) != NULL) {
1150 if (strcmp(zn, name) == 0) {
1151 opcode = PZE_MODIFY;
1152 free(zn);
1153 break;
1154 }
1155 free(zn);
1156 }
1157 endzoneent(cookie);
1158 ze.zone_state = ZONE_STATE_CONFIGURED;
1159 } else {
1160 opcode = PZE_MODIFY;
1161 }
1162
1163 if ((err = putzoneent(&ze, opcode)) != Z_OK)
1164 return (err);
1165
1166 return (Z_OK);
1167 }
1168
1169 /*
1170 * The goal of this routine is to cause the index file update and the
1171 * document save to happen as an atomic operation. We do the document
1172 * first, saving a backup copy using a hard link; if that succeeds, we go
1173 * on to the index. If that fails, we roll the document back into place.
1174 *
1175 * Strategy:
1176 *
1177 * New zone 'foo' configuration:
1178 * Create tmpfile (zonecfg.xxxxxx)
1179 * Write XML to tmpfile
1180 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
1181 * Add entry to index file
1182 * If it fails, delete foo.xml, leaving nothing behind.
1183 *
1184 * Save existing zone 'foo':
1185 * Make backup of foo.xml -> .backup
1186 * Create tmpfile (zonecfg.xxxxxx)
1187 * Write XML to tmpfile
1188 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml)
1189 * Modify index file as needed
1190 * If it fails, recover from .backup -> foo.xml
1191 *
1192 * Rename 'foo' to 'bar':
1193 * Create tmpfile (zonecfg.xxxxxx)
1194 * Write XML to tmpfile
1195 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml)
1196 * Add entry for 'bar' to index file, Remove entry for 'foo' (refresh)
1197 * If it fails, delete bar.xml; foo.xml is left behind.
1198 */
1199 static int
zonecfg_save_impl(zone_dochandle_t handle,char * filename)1200 zonecfg_save_impl(zone_dochandle_t handle, char *filename)
1201 {
1202 char tmpfile[MAXPATHLEN];
1203 char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN];
1204 int tmpfd, err, valid;
1205 xmlValidCtxt cvp = { NULL };
1206 boolean_t backup;
1207
1208 (void) strlcpy(tmpfile, filename, sizeof (tmpfile));
1209 (void) dirname(tmpfile);
1210 (void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile));
1211
1212 tmpfd = mkstemp(tmpfile);
1213 if (tmpfd == -1) {
1214 (void) unlink(tmpfile);
1215 return (Z_TEMP_FILE);
1216 }
1217 (void) close(tmpfd);
1218
1219 cvp.error = zonecfg_error_func;
1220 cvp.warning = zonecfg_error_func;
1221
1222 /*
1223 * We do a final validation of the document. Since the library has
1224 * malfunctioned if it fails to validate, we follow-up with an
1225 * assert() that the doc is valid.
1226 */
1227 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1228 assert(valid != 0);
1229
1230 if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0)
1231 goto err;
1232
1233 (void) chmod(tmpfile, 0644);
1234
1235 /*
1236 * In the event we are doing a standard save, hard link a copy of the
1237 * original file in .backup.<pid>.filename so we can restore it if
1238 * something goes wrong.
1239 */
1240 if (!is_new(handle) && !is_renaming(handle)) {
1241 backup = B_TRUE;
1242
1243 (void) strlcpy(bakdir, filename, sizeof (bakdir));
1244 (void) strlcpy(bakbase, filename, sizeof (bakbase));
1245 (void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s",
1246 dirname(bakdir), getpid(), basename(bakbase));
1247
1248 if (link(filename, bakfile) == -1) {
1249 err = errno;
1250 (void) unlink(tmpfile);
1251 if (errno == EACCES)
1252 return (Z_ACCES);
1253 return (Z_MISC_FS);
1254 }
1255 }
1256
1257 /*
1258 * Move the new document over top of the old.
1259 * i.e.: zonecfg.XXXXXX -> myzone.xml
1260 */
1261 if (rename(tmpfile, filename) == -1) {
1262 err = errno;
1263 (void) unlink(tmpfile);
1264 if (backup)
1265 (void) unlink(bakfile);
1266 if (err == EACCES)
1267 return (Z_ACCES);
1268 return (Z_MISC_FS);
1269 }
1270
1271 /*
1272 * If this is a snapshot, we're done-- don't add an index entry.
1273 */
1274 if (is_snapshot(handle))
1275 return (Z_OK);
1276
1277 /* now update the index file to reflect whatever we just did */
1278 if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) {
1279 if (backup) {
1280 /*
1281 * Try to restore from our backup.
1282 */
1283 (void) unlink(filename);
1284 (void) rename(bakfile, filename);
1285 } else {
1286 /*
1287 * Either the zone is new, in which case we can delete
1288 * new.xml, or we're doing a rename, so ditto.
1289 */
1290 assert(is_new(handle) || is_renaming(handle));
1291 (void) unlink(filename);
1292 }
1293 return (Z_UPDATING_INDEX);
1294 }
1295
1296 if (backup)
1297 (void) unlink(bakfile);
1298
1299 return (Z_OK);
1300
1301 err:
1302 (void) unlink(tmpfile);
1303 return (Z_SAVING_FILE);
1304 }
1305
1306 int
zonecfg_save(zone_dochandle_t handle)1307 zonecfg_save(zone_dochandle_t handle)
1308 {
1309 char zname[ZONENAME_MAX], path[MAXPATHLEN];
1310 char delpath[MAXPATHLEN];
1311 int err = Z_SAVING_FILE;
1312
1313 if (zonecfg_check_handle(handle) != Z_OK)
1314 return (Z_BAD_HANDLE);
1315
1316 /*
1317 * We don't support saving snapshots or a tree containing a sw
1318 * inventory at this time.
1319 */
1320 if (handle->zone_dh_snapshot || handle->zone_dh_sw_inv)
1321 return (Z_INVAL);
1322
1323 if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK)
1324 return (err);
1325
1326 if (!config_file_path(zname, path))
1327 return (Z_MISC_FS);
1328
1329 addcomment(handle, "\n DO NOT EDIT THIS "
1330 "FILE. Use zonecfg(1M) instead.\n");
1331
1332 /*
1333 * Update user_attr first so that it will be older
1334 * than the config file.
1335 */
1336 (void) zonecfg_authorize_users(handle, zname);
1337 err = zonecfg_save_impl(handle, path);
1338
1339 stripcomments(handle);
1340
1341 if (err != Z_OK)
1342 return (err);
1343
1344 handle->zone_dh_newzone = B_FALSE;
1345
1346 if (is_renaming(handle)) {
1347 if (config_file_path(handle->zone_dh_delete_name, delpath))
1348 (void) unlink(delpath);
1349 handle->zone_dh_delete_name[0] = '\0';
1350 }
1351
1352 return (Z_OK);
1353 }
1354
1355 int
zonecfg_verify_save(zone_dochandle_t handle,char * filename)1356 zonecfg_verify_save(zone_dochandle_t handle, char *filename)
1357 {
1358 int valid;
1359
1360 xmlValidCtxt cvp = { NULL };
1361
1362 if (zonecfg_check_handle(handle) != Z_OK)
1363 return (Z_BAD_HANDLE);
1364
1365 cvp.error = zonecfg_error_func;
1366 cvp.warning = zonecfg_error_func;
1367
1368 /*
1369 * We do a final validation of the document. Since the library has
1370 * malfunctioned if it fails to validate, we follow-up with an
1371 * assert() that the doc is valid.
1372 */
1373 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1374 assert(valid != 0);
1375
1376 if (xmlSaveFormatFile(filename, handle->zone_dh_doc, 1) <= 0)
1377 return (Z_SAVING_FILE);
1378
1379 return (Z_OK);
1380 }
1381
1382 int
zonecfg_detach_save(zone_dochandle_t handle,uint_t flags)1383 zonecfg_detach_save(zone_dochandle_t handle, uint_t flags)
1384 {
1385 char zname[ZONENAME_MAX];
1386 char path[MAXPATHLEN];
1387 char migpath[MAXPATHLEN];
1388 xmlValidCtxt cvp = { NULL };
1389 int err = Z_SAVING_FILE;
1390 int valid;
1391
1392 if (zonecfg_check_handle(handle) != Z_OK)
1393 return (Z_BAD_HANDLE);
1394
1395 if (flags & ZONE_DRY_RUN) {
1396 (void) strlcpy(migpath, "-", sizeof (migpath));
1397 } else {
1398 if ((err = zonecfg_get_name(handle, zname, sizeof (zname)))
1399 != Z_OK)
1400 return (err);
1401
1402 if ((err = zone_get_zonepath(zname, path, sizeof (path)))
1403 != Z_OK)
1404 return (err);
1405
1406 if (snprintf(migpath, sizeof (migpath), "%s/%s", path,
1407 ZONE_DETACHED) >= sizeof (migpath))
1408 return (Z_NOMEM);
1409 }
1410
1411 if ((err = operation_prep(handle)) != Z_OK)
1412 return (err);
1413
1414 addcomment(handle, "\n DO NOT EDIT THIS FILE. "
1415 "Use zonecfg(1M) and zoneadm(1M) attach.\n");
1416
1417 cvp.error = zonecfg_error_func;
1418 cvp.warning = zonecfg_error_func;
1419
1420 /*
1421 * We do a final validation of the document. Since the library has
1422 * malfunctioned if it fails to validate, we follow-up with an
1423 * assert() that the doc is valid.
1424 */
1425 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc);
1426 assert(valid != 0);
1427
1428 if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0)
1429 return (Z_SAVING_FILE);
1430
1431 if (!(flags & ZONE_DRY_RUN))
1432 (void) chmod(migpath, 0644);
1433
1434 stripcomments(handle);
1435
1436 handle->zone_dh_newzone = B_FALSE;
1437
1438 return (Z_OK);
1439 }
1440
1441 boolean_t
zonecfg_detached(const char * path)1442 zonecfg_detached(const char *path)
1443 {
1444 char migpath[MAXPATHLEN];
1445 struct stat buf;
1446
1447 if (snprintf(migpath, sizeof (migpath), "%s/%s", path, ZONE_DETACHED) >=
1448 sizeof (migpath))
1449 return (B_FALSE);
1450
1451 if (stat(migpath, &buf) != -1)
1452 return (B_TRUE);
1453
1454 return (B_FALSE);
1455 }
1456
1457 void
zonecfg_rm_detached(zone_dochandle_t handle,boolean_t forced)1458 zonecfg_rm_detached(zone_dochandle_t handle, boolean_t forced)
1459 {
1460 char zname[ZONENAME_MAX];
1461 char path[MAXPATHLEN];
1462 char detached[MAXPATHLEN];
1463 char attached[MAXPATHLEN];
1464
1465 if (zonecfg_check_handle(handle) != Z_OK)
1466 return;
1467
1468 if (zonecfg_get_name(handle, zname, sizeof (zname)) != Z_OK)
1469 return;
1470
1471 if (zone_get_zonepath(zname, path, sizeof (path)) != Z_OK)
1472 return;
1473
1474 (void) snprintf(detached, sizeof (detached), "%s/%s", path,
1475 ZONE_DETACHED);
1476 (void) snprintf(attached, sizeof (attached), "%s/%s", path,
1477 ATTACH_FORCED);
1478
1479 if (forced) {
1480 (void) rename(detached, attached);
1481 } else {
1482 (void) unlink(attached);
1483 (void) unlink(detached);
1484 }
1485 }
1486
1487 /*
1488 * Special case: if access(2) fails with ENOENT, then try again using
1489 * ZONE_CONFIG_ROOT instead of config_file_path(zonename). This is how we
1490 * work around the case of a config file which has not been created yet:
1491 * the user will need access to the directory so use that as a heuristic.
1492 */
1493
1494 int
zonecfg_access(const char * zonename,int amode)1495 zonecfg_access(const char *zonename, int amode)
1496 {
1497 char path[MAXPATHLEN];
1498
1499 if (!config_file_path(zonename, path))
1500 return (Z_INVAL);
1501 if (access(path, amode) == 0)
1502 return (Z_OK);
1503 if (errno == ENOENT) {
1504 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1505 ZONE_CONFIG_ROOT) >= sizeof (path))
1506 return (Z_INVAL);
1507 if (access(path, amode) == 0)
1508 return (Z_OK);
1509 }
1510 if (errno == EACCES)
1511 return (Z_ACCES);
1512 if (errno == EINVAL)
1513 return (Z_INVAL);
1514 return (Z_MISC_FS);
1515 }
1516
1517 int
zonecfg_create_snapshot(const char * zonename)1518 zonecfg_create_snapshot(const char *zonename)
1519 {
1520 zone_dochandle_t handle;
1521 char path[MAXPATHLEN], zonepath[MAXPATHLEN], rpath[MAXPATHLEN];
1522 int error = Z_OK, res;
1523
1524 if ((handle = zonecfg_init_handle()) == NULL) {
1525 return (Z_NOMEM);
1526 }
1527
1528 handle->zone_dh_newzone = B_TRUE;
1529 handle->zone_dh_snapshot = B_TRUE;
1530
1531 if ((error = zonecfg_get_handle(zonename, handle)) != Z_OK)
1532 goto out;
1533 if ((error = operation_prep(handle)) != Z_OK)
1534 goto out;
1535 error = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath));
1536 if (error != Z_OK)
1537 goto out;
1538 if ((res = resolvepath(zonepath, rpath, sizeof (rpath))) == -1) {
1539 error = Z_RESOLVED_PATH;
1540 goto out;
1541 }
1542 /*
1543 * If the resolved path is not the same as the original path, then
1544 * save the resolved path in the snapshot, thus preventing any
1545 * potential problems down the line when zoneadmd goes to unmount
1546 * file systems and depends on initial string matches with resolved
1547 * paths.
1548 */
1549 rpath[res] = '\0';
1550 if (strcmp(zonepath, rpath) != 0) {
1551 if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK)
1552 goto out;
1553 }
1554 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
1555 ZONE_SNAPSHOT_ROOT) >= sizeof (path)) {
1556 error = Z_MISC_FS;
1557 goto out;
1558 }
1559 if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) {
1560 error = Z_MISC_FS;
1561 goto out;
1562 }
1563
1564 if (!snap_file_path(zonename, path)) {
1565 error = Z_MISC_FS;
1566 goto out;
1567 }
1568
1569 addcomment(handle, "\n DO NOT EDIT THIS FILE. "
1570 "It is a snapshot of running zone state.\n");
1571
1572 error = zonecfg_save_impl(handle, path);
1573
1574 stripcomments(handle);
1575
1576 out:
1577 zonecfg_fini_handle(handle);
1578 return (error);
1579 }
1580
1581 int
zonecfg_get_iptype(zone_dochandle_t handle,zone_iptype_t * iptypep)1582 zonecfg_get_iptype(zone_dochandle_t handle, zone_iptype_t *iptypep)
1583 {
1584 char property[10]; /* 10 is big enough for "shared"/"exclusive" */
1585 int err;
1586
1587 err = getrootattr(handle, DTD_ATTR_IPTYPE, property, sizeof (property));
1588 if (err == Z_BAD_PROPERTY) {
1589 /* Return default value */
1590 *iptypep = ZS_SHARED;
1591 return (Z_OK);
1592 } else if (err != Z_OK) {
1593 return (err);
1594 }
1595
1596 if (strlen(property) == 0 ||
1597 strcmp(property, "shared") == 0)
1598 *iptypep = ZS_SHARED;
1599 else if (strcmp(property, "exclusive") == 0)
1600 *iptypep = ZS_EXCLUSIVE;
1601 else
1602 return (Z_INVAL);
1603
1604 return (Z_OK);
1605 }
1606
1607 int
zonecfg_set_iptype(zone_dochandle_t handle,zone_iptype_t iptype)1608 zonecfg_set_iptype(zone_dochandle_t handle, zone_iptype_t iptype)
1609 {
1610 xmlNodePtr cur;
1611
1612 if (handle == NULL)
1613 return (Z_INVAL);
1614
1615 cur = xmlDocGetRootElement(handle->zone_dh_doc);
1616 if (cur == NULL) {
1617 return (Z_EMPTY_DOCUMENT);
1618 }
1619
1620 if (xmlStrcmp(cur->name, DTD_ELEM_ZONE) != 0) {
1621 return (Z_WRONG_DOC_TYPE);
1622 }
1623 switch (iptype) {
1624 case ZS_SHARED:
1625 /*
1626 * Since "shared" is the default, we don't write it to the
1627 * configuration file, so that it's easier to migrate those
1628 * zones elsewhere, eg., to systems which are not IP-Instances
1629 * aware.
1630 * xmlUnsetProp only fails when the attribute doesn't exist,
1631 * which we don't care.
1632 */
1633 (void) xmlUnsetProp(cur, DTD_ATTR_IPTYPE);
1634 break;
1635 case ZS_EXCLUSIVE:
1636 if (xmlSetProp(cur, DTD_ATTR_IPTYPE,
1637 (const xmlChar *) "exclusive") == NULL)
1638 return (Z_INVAL);
1639 break;
1640 }
1641 return (Z_OK);
1642 }
1643
1644 static int
newprop(xmlNodePtr node,const xmlChar * attrname,char * src)1645 newprop(xmlNodePtr node, const xmlChar *attrname, char *src)
1646 {
1647 xmlAttrPtr newattr;
1648
1649 newattr = xmlNewProp(node, attrname, (xmlChar *)src);
1650 if (newattr == NULL) {
1651 xmlUnlinkNode(node);
1652 xmlFreeNode(node);
1653 return (Z_BAD_PROPERTY);
1654 }
1655 return (Z_OK);
1656 }
1657
1658 static int
zonecfg_add_filesystem_core(zone_dochandle_t handle,struct zone_fstab * tabptr)1659 zonecfg_add_filesystem_core(zone_dochandle_t handle, struct zone_fstab *tabptr)
1660 {
1661 xmlNodePtr newnode, cur = handle->zone_dh_cur, options_node;
1662 zone_fsopt_t *ptr;
1663 int err;
1664
1665 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_FS, NULL);
1666 if ((err = newprop(newnode, DTD_ATTR_SPECIAL,
1667 tabptr->zone_fs_special)) != Z_OK)
1668 return (err);
1669 if (tabptr->zone_fs_raw[0] != '\0' &&
1670 (err = newprop(newnode, DTD_ATTR_RAW, tabptr->zone_fs_raw)) != Z_OK)
1671 return (err);
1672 if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK)
1673 return (err);
1674 if ((err = newprop(newnode, DTD_ATTR_TYPE,
1675 tabptr->zone_fs_type)) != Z_OK)
1676 return (err);
1677 if (tabptr->zone_fs_options != NULL) {
1678 for (ptr = tabptr->zone_fs_options; ptr != NULL;
1679 ptr = ptr->zone_fsopt_next) {
1680 options_node = xmlNewTextChild(newnode, NULL,
1681 DTD_ELEM_FSOPTION, NULL);
1682 if ((err = newprop(options_node, DTD_ATTR_NAME,
1683 ptr->zone_fsopt_opt)) != Z_OK)
1684 return (err);
1685 }
1686 }
1687 return (Z_OK);
1688 }
1689
1690 int
zonecfg_add_filesystem(zone_dochandle_t handle,struct zone_fstab * tabptr)1691 zonecfg_add_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
1692 {
1693 int err;
1694
1695 if (tabptr == NULL)
1696 return (Z_INVAL);
1697
1698 if ((err = operation_prep(handle)) != Z_OK)
1699 return (err);
1700
1701 if ((err = zonecfg_add_filesystem_core(handle, tabptr)) != Z_OK)
1702 return (err);
1703
1704 return (Z_OK);
1705 }
1706
1707 int
zonecfg_add_fs_option(struct zone_fstab * tabptr,char * option)1708 zonecfg_add_fs_option(struct zone_fstab *tabptr, char *option)
1709 {
1710 zone_fsopt_t *last, *old, *new;
1711
1712 last = tabptr->zone_fs_options;
1713 for (old = last; old != NULL; old = old->zone_fsopt_next)
1714 last = old; /* walk to the end of the list */
1715 new = (zone_fsopt_t *)malloc(sizeof (zone_fsopt_t));
1716 if (new == NULL)
1717 return (Z_NOMEM);
1718 (void) strlcpy(new->zone_fsopt_opt, option,
1719 sizeof (new->zone_fsopt_opt));
1720 new->zone_fsopt_next = NULL;
1721 if (last == NULL)
1722 tabptr->zone_fs_options = new;
1723 else
1724 last->zone_fsopt_next = new;
1725 return (Z_OK);
1726 }
1727
1728 int
zonecfg_remove_fs_option(struct zone_fstab * tabptr,char * option)1729 zonecfg_remove_fs_option(struct zone_fstab *tabptr, char *option)
1730 {
1731 zone_fsopt_t *last, *this, *next;
1732
1733 last = tabptr->zone_fs_options;
1734 for (this = last; this != NULL; this = this->zone_fsopt_next) {
1735 if (strcmp(this->zone_fsopt_opt, option) == 0) {
1736 next = this->zone_fsopt_next;
1737 if (this == tabptr->zone_fs_options)
1738 tabptr->zone_fs_options = next;
1739 else
1740 last->zone_fsopt_next = next;
1741 free(this);
1742 return (Z_OK);
1743 } else
1744 last = this;
1745 }
1746 return (Z_NO_PROPERTY_ID);
1747 }
1748
1749 void
zonecfg_free_fs_option_list(zone_fsopt_t * list)1750 zonecfg_free_fs_option_list(zone_fsopt_t *list)
1751 {
1752 zone_fsopt_t *this, *next;
1753
1754 for (this = list; this != NULL; this = next) {
1755 next = this->zone_fsopt_next;
1756 free(this);
1757 }
1758 }
1759
1760 void
zonecfg_free_rctl_value_list(struct zone_rctlvaltab * valtab)1761 zonecfg_free_rctl_value_list(struct zone_rctlvaltab *valtab)
1762 {
1763 if (valtab == NULL)
1764 return;
1765 zonecfg_free_rctl_value_list(valtab->zone_rctlval_next);
1766 free(valtab);
1767 }
1768
1769 static boolean_t
match_prop(xmlNodePtr cur,const xmlChar * attr,char * user_prop)1770 match_prop(xmlNodePtr cur, const xmlChar *attr, char *user_prop)
1771 {
1772 xmlChar *gotten_prop;
1773 int prop_result;
1774
1775 gotten_prop = xmlGetProp(cur, attr);
1776 if (gotten_prop == NULL) /* shouldn't happen */
1777 return (B_FALSE);
1778 prop_result = xmlStrcmp(gotten_prop, (const xmlChar *) user_prop);
1779 xmlFree(gotten_prop);
1780 return ((prop_result == 0)); /* empty strings will match */
1781 }
1782
1783 static int
zonecfg_delete_filesystem_core(zone_dochandle_t handle,struct zone_fstab * tabptr)1784 zonecfg_delete_filesystem_core(zone_dochandle_t handle,
1785 struct zone_fstab *tabptr)
1786 {
1787 xmlNodePtr cur = handle->zone_dh_cur;
1788 boolean_t dir_match, spec_match, raw_match, type_match;
1789
1790 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1791 if (xmlStrcmp(cur->name, DTD_ELEM_FS))
1792 continue;
1793 dir_match = match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir);
1794 spec_match = match_prop(cur, DTD_ATTR_SPECIAL,
1795 tabptr->zone_fs_special);
1796 raw_match = match_prop(cur, DTD_ATTR_RAW,
1797 tabptr->zone_fs_raw);
1798 type_match = match_prop(cur, DTD_ATTR_TYPE,
1799 tabptr->zone_fs_type);
1800 if (dir_match && spec_match && raw_match && type_match) {
1801 xmlUnlinkNode(cur);
1802 xmlFreeNode(cur);
1803 return (Z_OK);
1804 }
1805 }
1806 return (Z_NO_RESOURCE_ID);
1807 }
1808
1809 int
zonecfg_delete_filesystem(zone_dochandle_t handle,struct zone_fstab * tabptr)1810 zonecfg_delete_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr)
1811 {
1812 int err;
1813
1814 if (tabptr == NULL)
1815 return (Z_INVAL);
1816
1817 if ((err = operation_prep(handle)) != Z_OK)
1818 return (err);
1819
1820 if ((err = zonecfg_delete_filesystem_core(handle, tabptr)) != Z_OK)
1821 return (err);
1822
1823 return (Z_OK);
1824 }
1825
1826 int
zonecfg_modify_filesystem(zone_dochandle_t handle,struct zone_fstab * oldtabptr,struct zone_fstab * newtabptr)1827 zonecfg_modify_filesystem(
1828 zone_dochandle_t handle,
1829 struct zone_fstab *oldtabptr,
1830 struct zone_fstab *newtabptr)
1831 {
1832 int err;
1833
1834 if (oldtabptr == NULL || newtabptr == NULL)
1835 return (Z_INVAL);
1836
1837 if ((err = operation_prep(handle)) != Z_OK)
1838 return (err);
1839
1840 if ((err = zonecfg_delete_filesystem_core(handle, oldtabptr)) != Z_OK)
1841 return (err);
1842
1843 if ((err = zonecfg_add_filesystem_core(handle, newtabptr)) != Z_OK)
1844 return (err);
1845
1846 return (Z_OK);
1847 }
1848
1849 int
zonecfg_lookup_filesystem(zone_dochandle_t handle,struct zone_fstab * tabptr)1850 zonecfg_lookup_filesystem(
1851 zone_dochandle_t handle,
1852 struct zone_fstab *tabptr)
1853 {
1854 xmlNodePtr cur, options, firstmatch;
1855 int err;
1856 char dirname[MAXPATHLEN], special[MAXPATHLEN], raw[MAXPATHLEN];
1857 char type[FSTYPSZ];
1858 char options_str[MAX_MNTOPT_STR];
1859
1860 if (tabptr == NULL)
1861 return (Z_INVAL);
1862
1863 if ((err = operation_prep(handle)) != Z_OK)
1864 return (err);
1865
1866 /*
1867 * Walk the list of children looking for matches on any properties
1868 * specified in the fstab parameter. If more than one resource
1869 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return
1870 * Z_NO_RESOURCE_ID.
1871 */
1872 cur = handle->zone_dh_cur;
1873 firstmatch = NULL;
1874 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
1875 if (xmlStrcmp(cur->name, DTD_ELEM_FS))
1876 continue;
1877 if (strlen(tabptr->zone_fs_dir) > 0) {
1878 if ((fetchprop(cur, DTD_ATTR_DIR, dirname,
1879 sizeof (dirname)) == Z_OK) &&
1880 (strcmp(tabptr->zone_fs_dir, dirname) == 0)) {
1881 if (firstmatch == NULL)
1882 firstmatch = cur;
1883 else
1884 return (Z_INSUFFICIENT_SPEC);
1885 }
1886 }
1887 if (strlen(tabptr->zone_fs_special) > 0) {
1888 if ((fetchprop(cur, DTD_ATTR_SPECIAL, special,
1889 sizeof (special)) == Z_OK)) {
1890 if (strcmp(tabptr->zone_fs_special,
1891 special) == 0) {
1892 if (firstmatch == NULL)
1893 firstmatch = cur;
1894 else if (firstmatch != cur)
1895 return (Z_INSUFFICIENT_SPEC);
1896 } else {
1897 /*
1898 * If another property matched but this
1899 * one doesn't then reset firstmatch.
1900 */
1901 if (firstmatch == cur)
1902 firstmatch = NULL;
1903 }
1904 }
1905 }
1906 if (strlen(tabptr->zone_fs_raw) > 0) {
1907 if ((fetchprop(cur, DTD_ATTR_RAW, raw,
1908 sizeof (raw)) == Z_OK)) {
1909 if (strcmp(tabptr->zone_fs_raw, raw) == 0) {
1910 if (firstmatch == NULL)
1911 firstmatch = cur;
1912 else if (firstmatch != cur)
1913 return (Z_INSUFFICIENT_SPEC);
1914 } else {
1915 /*
1916 * If another property matched but this
1917 * one doesn't then reset firstmatch.
1918 */
1919 if (firstmatch == cur)
1920 firstmatch = NULL;
1921 }
1922 }
1923 }
1924 if (strlen(tabptr->zone_fs_type) > 0) {
1925 if ((fetchprop(cur, DTD_ATTR_TYPE, type,
1926 sizeof (type)) == Z_OK)) {
1927 if (strcmp(tabptr->zone_fs_type, type) == 0) {
1928 if (firstmatch == NULL)
1929 firstmatch = cur;
1930 else if (firstmatch != cur)
1931 return (Z_INSUFFICIENT_SPEC);
1932 } else {
1933 /*
1934 * If another property matched but this
1935 * one doesn't then reset firstmatch.
1936 */
1937 if (firstmatch == cur)
1938 firstmatch = NULL;
1939 }
1940 }
1941 }
1942 }
1943
1944 if (firstmatch == NULL)
1945 return (Z_NO_RESOURCE_ID);
1946
1947 cur = firstmatch;
1948
1949 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir,
1950 sizeof (tabptr->zone_fs_dir))) != Z_OK)
1951 return (err);
1952
1953 if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special,
1954 sizeof (tabptr->zone_fs_special))) != Z_OK)
1955 return (err);
1956
1957 if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw,
1958 sizeof (tabptr->zone_fs_raw))) != Z_OK)
1959 return (err);
1960
1961 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type,
1962 sizeof (tabptr->zone_fs_type))) != Z_OK)
1963 return (err);
1964
1965 /* options are optional */
1966 tabptr->zone_fs_options = NULL;
1967 for (options = cur->xmlChildrenNode; options != NULL;
1968 options = options->next) {
1969 if ((fetchprop(options, DTD_ATTR_NAME, options_str,
1970 sizeof (options_str)) != Z_OK))
1971 break;
1972 if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK)
1973 break;
1974 }
1975 return (Z_OK);
1976 }
1977
1978 /*
1979 * Compare two IP addresses in string form. Allow for the possibility that
1980 * one might have "/<prefix-length>" at the end: allow a match on just the
1981 * IP address (or host name) part.
1982 */
1983
1984 boolean_t
zonecfg_same_net_address(char * a1,char * a2)1985 zonecfg_same_net_address(char *a1, char *a2)
1986 {
1987 char *slashp, *slashp1, *slashp2;
1988 int result;
1989
1990 if (strcmp(a1, a2) == 0)
1991 return (B_TRUE);
1992
1993 /*
1994 * If neither has a slash or both do, they need to match to be
1995 * considered the same, but they did not match above, so fail.
1996 */
1997 slashp1 = strchr(a1, '/');
1998 slashp2 = strchr(a2, '/');
1999 if ((slashp1 == NULL && slashp2 == NULL) ||
2000 (slashp1 != NULL && slashp2 != NULL))
2001 return (B_FALSE);
2002
2003 /*
2004 * Only one had a slash: pick that one, zero out the slash, compare
2005 * the "address only" strings, restore the slash, and return the
2006 * result of the comparison.
2007 */
2008 slashp = (slashp1 == NULL) ? slashp2 : slashp1;
2009 *slashp = '\0';
2010 result = strcmp(a1, a2);
2011 *slashp = '/';
2012 return ((result == 0));
2013 }
2014
2015 int
zonecfg_valid_net_address(char * address,struct lifreq * lifr)2016 zonecfg_valid_net_address(char *address, struct lifreq *lifr)
2017 {
2018 struct sockaddr_in *sin4;
2019 struct sockaddr_in6 *sin6;
2020 struct addrinfo hints, *result;
2021 char *slashp = strchr(address, '/');
2022
2023 bzero(lifr, sizeof (struct lifreq));
2024 sin4 = (struct sockaddr_in *)&lifr->lifr_addr;
2025 sin6 = (struct sockaddr_in6 *)&lifr->lifr_addr;
2026 if (slashp != NULL)
2027 *slashp = '\0';
2028 if (inet_pton(AF_INET, address, &sin4->sin_addr) == 1) {
2029 sin4->sin_family = AF_INET;
2030 } else if (inet_pton(AF_INET6, address, &sin6->sin6_addr) == 1) {
2031 if (slashp == NULL)
2032 return (Z_IPV6_ADDR_PREFIX_LEN);
2033 sin6->sin6_family = AF_INET6;
2034 } else {
2035 /* "address" may be a host name */
2036 (void) memset(&hints, 0, sizeof (hints));
2037 hints.ai_family = PF_INET;
2038 if (getaddrinfo(address, NULL, &hints, &result) != 0)
2039 return (Z_BOGUS_ADDRESS);
2040 sin4->sin_family = result->ai_family;
2041
2042 (void) memcpy(&sin4->sin_addr,
2043 /* LINTED E_BAD_PTR_CAST_ALIGN */
2044 &((struct sockaddr_in *)result->ai_addr)->sin_addr,
2045 sizeof (struct in_addr));
2046
2047 freeaddrinfo(result);
2048 }
2049 return (Z_OK);
2050 }
2051
2052 boolean_t
zonecfg_ifname_exists(sa_family_t af,char * ifname)2053 zonecfg_ifname_exists(sa_family_t af, char *ifname)
2054 {
2055 struct lifreq lifr;
2056 int so;
2057 int save_errno;
2058
2059 (void) memset(&lifr, 0, sizeof (lifr));
2060 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
2061 lifr.lifr_addr.ss_family = af;
2062 if ((so = socket(af, SOCK_DGRAM, 0)) < 0) {
2063 /* Odd - can't tell if the ifname exists */
2064 return (B_FALSE);
2065 }
2066 if (ioctl(so, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
2067 save_errno = errno;
2068 (void) close(so);
2069 errno = save_errno;
2070 return (B_FALSE);
2071 }
2072 (void) close(so);
2073 return (B_TRUE);
2074 }
2075
2076 /*
2077 * Determines whether there is a net resource with the physical interface, IP
2078 * address, and default router specified by 'tabptr' in the zone configuration
2079 * to which 'handle' refers. 'tabptr' must have an interface, an address, a
2080 * default router, or a combination of the three. This function returns Z_OK
2081 * iff there is exactly one net resource matching the query specified by
2082 * 'tabptr'. The function returns Z_INSUFFICIENT_SPEC if there are multiple
2083 * matches or 'tabptr' does not specify a physical interface, address, or
2084 * default router. The function returns Z_NO_RESOURCE_ID if are no matches.
2085 *
2086 * Errors might also be returned if the entry that exactly matches the
2087 * query lacks critical network resource information.
2088 *
2089 * If there is a single match, then the matching entry's physical interface, IP
2090 * address, and default router information are stored in 'tabptr'.
2091 */
2092 int
zonecfg_lookup_nwif(zone_dochandle_t handle,struct zone_nwiftab * tabptr)2093 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2094 {
2095 xmlNodePtr cur;
2096 xmlNodePtr firstmatch;
2097 int err;
2098 char address[INET6_ADDRSTRLEN];
2099 char physical[LIFNAMSIZ];
2100 size_t addrspec; /* nonzero if tabptr has IP addr */
2101 size_t physspec; /* nonzero if tabptr has interface */
2102 size_t defrouterspec; /* nonzero if tabptr has def. router */
2103 size_t allowed_addrspec;
2104 zone_iptype_t iptype;
2105
2106 if (tabptr == NULL)
2107 return (Z_INVAL);
2108
2109 /*
2110 * Determine the fields that will be searched. There must be at least
2111 * one.
2112 *
2113 * zone_nwif_address, zone_nwif_physical, and zone_nwif_defrouter are
2114 * arrays, so no NULL checks are necessary.
2115 */
2116 addrspec = strlen(tabptr->zone_nwif_address);
2117 physspec = strlen(tabptr->zone_nwif_physical);
2118 defrouterspec = strlen(tabptr->zone_nwif_defrouter);
2119 allowed_addrspec = strlen(tabptr->zone_nwif_allowed_address);
2120 if (addrspec != 0 && allowed_addrspec != 0)
2121 return (Z_INVAL); /* can't specify both */
2122 if (addrspec == 0 && physspec == 0 && defrouterspec == 0 &&
2123 allowed_addrspec == 0)
2124 return (Z_INSUFFICIENT_SPEC);
2125
2126 if ((err = operation_prep(handle)) != Z_OK)
2127 return (err);
2128
2129 if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK)
2130 return (err);
2131 /*
2132 * Iterate over the configuration's elements and look for net elements
2133 * that match the query.
2134 */
2135 firstmatch = NULL;
2136 cur = handle->zone_dh_cur;
2137 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2138 /* Skip non-net elements */
2139 if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2140 continue;
2141
2142 /*
2143 * If any relevant fields don't match the query, then skip
2144 * the current net element.
2145 */
2146 if (physspec != 0 && (fetchprop(cur, DTD_ATTR_PHYSICAL,
2147 physical, sizeof (physical)) != Z_OK ||
2148 strcmp(tabptr->zone_nwif_physical, physical) != 0))
2149 continue;
2150 if (iptype == ZS_SHARED && addrspec != 0 &&
2151 (fetchprop(cur, DTD_ATTR_ADDRESS, address,
2152 sizeof (address)) != Z_OK ||
2153 !zonecfg_same_net_address(tabptr->zone_nwif_address,
2154 address)))
2155 continue;
2156 if (iptype == ZS_EXCLUSIVE && allowed_addrspec != 0 &&
2157 (fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS, address,
2158 sizeof (address)) != Z_OK ||
2159 !zonecfg_same_net_address(tabptr->zone_nwif_allowed_address,
2160 address)))
2161 continue;
2162 if (defrouterspec != 0 && (fetchprop(cur, DTD_ATTR_DEFROUTER,
2163 address, sizeof (address)) != Z_OK ||
2164 !zonecfg_same_net_address(tabptr->zone_nwif_defrouter,
2165 address)))
2166 continue;
2167
2168 /*
2169 * The current net element matches the query. Select it if
2170 * it's the first match; otherwise, abort the search.
2171 */
2172 if (firstmatch == NULL)
2173 firstmatch = cur;
2174 else
2175 return (Z_INSUFFICIENT_SPEC);
2176 }
2177 if (firstmatch == NULL)
2178 return (Z_NO_RESOURCE_ID);
2179
2180 cur = firstmatch;
2181
2182 if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical,
2183 sizeof (tabptr->zone_nwif_physical))) != Z_OK)
2184 return (err);
2185
2186 if (iptype == ZS_SHARED &&
2187 (err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address,
2188 sizeof (tabptr->zone_nwif_address))) != Z_OK)
2189 return (err);
2190
2191 if (iptype == ZS_EXCLUSIVE &&
2192 (err = fetchprop(cur, DTD_ATTR_ALLOWED_ADDRESS,
2193 tabptr->zone_nwif_allowed_address,
2194 sizeof (tabptr->zone_nwif_allowed_address))) != Z_OK)
2195 return (err);
2196
2197 if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER,
2198 tabptr->zone_nwif_defrouter,
2199 sizeof (tabptr->zone_nwif_defrouter))) != Z_OK)
2200 return (err);
2201
2202 return (Z_OK);
2203 }
2204
2205 static int
zonecfg_add_nwif_core(zone_dochandle_t handle,struct zone_nwiftab * tabptr)2206 zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2207 {
2208 xmlNodePtr newnode, cur = handle->zone_dh_cur;
2209 int err;
2210
2211 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL);
2212 if (strlen(tabptr->zone_nwif_address) > 0 &&
2213 (err = newprop(newnode, DTD_ATTR_ADDRESS,
2214 tabptr->zone_nwif_address)) != Z_OK)
2215 return (err);
2216 if (strlen(tabptr->zone_nwif_allowed_address) > 0 &&
2217 (err = newprop(newnode, DTD_ATTR_ALLOWED_ADDRESS,
2218 tabptr->zone_nwif_allowed_address)) != Z_OK)
2219 return (err);
2220 if ((err = newprop(newnode, DTD_ATTR_PHYSICAL,
2221 tabptr->zone_nwif_physical)) != Z_OK)
2222 return (err);
2223 /*
2224 * Do not add this property when it is not set, for backwards
2225 * compatibility and because it is optional.
2226 */
2227 if ((strlen(tabptr->zone_nwif_defrouter) > 0) &&
2228 ((err = newprop(newnode, DTD_ATTR_DEFROUTER,
2229 tabptr->zone_nwif_defrouter)) != Z_OK))
2230 return (err);
2231 return (Z_OK);
2232 }
2233
2234 int
zonecfg_add_nwif(zone_dochandle_t handle,struct zone_nwiftab * tabptr)2235 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2236 {
2237 int err;
2238
2239 if (tabptr == NULL)
2240 return (Z_INVAL);
2241
2242 if ((err = operation_prep(handle)) != Z_OK)
2243 return (err);
2244
2245 if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK)
2246 return (err);
2247
2248 return (Z_OK);
2249 }
2250
2251 static int
zonecfg_delete_nwif_core(zone_dochandle_t handle,struct zone_nwiftab * tabptr)2252 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2253 {
2254 xmlNodePtr cur = handle->zone_dh_cur;
2255 boolean_t addr_match, phys_match, allowed_addr_match;
2256
2257 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2258 if (xmlStrcmp(cur->name, DTD_ELEM_NET))
2259 continue;
2260
2261 addr_match = match_prop(cur, DTD_ATTR_ADDRESS,
2262 tabptr->zone_nwif_address);
2263 allowed_addr_match = match_prop(cur, DTD_ATTR_ALLOWED_ADDRESS,
2264 tabptr->zone_nwif_allowed_address);
2265 phys_match = match_prop(cur, DTD_ATTR_PHYSICAL,
2266 tabptr->zone_nwif_physical);
2267
2268 if (addr_match && allowed_addr_match && phys_match) {
2269 xmlUnlinkNode(cur);
2270 xmlFreeNode(cur);
2271 return (Z_OK);
2272 }
2273 }
2274 return (Z_NO_RESOURCE_ID);
2275 }
2276
2277 int
zonecfg_delete_nwif(zone_dochandle_t handle,struct zone_nwiftab * tabptr)2278 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr)
2279 {
2280 int err;
2281
2282 if (tabptr == NULL)
2283 return (Z_INVAL);
2284
2285 if ((err = operation_prep(handle)) != Z_OK)
2286 return (err);
2287
2288 if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK)
2289 return (err);
2290
2291 return (Z_OK);
2292 }
2293
2294 int
zonecfg_modify_nwif(zone_dochandle_t handle,struct zone_nwiftab * oldtabptr,struct zone_nwiftab * newtabptr)2295 zonecfg_modify_nwif(
2296 zone_dochandle_t handle,
2297 struct zone_nwiftab *oldtabptr,
2298 struct zone_nwiftab *newtabptr)
2299 {
2300 int err;
2301
2302 if (oldtabptr == NULL || newtabptr == NULL)
2303 return (Z_INVAL);
2304
2305 if ((err = operation_prep(handle)) != Z_OK)
2306 return (err);
2307
2308 if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK)
2309 return (err);
2310
2311 if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK)
2312 return (err);
2313
2314 return (Z_OK);
2315 }
2316
2317 /*
2318 * Must be a comma-separated list of alpha-numeric file system names.
2319 */
2320 static int
zonecfg_valid_fs_allowed(const char * fsallowedp)2321 zonecfg_valid_fs_allowed(const char *fsallowedp)
2322 {
2323 char tmp[ZONE_FS_ALLOWED_MAX];
2324 char *cp = tmp;
2325 char *p;
2326
2327 if (strlen(fsallowedp) > ZONE_FS_ALLOWED_MAX)
2328 return (Z_TOO_BIG);
2329
2330 (void) strlcpy(tmp, fsallowedp, sizeof (tmp));
2331
2332 while (*cp != '\0') {
2333 p = cp;
2334 while (*p != '\0' && *p != ',') {
2335 if (!isalnum(*p) && *p != '-')
2336 return (Z_INVALID_PROPERTY);
2337 p++;
2338 }
2339
2340 if (*p == ',') {
2341 if (p == cp)
2342 return (Z_INVALID_PROPERTY);
2343
2344 p++;
2345
2346 if (*p == '\0')
2347 return (Z_INVALID_PROPERTY);
2348 }
2349
2350 cp = p;
2351 }
2352
2353 return (Z_OK);
2354 }
2355
2356 int
zonecfg_get_fs_allowed(zone_dochandle_t handle,char * bufp,size_t buflen)2357 zonecfg_get_fs_allowed(zone_dochandle_t handle, char *bufp, size_t buflen)
2358 {
2359 int err;
2360
2361 if ((err = getrootattr(handle, DTD_ATTR_FS_ALLOWED,
2362 bufp, buflen)) != Z_OK)
2363 return (err);
2364 if (bufp[0] == '\0')
2365 return (Z_BAD_PROPERTY);
2366 return (zonecfg_valid_fs_allowed(bufp));
2367 }
2368
2369 int
zonecfg_set_fs_allowed(zone_dochandle_t handle,const char * bufp)2370 zonecfg_set_fs_allowed(zone_dochandle_t handle, const char *bufp)
2371 {
2372 int err;
2373
2374 if (bufp == NULL || (err = zonecfg_valid_fs_allowed(bufp)) == Z_OK)
2375 return (setrootattr(handle, DTD_ATTR_FS_ALLOWED, bufp));
2376 return (err);
2377 }
2378
2379 /*
2380 * Determines if the specified string is a valid hostid string. This function
2381 * returns Z_OK if the string is a valid hostid string. It returns Z_INVAL if
2382 * 'hostidp' is NULL, Z_TOO_BIG if 'hostidp' refers to a string buffer
2383 * containing a hex string with more than 8 digits, and Z_INVALID_PROPERTY if
2384 * the string has an invalid format.
2385 */
2386 static int
zonecfg_valid_hostid(const char * hostidp)2387 zonecfg_valid_hostid(const char *hostidp)
2388 {
2389 char *currentp;
2390 u_longlong_t hostidval;
2391 size_t len;
2392
2393 if (hostidp == NULL)
2394 return (Z_INVAL);
2395
2396 /* Empty strings and strings with whitespace are invalid. */
2397 if (*hostidp == '\0')
2398 return (Z_INVALID_PROPERTY);
2399 for (currentp = (char *)hostidp; *currentp != '\0'; ++currentp) {
2400 if (isspace(*currentp))
2401 return (Z_INVALID_PROPERTY);
2402 }
2403 len = (size_t)(currentp - hostidp);
2404
2405 /*
2406 * The caller might pass a hostid that is larger than the maximum
2407 * unsigned 32-bit integral value. Check for this! Also, make sure
2408 * that the whole string is converted (this helps us find illegal
2409 * characters) and that the whole string fits within a buffer of size
2410 * HW_HOSTID_LEN.
2411 */
2412 currentp = (char *)hostidp;
2413 if (strncmp(hostidp, "0x", 2) == 0 || strncmp(hostidp, "0X", 2) == 0)
2414 currentp += 2;
2415 hostidval = strtoull(currentp, ¤tp, 16);
2416 if ((size_t)(currentp - hostidp) >= HW_HOSTID_LEN)
2417 return (Z_TOO_BIG);
2418 if (hostidval > UINT_MAX || hostidval == HW_INVALID_HOSTID ||
2419 currentp != hostidp + len)
2420 return (Z_INVALID_PROPERTY);
2421 return (Z_OK);
2422 }
2423
2424 /*
2425 * Gets the zone hostid string stored in the specified zone configuration
2426 * document. This function returns Z_OK on success. Z_BAD_PROPERTY is returned
2427 * if the config file doesn't specify a hostid or if the hostid is blank.
2428 *
2429 * Note that buflen should be at least HW_HOSTID_LEN.
2430 */
2431 int
zonecfg_get_hostid(zone_dochandle_t handle,char * bufp,size_t buflen)2432 zonecfg_get_hostid(zone_dochandle_t handle, char *bufp, size_t buflen)
2433 {
2434 int err;
2435
2436 if ((err = getrootattr(handle, DTD_ATTR_HOSTID, bufp, buflen)) != Z_OK)
2437 return (err);
2438 if (bufp[0] == '\0')
2439 return (Z_BAD_PROPERTY);
2440 return (zonecfg_valid_hostid(bufp));
2441 }
2442
2443 /*
2444 * Sets the hostid string in the specified zone config document to the given
2445 * string value. If 'hostidp' is NULL, then the config document's hostid
2446 * attribute is cleared. Non-NULL hostids are validated. This function returns
2447 * Z_OK on success. Any other return value indicates failure.
2448 */
2449 int
zonecfg_set_hostid(zone_dochandle_t handle,const char * hostidp)2450 zonecfg_set_hostid(zone_dochandle_t handle, const char *hostidp)
2451 {
2452 int err;
2453
2454 /*
2455 * A NULL hostid string is interpreted as a request to clear the
2456 * hostid.
2457 */
2458 if (hostidp == NULL || (err = zonecfg_valid_hostid(hostidp)) == Z_OK)
2459 return (setrootattr(handle, DTD_ATTR_HOSTID, hostidp));
2460 return (err);
2461 }
2462
2463 int
zonecfg_lookup_dev(zone_dochandle_t handle,struct zone_devtab * tabptr)2464 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2465 {
2466 xmlNodePtr cur, firstmatch;
2467 int err;
2468 char match[MAXPATHLEN];
2469
2470 if (tabptr == NULL)
2471 return (Z_INVAL);
2472
2473 if ((err = operation_prep(handle)) != Z_OK)
2474 return (err);
2475
2476 cur = handle->zone_dh_cur;
2477 firstmatch = NULL;
2478 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2479 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2480 continue;
2481 if (strlen(tabptr->zone_dev_match) == 0)
2482 continue;
2483
2484 if ((fetchprop(cur, DTD_ATTR_MATCH, match,
2485 sizeof (match)) == Z_OK)) {
2486 if (strcmp(tabptr->zone_dev_match,
2487 match) == 0) {
2488 if (firstmatch == NULL)
2489 firstmatch = cur;
2490 else if (firstmatch != cur)
2491 return (Z_INSUFFICIENT_SPEC);
2492 } else {
2493 /*
2494 * If another property matched but this
2495 * one doesn't then reset firstmatch.
2496 */
2497 if (firstmatch == cur)
2498 firstmatch = NULL;
2499 }
2500 }
2501 }
2502 if (firstmatch == NULL)
2503 return (Z_NO_RESOURCE_ID);
2504
2505 cur = firstmatch;
2506
2507 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match,
2508 sizeof (tabptr->zone_dev_match))) != Z_OK)
2509 return (err);
2510
2511 return (Z_OK);
2512 }
2513
2514 static int
zonecfg_add_dev_core(zone_dochandle_t handle,struct zone_devtab * tabptr)2515 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
2516 {
2517 xmlNodePtr newnode, cur = handle->zone_dh_cur;
2518 int err;
2519
2520 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL);
2521
2522 if ((err = newprop(newnode, DTD_ATTR_MATCH,
2523 tabptr->zone_dev_match)) != Z_OK)
2524 return (err);
2525
2526 return (Z_OK);
2527 }
2528
2529 int
zonecfg_add_dev(zone_dochandle_t handle,struct zone_devtab * tabptr)2530 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2531 {
2532 int err;
2533
2534 if (tabptr == NULL)
2535 return (Z_INVAL);
2536
2537 if ((err = operation_prep(handle)) != Z_OK)
2538 return (err);
2539
2540 if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK)
2541 return (err);
2542
2543 return (Z_OK);
2544 }
2545
2546 static int
zonecfg_delete_dev_core(zone_dochandle_t handle,struct zone_devtab * tabptr)2547 zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr)
2548 {
2549 xmlNodePtr cur = handle->zone_dh_cur;
2550 int match_match;
2551
2552 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2553 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE))
2554 continue;
2555
2556 match_match = match_prop(cur, DTD_ATTR_MATCH,
2557 tabptr->zone_dev_match);
2558
2559 if (match_match) {
2560 xmlUnlinkNode(cur);
2561 xmlFreeNode(cur);
2562 return (Z_OK);
2563 }
2564 }
2565 return (Z_NO_RESOURCE_ID);
2566 }
2567
2568 int
zonecfg_delete_dev(zone_dochandle_t handle,struct zone_devtab * tabptr)2569 zonecfg_delete_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
2570 {
2571 int err;
2572
2573 if (tabptr == NULL)
2574 return (Z_INVAL);
2575
2576 if ((err = operation_prep(handle)) != Z_OK)
2577 return (err);
2578
2579 if ((err = zonecfg_delete_dev_core(handle, tabptr)) != Z_OK)
2580 return (err);
2581
2582 return (Z_OK);
2583 }
2584
2585 int
zonecfg_modify_dev(zone_dochandle_t handle,struct zone_devtab * oldtabptr,struct zone_devtab * newtabptr)2586 zonecfg_modify_dev(
2587 zone_dochandle_t handle,
2588 struct zone_devtab *oldtabptr,
2589 struct zone_devtab *newtabptr)
2590 {
2591 int err;
2592
2593 if (oldtabptr == NULL || newtabptr == NULL)
2594 return (Z_INVAL);
2595
2596 if ((err = operation_prep(handle)) != Z_OK)
2597 return (err);
2598
2599 if ((err = zonecfg_delete_dev_core(handle, oldtabptr)) != Z_OK)
2600 return (err);
2601
2602 if ((err = zonecfg_add_dev_core(handle, newtabptr)) != Z_OK)
2603 return (err);
2604
2605 return (Z_OK);
2606 }
2607
2608 static int
zonecfg_add_auth_core(zone_dochandle_t handle,struct zone_admintab * tabptr,char * zonename)2609 zonecfg_add_auth_core(zone_dochandle_t handle, struct zone_admintab *tabptr,
2610 char *zonename)
2611 {
2612 xmlNodePtr newnode, cur = handle->zone_dh_cur;
2613 int err;
2614
2615 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ADMIN, NULL);
2616 err = newprop(newnode, DTD_ATTR_USER, tabptr->zone_admin_user);
2617 if (err != Z_OK)
2618 return (err);
2619 err = newprop(newnode, DTD_ATTR_AUTHS, tabptr->zone_admin_auths);
2620 if (err != Z_OK)
2621 return (err);
2622 if ((err = zonecfg_remove_userauths(
2623 handle, tabptr->zone_admin_user, zonename, B_FALSE)) != Z_OK)
2624 return (err);
2625 return (Z_OK);
2626 }
2627
2628 int
zonecfg_add_admin(zone_dochandle_t handle,struct zone_admintab * tabptr,char * zonename)2629 zonecfg_add_admin(zone_dochandle_t handle, struct zone_admintab *tabptr,
2630 char *zonename)
2631 {
2632 int err;
2633
2634 if (tabptr == NULL)
2635 return (Z_INVAL);
2636
2637 if ((err = operation_prep(handle)) != Z_OK)
2638 return (err);
2639
2640 if ((err = zonecfg_add_auth_core(handle, tabptr,
2641 zonename)) != Z_OK)
2642 return (err);
2643
2644 return (Z_OK);
2645 }
2646
2647 static int
zonecfg_delete_auth_core(zone_dochandle_t handle,struct zone_admintab * tabptr,char * zonename)2648 zonecfg_delete_auth_core(zone_dochandle_t handle, struct zone_admintab *tabptr,
2649 char *zonename)
2650 {
2651 xmlNodePtr cur = handle->zone_dh_cur;
2652 boolean_t auth_match;
2653 int err;
2654
2655 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2656 if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
2657 continue;
2658 auth_match = match_prop(cur, DTD_ATTR_USER,
2659 tabptr->zone_admin_user);
2660 if (auth_match) {
2661 if ((err = zonecfg_insert_userauths(
2662 handle, tabptr->zone_admin_user,
2663 zonename)) != Z_OK)
2664 return (err);
2665 xmlUnlinkNode(cur);
2666 xmlFreeNode(cur);
2667 return (Z_OK);
2668 }
2669 }
2670 return (Z_NO_RESOURCE_ID);
2671 }
2672
2673 int
zonecfg_delete_admin(zone_dochandle_t handle,struct zone_admintab * tabptr,char * zonename)2674 zonecfg_delete_admin(zone_dochandle_t handle, struct zone_admintab *tabptr,
2675 char *zonename)
2676 {
2677 int err;
2678
2679 if (tabptr == NULL)
2680 return (Z_INVAL);
2681
2682 if ((err = operation_prep(handle)) != Z_OK)
2683 return (err);
2684
2685 if ((err = zonecfg_delete_auth_core(handle, tabptr, zonename)) != Z_OK)
2686 return (err);
2687
2688 return (Z_OK);
2689 }
2690
2691 int
zonecfg_modify_admin(zone_dochandle_t handle,struct zone_admintab * oldtabptr,struct zone_admintab * newtabptr,char * zonename)2692 zonecfg_modify_admin(zone_dochandle_t handle, struct zone_admintab *oldtabptr,
2693 struct zone_admintab *newtabptr, char *zonename)
2694 {
2695 int err;
2696
2697 if (oldtabptr == NULL || newtabptr == NULL)
2698 return (Z_INVAL);
2699
2700 if ((err = operation_prep(handle)) != Z_OK)
2701 return (err);
2702
2703 if ((err = zonecfg_delete_auth_core(handle, oldtabptr, zonename))
2704 != Z_OK)
2705 return (err);
2706
2707 if ((err = zonecfg_add_auth_core(handle, newtabptr,
2708 zonename)) != Z_OK)
2709 return (err);
2710
2711 return (Z_OK);
2712 }
2713
2714 int
zonecfg_lookup_admin(zone_dochandle_t handle,struct zone_admintab * tabptr)2715 zonecfg_lookup_admin(zone_dochandle_t handle, struct zone_admintab *tabptr)
2716 {
2717 xmlNodePtr cur, firstmatch;
2718 int err;
2719 char user[MAXUSERNAME];
2720
2721 if (tabptr == NULL)
2722 return (Z_INVAL);
2723
2724 if ((err = operation_prep(handle)) != Z_OK)
2725 return (err);
2726
2727 cur = handle->zone_dh_cur;
2728 firstmatch = NULL;
2729 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2730 if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN))
2731 continue;
2732 if (strlen(tabptr->zone_admin_user) > 0) {
2733 if ((fetchprop(cur, DTD_ATTR_USER, user,
2734 sizeof (user)) == Z_OK) &&
2735 (strcmp(tabptr->zone_admin_user, user) == 0)) {
2736 if (firstmatch == NULL)
2737 firstmatch = cur;
2738 else
2739 return (Z_INSUFFICIENT_SPEC);
2740 }
2741 }
2742 }
2743 if (firstmatch == NULL)
2744 return (Z_NO_RESOURCE_ID);
2745
2746 cur = firstmatch;
2747
2748 if ((err = fetchprop(cur, DTD_ATTR_USER, tabptr->zone_admin_user,
2749 sizeof (tabptr->zone_admin_user))) != Z_OK)
2750 return (err);
2751
2752 if ((err = fetchprop(cur, DTD_ATTR_AUTHS, tabptr->zone_admin_auths,
2753 sizeof (tabptr->zone_admin_auths))) != Z_OK)
2754 return (err);
2755
2756 return (Z_OK);
2757 }
2758
2759 static int
zonecfg_add_secflags_core(zone_dochandle_t handle,struct zone_secflagstab * tabptr)2760 zonecfg_add_secflags_core(zone_dochandle_t handle,
2761 struct zone_secflagstab *tabptr)
2762 {
2763 xmlNodePtr newnode, cur = handle->zone_dh_cur;
2764 int err;
2765
2766 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_SECFLAGS, NULL);
2767 err = newprop(newnode, DTD_ATTR_DEFAULT, tabptr->zone_secflags_default);
2768 if (err != Z_OK)
2769 return (err);
2770 err = newprop(newnode, DTD_ATTR_LOWER, tabptr->zone_secflags_lower);
2771 if (err != Z_OK)
2772 return (err);
2773 err = newprop(newnode, DTD_ATTR_UPPER, tabptr->zone_secflags_upper);
2774 if (err != Z_OK)
2775 return (err);
2776
2777 return (Z_OK);
2778 }
2779
2780 int
zonecfg_add_secflags(zone_dochandle_t handle,struct zone_secflagstab * tabptr)2781 zonecfg_add_secflags(zone_dochandle_t handle, struct zone_secflagstab *tabptr)
2782 {
2783 int err;
2784
2785
2786 if (tabptr == NULL)
2787 return (Z_INVAL);
2788
2789 if ((err = operation_prep(handle)) != Z_OK)
2790 return (err);
2791
2792 if ((err = zonecfg_add_secflags_core(handle, tabptr)) != Z_OK)
2793 return (err);
2794
2795 return (Z_OK);
2796 }
2797
2798 static int
zonecfg_delete_secflags_core(zone_dochandle_t handle,struct zone_secflagstab * tabptr)2799 zonecfg_delete_secflags_core(zone_dochandle_t handle,
2800 struct zone_secflagstab *tabptr)
2801 {
2802 xmlNodePtr cur = handle->zone_dh_cur;
2803 boolean_t def_match, low_match, up_match;
2804
2805 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2806 if (xmlStrcmp(cur->name, DTD_ELEM_SECFLAGS) != 0)
2807 continue;
2808
2809 def_match = match_prop(cur, DTD_ATTR_DEFAULT,
2810 tabptr->zone_secflags_default);
2811 low_match = match_prop(cur, DTD_ATTR_LOWER,
2812 tabptr->zone_secflags_lower);
2813 up_match = match_prop(cur, DTD_ATTR_UPPER,
2814 tabptr->zone_secflags_upper);
2815
2816 if (def_match && low_match && up_match) {
2817 xmlUnlinkNode(cur);
2818 xmlFreeNode(cur);
2819 return (Z_OK);
2820 }
2821
2822 }
2823 return (Z_NO_RESOURCE_ID);
2824 }
2825
2826 int
zonecfg_delete_secflags(zone_dochandle_t handle,struct zone_secflagstab * tabptr)2827 zonecfg_delete_secflags(zone_dochandle_t handle,
2828 struct zone_secflagstab *tabptr)
2829 {
2830 int err;
2831
2832 if (tabptr == NULL)
2833 return (Z_INVAL);
2834
2835 if ((err = operation_prep(handle)) != Z_OK)
2836 return (err);
2837
2838 if ((err = zonecfg_delete_secflags_core(handle, tabptr)) != Z_OK)
2839 return (err);
2840
2841 return (Z_OK);
2842 }
2843
2844 int
zonecfg_modify_secflags(zone_dochandle_t handle,struct zone_secflagstab * oldtabptr,struct zone_secflagstab * newtabptr)2845 zonecfg_modify_secflags(zone_dochandle_t handle,
2846 struct zone_secflagstab *oldtabptr,
2847 struct zone_secflagstab *newtabptr)
2848 {
2849 int err;
2850
2851 if (oldtabptr == NULL || newtabptr == NULL)
2852 return (Z_INVAL);
2853
2854 if ((err = operation_prep(handle)) != Z_OK)
2855 return (err);
2856
2857 if ((err = zonecfg_delete_secflags_core(handle, oldtabptr))
2858 != Z_OK)
2859 return (err);
2860
2861 if ((err = zonecfg_add_secflags_core(handle, newtabptr)) != Z_OK)
2862 return (err);
2863
2864 return (Z_OK);
2865 }
2866
2867 int
zonecfg_lookup_secflags(zone_dochandle_t handle,struct zone_secflagstab * tabptr)2868 zonecfg_lookup_secflags(zone_dochandle_t handle,
2869 struct zone_secflagstab *tabptr)
2870 {
2871 xmlNodePtr cur;
2872 int err;
2873
2874 if (tabptr == NULL)
2875 return (Z_INVAL);
2876
2877 if ((err = operation_prep(handle)) != Z_OK)
2878 return (err);
2879
2880 cur = handle->zone_dh_cur;
2881
2882 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
2883 if (xmlStrcmp(cur->name, DTD_ELEM_SECFLAGS) != 0)
2884 continue;
2885
2886 if ((err = fetchprop(cur, DTD_ATTR_DEFAULT,
2887 tabptr->zone_secflags_default,
2888 sizeof (tabptr->zone_secflags_default))) != Z_OK) {
2889 handle->zone_dh_cur = handle->zone_dh_top;
2890 return (err);
2891 }
2892
2893 if ((err = fetchprop(cur, DTD_ATTR_LOWER,
2894 tabptr->zone_secflags_lower,
2895 sizeof (tabptr->zone_secflags_lower))) != Z_OK) {
2896 handle->zone_dh_cur = handle->zone_dh_top;
2897 return (err);
2898 }
2899
2900 if ((err = fetchprop(cur, DTD_ATTR_UPPER,
2901 tabptr->zone_secflags_upper,
2902 sizeof (tabptr->zone_secflags_upper))) != Z_OK) {
2903 handle->zone_dh_cur = handle->zone_dh_top;
2904 return (err);
2905 }
2906
2907 return (Z_OK);
2908 }
2909
2910 return (Z_NO_ENTRY);
2911 }
2912
2913 /* Lock to serialize all devwalks */
2914 static pthread_mutex_t zonecfg_devwalk_lock = PTHREAD_MUTEX_INITIALIZER;
2915 /*
2916 * Global variables used to pass data from zonecfg_dev_manifest to the nftw
2917 * call-back (zonecfg_devwalk_cb). g_devwalk_data is really the void*
2918 * parameter and g_devwalk_cb is really the *cb parameter from
2919 * zonecfg_dev_manifest.
2920 */
2921 typedef struct __g_devwalk_data *g_devwalk_data_t;
2922 static g_devwalk_data_t g_devwalk_data;
2923 static int (*g_devwalk_cb)(const char *, uid_t, gid_t, mode_t, const char *,
2924 void *);
2925 static size_t g_devwalk_skip_prefix;
2926
2927 /*
2928 * zonecfg_dev_manifest call-back function used during detach to generate the
2929 * dev info in the manifest.
2930 */
2931 static int
get_detach_dev_entry(const char * name,uid_t uid,gid_t gid,mode_t mode,const char * acl,void * hdl)2932 get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode,
2933 const char *acl, void *hdl)
2934 {
2935 zone_dochandle_t handle = (zone_dochandle_t)hdl;
2936 xmlNodePtr newnode;
2937 xmlNodePtr cur;
2938 int err;
2939 char buf[128];
2940
2941 if ((err = operation_prep(handle)) != Z_OK)
2942 return (err);
2943
2944 cur = handle->zone_dh_cur;
2945 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL);
2946 if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK)
2947 return (err);
2948 (void) snprintf(buf, sizeof (buf), "%lu", uid);
2949 if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK)
2950 return (err);
2951 (void) snprintf(buf, sizeof (buf), "%lu", gid);
2952 if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK)
2953 return (err);
2954 (void) snprintf(buf, sizeof (buf), "%o", mode);
2955 if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK)
2956 return (err);
2957 if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK)
2958 return (err);
2959 return (Z_OK);
2960 }
2961
2962 /*
2963 * This is the nftw call-back function used by zonecfg_dev_manifest. It is
2964 * responsible for calling the actual call-back.
2965 */
2966 /* ARGSUSED2 */
2967 static int
zonecfg_devwalk_cb(const char * path,const struct stat * st,int f,struct FTW * ftw)2968 zonecfg_devwalk_cb(const char *path, const struct stat *st, int f,
2969 struct FTW *ftw)
2970 {
2971 acl_t *acl;
2972 char *acl_txt = NULL;
2973
2974 /* skip all but character and block devices */
2975 if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode))
2976 return (0);
2977
2978 if ((acl_get(path, ACL_NO_TRIVIAL, &acl) == 0) &&
2979 acl != NULL) {
2980 acl_txt = acl_totext(acl, ACL_NORESOLVE);
2981 acl_free(acl);
2982 }
2983
2984 if (strlen(path) <= g_devwalk_skip_prefix)
2985 return (0);
2986
2987 (void) g_devwalk_cb(path + g_devwalk_skip_prefix, st->st_uid,
2988 st->st_gid, st->st_mode & S_IAMB, acl_txt != NULL ? acl_txt : "",
2989 g_devwalk_data);
2990 free(acl_txt);
2991 return (0);
2992 }
2993
2994 /*
2995 * Walk the dev tree for the zone specified by hdl and call the
2996 * get_detach_dev_entry call-back function for each entry in the tree. The
2997 * call-back will be passed the name, uid, gid, mode, acl string and the
2998 * handle input parameter for each dev entry.
2999 *
3000 * Data is passed to get_detach_dev_entry through the global variables
3001 * g_devwalk_data, *g_devwalk_cb, and g_devwalk_skip_prefix. The
3002 * zonecfg_devwalk_cb function will actually call get_detach_dev_entry.
3003 */
3004 int
zonecfg_dev_manifest(zone_dochandle_t hdl)3005 zonecfg_dev_manifest(zone_dochandle_t hdl)
3006 {
3007 char path[MAXPATHLEN];
3008 int ret;
3009
3010 if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK)
3011 return (ret);
3012
3013 if (strlcat(path, "/dev", sizeof (path)) >= sizeof (path))
3014 return (Z_TOO_BIG);
3015
3016 /*
3017 * We have to serialize all devwalks in the same process
3018 * (which should be fine), since nftw() is so badly designed.
3019 */
3020 (void) pthread_mutex_lock(&zonecfg_devwalk_lock);
3021
3022 g_devwalk_skip_prefix = strlen(path) + 1;
3023 g_devwalk_data = (g_devwalk_data_t)hdl;
3024 g_devwalk_cb = get_detach_dev_entry;
3025 (void) nftw(path, zonecfg_devwalk_cb, 0, FTW_PHYS);
3026
3027 (void) pthread_mutex_unlock(&zonecfg_devwalk_lock);
3028 return (Z_OK);
3029 }
3030
3031 /*
3032 * Update the owner, group, mode and acl on the specified dev (inpath) for
3033 * the zone (hdl). This function can be used to fix up the dev tree after
3034 * attaching a migrated zone.
3035 */
3036 int
zonecfg_devperms_apply(zone_dochandle_t hdl,const char * inpath,uid_t owner,gid_t group,mode_t mode,const char * acltxt)3037 zonecfg_devperms_apply(zone_dochandle_t hdl, const char *inpath, uid_t owner,
3038 gid_t group, mode_t mode, const char *acltxt)
3039 {
3040 int ret;
3041 char path[MAXPATHLEN];
3042 struct stat st;
3043 acl_t *aclp;
3044
3045 if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK)
3046 return (ret);
3047
3048 if (strlcat(path, "/dev/", sizeof (path)) >= sizeof (path))
3049 return (Z_TOO_BIG);
3050 if (strlcat(path, inpath, sizeof (path)) >= sizeof (path))
3051 return (Z_TOO_BIG);
3052
3053 if (stat(path, &st) == -1)
3054 return (Z_INVAL);
3055
3056 /* make sure we're only touching device nodes */
3057 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode))
3058 return (Z_INVAL);
3059
3060 if (chown(path, owner, group) == -1)
3061 return (Z_SYSTEM);
3062
3063 if (chmod(path, mode) == -1)
3064 return (Z_SYSTEM);
3065
3066 if ((acltxt == NULL) || (strcmp(acltxt, "") == 0))
3067 return (Z_OK);
3068
3069 if (acl_fromtext(acltxt, &aclp) != 0) {
3070 errno = EINVAL;
3071 return (Z_SYSTEM);
3072 }
3073
3074 errno = 0;
3075 if (acl_set(path, aclp) == -1) {
3076 free(aclp);
3077 return (Z_SYSTEM);
3078 }
3079
3080 free(aclp);
3081 return (Z_OK);
3082 }
3083
3084 /*
3085 * This function finds everything mounted under a zone's rootpath.
3086 * This returns the number of mounts under rootpath, or -1 on error.
3087 * callback is called once per mount found with the first argument
3088 * pointing to a mnttab structure containing the mount's information.
3089 *
3090 * If the callback function returns non-zero zonecfg_find_mounts
3091 * aborts with an error.
3092 */
3093 int
zonecfg_find_mounts(char * rootpath,int (* callback)(const struct mnttab *,void *),void * priv)3094 zonecfg_find_mounts(char *rootpath, int (*callback)(const struct mnttab *,
3095 void *), void *priv)
3096 {
3097 FILE *mnttab;
3098 struct mnttab m;
3099 size_t l;
3100 int zfsl;
3101 int rv = 0;
3102 char zfs_path[MAXPATHLEN];
3103
3104 assert(rootpath != NULL);
3105
3106 if ((zfsl = snprintf(zfs_path, sizeof (zfs_path), "%s/.zfs/", rootpath))
3107 >= sizeof (zfs_path))
3108 return (-1);
3109
3110 l = strlen(rootpath);
3111
3112 mnttab = fopen("/etc/mnttab", "r");
3113
3114 if (mnttab == NULL)
3115 return (-1);
3116
3117 if (ioctl(fileno(mnttab), MNTIOC_SHOWHIDDEN, NULL) < 0) {
3118 rv = -1;
3119 goto out;
3120 }
3121
3122 while (!getmntent(mnttab, &m)) {
3123 if ((strncmp(rootpath, m.mnt_mountp, l) == 0) &&
3124 (m.mnt_mountp[l] == '/') &&
3125 (strncmp(zfs_path, m.mnt_mountp, zfsl) != 0)) {
3126 rv++;
3127 if (callback == NULL)
3128 continue;
3129 if (callback(&m, priv)) {
3130 rv = -1;
3131 goto out;
3132
3133 }
3134 }
3135 }
3136
3137 out:
3138 (void) fclose(mnttab);
3139 return (rv);
3140 }
3141
3142 int
zonecfg_lookup_attr(zone_dochandle_t handle,struct zone_attrtab * tabptr)3143 zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3144 {
3145 xmlNodePtr cur, firstmatch;
3146 int err;
3147 char name[MAXNAMELEN], type[MAXNAMELEN], value[MAXNAMELEN];
3148
3149 if (tabptr == NULL)
3150 return (Z_INVAL);
3151
3152 if ((err = operation_prep(handle)) != Z_OK)
3153 return (err);
3154
3155 cur = handle->zone_dh_cur;
3156 firstmatch = NULL;
3157 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
3158 if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
3159 continue;
3160 if (strlen(tabptr->zone_attr_name) > 0) {
3161 if ((fetchprop(cur, DTD_ATTR_NAME, name,
3162 sizeof (name)) == Z_OK) &&
3163 (strcmp(tabptr->zone_attr_name, name) == 0)) {
3164 if (firstmatch == NULL)
3165 firstmatch = cur;
3166 else
3167 return (Z_INSUFFICIENT_SPEC);
3168 }
3169 }
3170 if (strlen(tabptr->zone_attr_type) > 0) {
3171 if ((fetchprop(cur, DTD_ATTR_TYPE, type,
3172 sizeof (type)) == Z_OK)) {
3173 if (strcmp(tabptr->zone_attr_type, type) == 0) {
3174 if (firstmatch == NULL)
3175 firstmatch = cur;
3176 else if (firstmatch != cur)
3177 return (Z_INSUFFICIENT_SPEC);
3178 } else {
3179 /*
3180 * If another property matched but this
3181 * one doesn't then reset firstmatch.
3182 */
3183 if (firstmatch == cur)
3184 firstmatch = NULL;
3185 }
3186 }
3187 }
3188 if (strlen(tabptr->zone_attr_value) > 0) {
3189 if ((fetchprop(cur, DTD_ATTR_VALUE, value,
3190 sizeof (value)) == Z_OK)) {
3191 if (strcmp(tabptr->zone_attr_value, value) ==
3192 0) {
3193 if (firstmatch == NULL)
3194 firstmatch = cur;
3195 else if (firstmatch != cur)
3196 return (Z_INSUFFICIENT_SPEC);
3197 } else {
3198 /*
3199 * If another property matched but this
3200 * one doesn't then reset firstmatch.
3201 */
3202 if (firstmatch == cur)
3203 firstmatch = NULL;
3204 }
3205 }
3206 }
3207 }
3208 if (firstmatch == NULL)
3209 return (Z_NO_RESOURCE_ID);
3210
3211 cur = firstmatch;
3212
3213 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name,
3214 sizeof (tabptr->zone_attr_name))) != Z_OK)
3215 return (err);
3216
3217 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type,
3218 sizeof (tabptr->zone_attr_type))) != Z_OK)
3219 return (err);
3220
3221 if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value,
3222 sizeof (tabptr->zone_attr_value))) != Z_OK)
3223 return (err);
3224
3225 return (Z_OK);
3226 }
3227
3228 static int
zonecfg_add_attr_core(zone_dochandle_t handle,struct zone_attrtab * tabptr)3229 zonecfg_add_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3230 {
3231 xmlNodePtr newnode, cur = handle->zone_dh_cur;
3232 int err;
3233
3234 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ATTR, NULL);
3235 err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_attr_name);
3236 if (err != Z_OK)
3237 return (err);
3238 err = newprop(newnode, DTD_ATTR_TYPE, tabptr->zone_attr_type);
3239 if (err != Z_OK)
3240 return (err);
3241 err = newprop(newnode, DTD_ATTR_VALUE, tabptr->zone_attr_value);
3242 if (err != Z_OK)
3243 return (err);
3244 return (Z_OK);
3245 }
3246
3247 int
zonecfg_add_attr(zone_dochandle_t handle,struct zone_attrtab * tabptr)3248 zonecfg_add_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3249 {
3250 int err;
3251
3252 if (tabptr == NULL)
3253 return (Z_INVAL);
3254
3255 if ((err = operation_prep(handle)) != Z_OK)
3256 return (err);
3257
3258 if ((err = zonecfg_add_attr_core(handle, tabptr)) != Z_OK)
3259 return (err);
3260
3261 return (Z_OK);
3262 }
3263
3264 static int
zonecfg_delete_attr_core(zone_dochandle_t handle,struct zone_attrtab * tabptr)3265 zonecfg_delete_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3266 {
3267 xmlNodePtr cur = handle->zone_dh_cur;
3268 int name_match, type_match, value_match;
3269
3270 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
3271 if (xmlStrcmp(cur->name, DTD_ELEM_ATTR))
3272 continue;
3273
3274 name_match = match_prop(cur, DTD_ATTR_NAME,
3275 tabptr->zone_attr_name);
3276 type_match = match_prop(cur, DTD_ATTR_TYPE,
3277 tabptr->zone_attr_type);
3278 value_match = match_prop(cur, DTD_ATTR_VALUE,
3279 tabptr->zone_attr_value);
3280
3281 if (name_match && type_match && value_match) {
3282 xmlUnlinkNode(cur);
3283 xmlFreeNode(cur);
3284 return (Z_OK);
3285 }
3286 }
3287 return (Z_NO_RESOURCE_ID);
3288 }
3289
3290 int
zonecfg_delete_attr(zone_dochandle_t handle,struct zone_attrtab * tabptr)3291 zonecfg_delete_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr)
3292 {
3293 int err;
3294
3295 if (tabptr == NULL)
3296 return (Z_INVAL);
3297
3298 if ((err = operation_prep(handle)) != Z_OK)
3299 return (err);
3300
3301 if ((err = zonecfg_delete_attr_core(handle, tabptr)) != Z_OK)
3302 return (err);
3303
3304 return (Z_OK);
3305 }
3306
3307 int
zonecfg_modify_attr(zone_dochandle_t handle,struct zone_attrtab * oldtabptr,struct zone_attrtab * newtabptr)3308