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