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