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