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