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