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 #include <libsysevent.h> 28 #include <pthread.h> 29 #include <stdlib.h> 30 #include <errno.h> 31 #include <fnmatch.h> 32 #include <strings.h> 33 #include <unistd.h> 34 #include <assert.h> 35 #include <libgen.h> 36 #include <libintl.h> 37 #include <alloca.h> 38 #include <ctype.h> 39 #include <sys/acl.h> 40 #include <sys/stat.h> 41 #include <sys/brand.h> 42 #include <sys/mntio.h> 43 #include <sys/mnttab.h> 44 #include <sys/nvpair.h> 45 #include <sys/types.h> 46 #include <sys/sockio.h> 47 #include <ftw.h> 48 #include <pool.h> 49 #include <libscf.h> 50 #include <libproc.h> 51 #include <sys/priocntl.h> 52 #include <libuutil.h> 53 #include <wait.h> 54 #include <bsm/adt.h> 55 56 #include <arpa/inet.h> 57 #include <netdb.h> 58 59 #include <libxml/xmlmemory.h> 60 #include <libxml/parser.h> 61 62 #include <libdevinfo.h> 63 #include <uuid/uuid.h> 64 #include <dirent.h> 65 #include <libbrand.h> 66 67 #include <libzonecfg.h> 68 #include "zonecfg_impl.h" 69 70 #define _PATH_TMPFILE "/zonecfg.XXXXXX" 71 #define ZONE_CB_RETRY_COUNT 10 72 #define ZONE_EVENT_PING_SUBCLASS "ping" 73 #define ZONE_EVENT_PING_PUBLISHER "solaris" 74 75 /* Hard-code the DTD element/attribute/entity names just once, here. */ 76 #define DTD_ELEM_ATTR (const xmlChar *) "attr" 77 #define DTD_ELEM_COMMENT (const xmlChar *) "comment" 78 #define DTD_ELEM_DEVICE (const xmlChar *) "device" 79 #define DTD_ELEM_FS (const xmlChar *) "filesystem" 80 #define DTD_ELEM_FSOPTION (const xmlChar *) "fsoption" 81 #define DTD_ELEM_IPD (const xmlChar *) "inherited-pkg-dir" 82 #define DTD_ELEM_NET (const xmlChar *) "network" 83 #define DTD_ELEM_RCTL (const xmlChar *) "rctl" 84 #define DTD_ELEM_RCTLVALUE (const xmlChar *) "rctl-value" 85 #define DTD_ELEM_ZONE (const xmlChar *) "zone" 86 #define DTD_ELEM_DATASET (const xmlChar *) "dataset" 87 #define DTD_ELEM_TMPPOOL (const xmlChar *) "tmp_pool" 88 #define DTD_ELEM_PSET (const xmlChar *) "pset" 89 #define DTD_ELEM_MCAP (const xmlChar *) "mcap" 90 #define DTD_ELEM_PACKAGE (const xmlChar *) "package" 91 #define DTD_ELEM_PATCH (const xmlChar *) "patch" 92 #define DTD_ELEM_OBSOLETES (const xmlChar *) "obsoletes" 93 #define DTD_ELEM_DEV_PERM (const xmlChar *) "dev-perm" 94 95 #define DTD_ATTR_ACTION (const xmlChar *) "action" 96 #define DTD_ATTR_ADDRESS (const xmlChar *) "address" 97 #define DTD_ATTR_AUTOBOOT (const xmlChar *) "autoboot" 98 #define DTD_ATTR_IPTYPE (const xmlChar *) "ip-type" 99 #define DTD_ATTR_DEFROUTER (const xmlChar *) "defrouter" 100 #define DTD_ATTR_DIR (const xmlChar *) "directory" 101 #define DTD_ATTR_LIMIT (const xmlChar *) "limit" 102 #define DTD_ATTR_LIMITPRIV (const xmlChar *) "limitpriv" 103 #define DTD_ATTR_BOOTARGS (const xmlChar *) "bootargs" 104 #define DTD_ATTR_SCHED (const xmlChar *) "scheduling-class" 105 #define DTD_ATTR_MATCH (const xmlChar *) "match" 106 #define DTD_ATTR_NAME (const xmlChar *) "name" 107 #define DTD_ATTR_PHYSICAL (const xmlChar *) "physical" 108 #define DTD_ATTR_POOL (const xmlChar *) "pool" 109 #define DTD_ATTR_PRIV (const xmlChar *) "priv" 110 #define DTD_ATTR_RAW (const xmlChar *) "raw" 111 #define DTD_ATTR_SPECIAL (const xmlChar *) "special" 112 #define DTD_ATTR_TYPE (const xmlChar *) "type" 113 #define DTD_ATTR_VALUE (const xmlChar *) "value" 114 #define DTD_ATTR_ZONEPATH (const xmlChar *) "zonepath" 115 #define DTD_ATTR_NCPU_MIN (const xmlChar *) "ncpu_min" 116 #define DTD_ATTR_NCPU_MAX (const xmlChar *) "ncpu_max" 117 #define DTD_ATTR_IMPORTANCE (const xmlChar *) "importance" 118 #define DTD_ATTR_PHYSCAP (const xmlChar *) "physcap" 119 #define DTD_ATTR_VERSION (const xmlChar *) "version" 120 #define DTD_ATTR_ID (const xmlChar *) "id" 121 #define DTD_ATTR_UID (const xmlChar *) "uid" 122 #define DTD_ATTR_GID (const xmlChar *) "gid" 123 #define DTD_ATTR_MODE (const xmlChar *) "mode" 124 #define DTD_ATTR_ACL (const xmlChar *) "acl" 125 #define DTD_ATTR_BRAND (const xmlChar *) "brand" 126 127 #define DTD_ENTITY_BOOLEAN "boolean" 128 #define DTD_ENTITY_DEVPATH "devpath" 129 #define DTD_ENTITY_DRIVER "driver" 130 #define DTD_ENTITY_DRVMIN "drv_min" 131 #define DTD_ENTITY_FALSE "false" 132 #define DTD_ENTITY_INT "int" 133 #define DTD_ENTITY_STRING "string" 134 #define DTD_ENTITY_TRUE "true" 135 #define DTD_ENTITY_UINT "uint" 136 137 #define DTD_ENTITY_BOOL_LEN 6 /* "false" */ 138 139 #define ATTACH_FORCED "SUNWattached.xml" 140 141 #define TMP_POOL_NAME "SUNWtmp_%s" 142 #define MAX_TMP_POOL_NAME (ZONENAME_MAX + 9) 143 #define RCAP_SERVICE "system/rcap:default" 144 #define POOLD_SERVICE "system/pools/dynamic:default" 145 146 /* 147 * rctl alias definitions 148 * 149 * This holds the alias, the full rctl name, the default priv value, action 150 * and lower limit. The functions that handle rctl aliases step through 151 * this table, matching on the alias, and using the full values for setting 152 * the rctl entry as well the limit for validation. 153 */ 154 static struct alias { 155 char *shortname; 156 char *realname; 157 char *priv; 158 char *action; 159 uint64_t low_limit; 160 } aliases[] = { 161 {ALIAS_MAXLWPS, "zone.max-lwps", "privileged", "deny", 100}, 162 {ALIAS_MAXSHMMEM, "zone.max-shm-memory", "privileged", "deny", 0}, 163 {ALIAS_MAXSHMIDS, "zone.max-shm-ids", "privileged", "deny", 0}, 164 {ALIAS_MAXMSGIDS, "zone.max-msg-ids", "privileged", "deny", 0}, 165 {ALIAS_MAXSEMIDS, "zone.max-sem-ids", "privileged", "deny", 0}, 166 {ALIAS_MAXLOCKEDMEM, "zone.max-locked-memory", "privileged", "deny", 0}, 167 {ALIAS_MAXSWAP, "zone.max-swap", "privileged", "deny", 0}, 168 {ALIAS_SHARES, "zone.cpu-shares", "privileged", "none", 0}, 169 {ALIAS_CPUCAP, "zone.cpu-cap", "privileged", "deny", 0}, 170 {NULL, NULL, NULL, NULL, 0} 171 }; 172 173 /* 174 * Structure for applying rctls to a running zone. It allows important 175 * process values to be passed together easily. 176 */ 177 typedef struct pr_info_handle { 178 struct ps_prochandle *pr; 179 pid_t pid; 180 } pr_info_handle_t; 181 182 struct zone_dochandle { 183 char *zone_dh_rootdir; 184 xmlDocPtr zone_dh_doc; 185 xmlNodePtr zone_dh_cur; 186 xmlNodePtr zone_dh_top; 187 boolean_t zone_dh_newzone; 188 boolean_t zone_dh_snapshot; 189 boolean_t zone_dh_sw_inv; 190 char zone_dh_delete_name[ZONENAME_MAX]; 191 }; 192 193 struct znotify { 194 void * zn_private; 195 evchan_t *zn_eventchan; 196 int (*zn_callback)(const char *zonename, zoneid_t zid, 197 const char *newstate, const char *oldstate, hrtime_t when, void *p); 198 pthread_mutex_t zn_mutex; 199 pthread_cond_t zn_cond; 200 pthread_mutex_t zn_bigmutex; 201 volatile enum {ZN_UNLOCKED, ZN_LOCKED, ZN_PING_INFLIGHT, 202 ZN_PING_RECEIVED} zn_state; 203 char zn_subscriber_id[MAX_SUBID_LEN]; 204 volatile boolean_t zn_failed; 205 int zn_failure_count; 206 }; 207 208 /* used to track nested zone-lock operations */ 209 static int zone_lock_cnt = 0; 210 211 /* used to communicate lock status to children */ 212 #define LOCK_ENV_VAR "_ZONEADM_LOCK_HELD" 213 static char zoneadm_lock_held[] = LOCK_ENV_VAR"=1"; 214 static char zoneadm_lock_not_held[] = LOCK_ENV_VAR"=0"; 215 216 char *zonecfg_root = ""; 217 218 /* 219 * For functions which return int, which is most of the functions herein, 220 * the return values should be from the Z_foo set defined in <libzonecfg.h>. 221 * In some instances, we take pains mapping some libc errno values to Z_foo 222 * values from this set. 223 */ 224 225 /* 226 * Set the root (/) path for all zonecfg configuration files. This is a 227 * private interface used by Live Upgrade extensions to access zone 228 * configuration inside mounted alternate boot environments. 229 */ 230 void 231 zonecfg_set_root(const char *rootpath) 232 { 233 if (*zonecfg_root != '\0') 234 free(zonecfg_root); 235 if (rootpath == NULL || rootpath[0] == '\0' || rootpath[1] == '\0' || 236 (zonecfg_root = strdup(rootpath)) == NULL) 237 zonecfg_root = ""; 238 } 239 240 const char * 241 zonecfg_get_root(void) 242 { 243 return (zonecfg_root); 244 } 245 246 boolean_t 247 zonecfg_in_alt_root(void) 248 { 249 return (*zonecfg_root != '\0'); 250 } 251 252 /* 253 * Callers of the _file_path() functions are expected to have the second 254 * parameter be a (char foo[MAXPATHLEN]). 255 */ 256 257 static boolean_t 258 config_file_path(const char *zonename, char *answer) 259 { 260 return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root, 261 ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN); 262 } 263 264 static boolean_t 265 snap_file_path(const char *zonename, char *answer) 266 { 267 return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml", 268 zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN); 269 } 270 271 /*ARGSUSED*/ 272 static void 273 zonecfg_error_func(void *ctx, const char *msg, ...) 274 { 275 /* 276 * This function does nothing by design. Its purpose is to prevent 277 * libxml from dumping unwanted messages to stdout/stderr. 278 */ 279 } 280 281 zone_dochandle_t 282 zonecfg_init_handle(void) 283 { 284 zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle)); 285 if (handle == NULL) { 286 errno = Z_NOMEM; 287 return (NULL); 288 } 289 290 /* generic libxml initialization */ 291 xmlLineNumbersDefault(1); 292 xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS; 293 xmlDoValidityCheckingDefaultValue = 1; 294 (void) xmlKeepBlanksDefault(0); 295 xmlGetWarningsDefaultValue = 0; 296 xmlSetGenericErrorFunc(NULL, zonecfg_error_func); 297 298 return (handle); 299 } 300 301 int 302 zonecfg_check_handle(zone_dochandle_t handle) 303 { 304 if (handle == NULL || handle->zone_dh_doc == NULL) 305 return (Z_BAD_HANDLE); 306 return (Z_OK); 307 } 308 309 void 310 zonecfg_fini_handle(zone_dochandle_t handle) 311 { 312 if (zonecfg_check_handle(handle) == Z_OK) 313 xmlFreeDoc(handle->zone_dh_doc); 314 if (handle != NULL) 315 free(handle); 316 } 317 318 static int 319 zonecfg_destroy_impl(char *filename) 320 { 321 if (unlink(filename) == -1) { 322 if (errno == EACCES) 323 return (Z_ACCES); 324 if (errno == ENOENT) 325 return (Z_NO_ZONE); 326 return (Z_MISC_FS); 327 } 328 return (Z_OK); 329 } 330 331 int 332 zonecfg_destroy(const char *zonename, boolean_t force) 333 { 334 char path[MAXPATHLEN]; 335 struct zoneent ze; 336 int err, state_err; 337 zone_state_t state; 338 339 if (!config_file_path(zonename, path)) 340 return (Z_MISC_FS); 341 342 state_err = zone_get_state((char *)zonename, &state); 343 err = access(path, W_OK); 344 345 /* 346 * If there is no file, and no index entry, reliably indicate that no 347 * such zone exists. 348 */ 349 if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT)) 350 return (Z_NO_ZONE); 351 352 /* 353 * Handle any other filesystem related errors (except if the XML 354 * file is missing, which we treat silently), unless we're forcing, 355 * in which case we plow on. 356 */ 357 if (err == -1 && errno != ENOENT) { 358 if (errno == EACCES) 359 return (Z_ACCES); 360 else if (!force) 361 return (Z_MISC_FS); 362 } 363 364 if (state > ZONE_STATE_INSTALLED) 365 return (Z_BAD_ZONE_STATE); 366 367 if (!force && state > ZONE_STATE_CONFIGURED) 368 return (Z_BAD_ZONE_STATE); 369 370 /* 371 * Index deletion succeeds even if the entry doesn't exist. So this 372 * will fail only if we've had some more severe problem. 373 */ 374 bzero(&ze, sizeof (ze)); 375 (void) strlcpy(ze.zone_name, zonename, sizeof (ze.zone_name)); 376 if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK) 377 if (!force) 378 return (err); 379 380 err = zonecfg_destroy_impl(path); 381 382 /* 383 * Treat failure to find the XML file silently, since, well, it's 384 * gone, and with the index file cleaned up, we're done. 385 */ 386 if (err == Z_OK || err == Z_NO_ZONE) 387 return (Z_OK); 388 return (err); 389 } 390 391 int 392 zonecfg_destroy_snapshot(const char *zonename) 393 { 394 char path[MAXPATHLEN]; 395 396 if (!snap_file_path(zonename, path)) 397 return (Z_MISC_FS); 398 return (zonecfg_destroy_impl(path)); 399 } 400 401 static int 402 getroot(zone_dochandle_t handle, xmlNodePtr *root) 403 { 404 if (zonecfg_check_handle(handle) == Z_BAD_HANDLE) 405 return (Z_BAD_HANDLE); 406 407 *root = xmlDocGetRootElement(handle->zone_dh_doc); 408 409 if (*root == NULL) 410 return (Z_EMPTY_DOCUMENT); 411 412 if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE)) 413 return (Z_WRONG_DOC_TYPE); 414 415 return (Z_OK); 416 } 417 418 static int 419 operation_prep(zone_dochandle_t handle) 420 { 421 xmlNodePtr root; 422 int err; 423 424 if ((err = getroot(handle, &root)) != 0) 425 return (err); 426 427 handle->zone_dh_cur = root; 428 handle->zone_dh_top = root; 429 return (Z_OK); 430 } 431 432 static int 433 fetchprop(xmlNodePtr cur, const xmlChar *propname, char *dst, size_t dstsize) 434 { 435 xmlChar *property; 436 size_t srcsize; 437 438 if ((property = xmlGetProp(cur, propname)) == NULL) 439 return (Z_BAD_PROPERTY); 440 srcsize = strlcpy(dst, (char *)property, dstsize); 441 xmlFree(property); 442 if (srcsize >= dstsize) 443 return (Z_TOO_BIG); 444 return (Z_OK); 445 } 446 447 static int 448 fetch_alloc_prop(xmlNodePtr cur, const xmlChar *propname, char **dst) 449 { 450 xmlChar *property; 451 452 if ((property = xmlGetProp(cur, propname)) == NULL) 453 return (Z_BAD_PROPERTY); 454 if ((*dst = strdup((char *)property)) == NULL) { 455 xmlFree(property); 456 return (Z_NOMEM); 457 } 458 xmlFree(property); 459 return (Z_OK); 460 } 461 462 static int 463 getrootattr(zone_dochandle_t handle, const xmlChar *propname, 464 char *propval, size_t propsize) 465 { 466 xmlNodePtr root; 467 int err; 468 469 if ((err = getroot(handle, &root)) != 0) 470 return (err); 471 472 return (fetchprop(root, propname, propval, propsize)); 473 } 474 475 static int 476 get_alloc_rootattr(zone_dochandle_t handle, const xmlChar *propname, 477 char **propval) 478 { 479 xmlNodePtr root; 480 int err; 481 482 if ((err = getroot(handle, &root)) != 0) 483 return (err); 484 485 return (fetch_alloc_prop(root, propname, propval)); 486 } 487 488 static int 489 setrootattr(zone_dochandle_t handle, const xmlChar *propname, 490 const char *propval) 491 { 492 int err; 493 xmlNodePtr root; 494 495 if ((err = getroot(handle, &root)) != Z_OK) 496 return (err); 497 498 /* 499 * If we get a null propval remove the property (ignore return since it 500 * may not be set to begin with). 501 */ 502 if (propval == NULL) { 503 (void) xmlUnsetProp(root, propname); 504 } else { 505 if (xmlSetProp(root, propname, (const xmlChar *) propval) 506 == NULL) 507 return (Z_INVAL); 508 } 509 return (Z_OK); 510 } 511 512 static void 513 addcomment(zone_dochandle_t handle, const char *comment) 514 { 515 xmlNodePtr node; 516 node = xmlNewComment((xmlChar *) comment); 517 518 if (node != NULL) 519 (void) xmlAddPrevSibling(handle->zone_dh_top, node); 520 } 521 522 static void 523 stripcomments(zone_dochandle_t handle) 524 { 525 xmlDocPtr top; 526 xmlNodePtr child, next; 527 528 top = handle->zone_dh_doc; 529 for (child = top->xmlChildrenNode; child != NULL; child = next) { 530 next = child->next; 531 if (child->name == NULL) 532 continue; 533 if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) { 534 next = child->next; 535 xmlUnlinkNode(child); 536 xmlFreeNode(child); 537 } 538 } 539 } 540 541 static void 542 strip_sw_inv(zone_dochandle_t handle) 543 { 544 xmlNodePtr root, child, next; 545 546 root = xmlDocGetRootElement(handle->zone_dh_doc); 547 for (child = root->xmlChildrenNode; child != NULL; child = next) { 548 next = child->next; 549 if (child->name == NULL) 550 continue; 551 if (xmlStrcmp(child->name, DTD_ELEM_PACKAGE) == 0 || 552 xmlStrcmp(child->name, DTD_ELEM_PATCH) == 0) { 553 next = child->next; 554 xmlUnlinkNode(child); 555 xmlFreeNode(child); 556 } 557 } 558 } 559 560 static int 561 zonecfg_get_handle_impl(const char *zonename, const char *filename, 562 zone_dochandle_t handle) 563 { 564 xmlValidCtxtPtr cvp; 565 struct stat statbuf; 566 int valid; 567 568 if (zonename == NULL) 569 return (Z_NO_ZONE); 570 571 if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) { 572 /* distinguish file not found vs. found but not parsed */ 573 if (stat(filename, &statbuf) == 0) 574 return (Z_INVALID_DOCUMENT); 575 return (Z_NO_ZONE); 576 } 577 if ((cvp = xmlNewValidCtxt()) == NULL) 578 return (Z_NOMEM); 579 cvp->error = zonecfg_error_func; 580 cvp->warning = zonecfg_error_func; 581 valid = xmlValidateDocument(cvp, handle->zone_dh_doc); 582 xmlFreeValidCtxt(cvp); 583 if (valid == 0) 584 return (Z_INVALID_DOCUMENT); 585 586 /* delete any comments such as inherited Sun copyright / ident str */ 587 stripcomments(handle); 588 return (Z_OK); 589 } 590 591 int 592 zonecfg_get_handle(const char *zonename, zone_dochandle_t handle) 593 { 594 char path[MAXPATHLEN]; 595 596 if (!config_file_path(zonename, path)) 597 return (Z_MISC_FS); 598 handle->zone_dh_newzone = B_FALSE; 599 600 return (zonecfg_get_handle_impl(zonename, path, handle)); 601 } 602 603 int 604 zonecfg_get_attach_handle(const char *path, const char *fname, 605 const char *zonename, boolean_t preserve_sw, zone_dochandle_t handle) 606 { 607 char migpath[MAXPATHLEN]; 608 int err; 609 struct stat buf; 610 611 if (snprintf(migpath, sizeof (migpath), "%s/root", path) >= 612 sizeof (migpath)) 613 return (Z_NOMEM); 614 615 if (stat(migpath, &buf) == -1 || !S_ISDIR(buf.st_mode)) 616 return (Z_NO_ZONE); 617 618 if (snprintf(migpath, sizeof (migpath), "%s/%s", path, fname) >= 619 sizeof (migpath)) 620 return (Z_NOMEM); 621 622 if ((err = zonecfg_get_handle_impl(zonename, migpath, handle)) != Z_OK) 623 return (err); 624 625 if (!preserve_sw) 626 strip_sw_inv(handle); 627 628 handle->zone_dh_newzone = B_TRUE; 629 if ((err = setrootattr(handle, DTD_ATTR_ZONEPATH, path)) != Z_OK) 630 return (err); 631 632 return (setrootattr(handle, DTD_ATTR_NAME, zonename)); 633 } 634 635 int 636 zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle) 637 { 638 char path[MAXPATHLEN]; 639 640 if (!snap_file_path(zonename, path)) 641 return (Z_MISC_FS); 642 handle->zone_dh_newzone = B_FALSE; 643 return (zonecfg_get_handle_impl(zonename, path, handle)); 644 } 645 646 int 647 zonecfg_get_template_handle(const char *template, const char *zonename, 648 zone_dochandle_t handle) 649 { 650 char path[MAXPATHLEN]; 651 int err; 652 653 if (!config_file_path(template, path)) 654 return (Z_MISC_FS); 655 656 if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK) 657 return (err); 658 handle->zone_dh_newzone = B_TRUE; 659 return (setrootattr(handle, DTD_ATTR_NAME, zonename)); 660 } 661 662 int 663 zonecfg_get_xml_handle(const char *path, zone_dochandle_t handle) 664 { 665 struct stat buf; 666 int err; 667 668 if (stat(path, &buf) == -1) 669 return (Z_MISC_FS); 670 671 if ((err = zonecfg_get_handle_impl("xml", path, handle)) != Z_OK) 672 return (err); 673 handle->zone_dh_newzone = B_TRUE; 674 return (Z_OK); 675 } 676 677 /* 678 * Initialize two handles from the manifest read on fd. The rem_handle 679 * is initialized from the input file, including the sw inventory. The 680 * local_handle is initialized with the same zone configuration but with 681 * no sw inventory. 682 */ 683 int 684 zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle, 685 zone_dochandle_t rem_handle) 686 { 687 xmlValidCtxtPtr cvp; 688 int valid; 689 690 /* load the manifest into the handle for the remote system */ 691 if ((rem_handle->zone_dh_doc = xmlReadFd(fd, NULL, NULL, 0)) == NULL) { 692 return (Z_INVALID_DOCUMENT); 693 } 694 if ((cvp = xmlNewValidCtxt()) == NULL) 695 return (Z_NOMEM); 696 cvp->error = zonecfg_error_func; 697 cvp->warning = zonecfg_error_func; 698 valid = xmlValidateDocument(cvp, rem_handle->zone_dh_doc); 699 xmlFreeValidCtxt(cvp); 700 if (valid == 0) 701 return (Z_INVALID_DOCUMENT); 702 703 /* delete any comments such as inherited Sun copyright / ident str */ 704 stripcomments(rem_handle); 705 706 rem_handle->zone_dh_newzone = B_TRUE; 707 rem_handle->zone_dh_sw_inv = B_TRUE; 708 709 /* 710 * Now use the remote system handle to generate a local system handle 711 * with an identical zones configuration but no sw inventory. 712 */ 713 if ((local_handle->zone_dh_doc = xmlCopyDoc(rem_handle->zone_dh_doc, 714 1)) == NULL) { 715 return (Z_INVALID_DOCUMENT); 716 } 717 718 /* 719 * We need to re-run xmlValidateDocument on local_handle to properly 720 * update the in-core representation of the configuration. 721 */ 722 if ((cvp = xmlNewValidCtxt()) == NULL) 723 return (Z_NOMEM); 724 cvp->error = zonecfg_error_func; 725 cvp->warning = zonecfg_error_func; 726 valid = xmlValidateDocument(cvp, local_handle->zone_dh_doc); 727 xmlFreeValidCtxt(cvp); 728 if (valid == 0) 729 return (Z_INVALID_DOCUMENT); 730 731 strip_sw_inv(local_handle); 732 733 local_handle->zone_dh_newzone = B_TRUE; 734 local_handle->zone_dh_sw_inv = B_FALSE; 735 736 return (Z_OK); 737 } 738 739 static boolean_t 740 is_renaming(zone_dochandle_t handle) 741 { 742 if (handle->zone_dh_newzone) 743 return (B_FALSE); 744 if (strlen(handle->zone_dh_delete_name) > 0) 745 return (B_TRUE); 746 return (B_FALSE); 747 } 748 749 static boolean_t 750 is_new(zone_dochandle_t handle) 751 { 752 return (handle->zone_dh_newzone || handle->zone_dh_snapshot); 753 } 754 755 static boolean_t 756 is_snapshot(zone_dochandle_t handle) 757 { 758 return (handle->zone_dh_snapshot); 759 } 760 761 /* 762 * It would be great to be able to use libc's ctype(3c) macros, but we 763 * can't, as they are locale sensitive, and it would break our limited thread 764 * safety if this routine had to change the app locale on the fly. 765 */ 766 int 767 zonecfg_validate_zonename(const char *zone) 768 { 769 int i; 770 771 if (strcmp(zone, GLOBAL_ZONENAME) == 0) 772 return (Z_BOGUS_ZONE_NAME); 773 774 if (strlen(zone) >= ZONENAME_MAX) 775 return (Z_BOGUS_ZONE_NAME); 776 777 if (!((zone[0] >= 'a' && zone[0] <= 'z') || 778 (zone[0] >= 'A' && zone[0] <= 'Z') || 779 (zone[0] >= '0' && zone[0] <= '9'))) 780 return (Z_BOGUS_ZONE_NAME); 781 782 for (i = 1; zone[i] != '\0'; i++) { 783 if (!((zone[i] >= 'a' && zone[i] <= 'z') || 784 (zone[i] >= 'A' && zone[i] <= 'Z') || 785 (zone[i] >= '0' && zone[i] <= '9') || 786 (zone[i] == '-') || (zone[i] == '_') || (zone[i] == '.'))) 787 return (Z_BOGUS_ZONE_NAME); 788 } 789 790 return (Z_OK); 791 } 792 793 /* 794 * Changing the zone name requires us to track both the old and new 795 * name of the zone until commit time. 796 */ 797 int 798 zonecfg_get_name(zone_dochandle_t handle, char *name, size_t namesize) 799 { 800 return (getrootattr(handle, DTD_ATTR_NAME, name, namesize)); 801 } 802 803 int 804 zonecfg_set_name(zone_dochandle_t handle, char *name) 805 { 806 zone_state_t state; 807 char curname[ZONENAME_MAX], old_delname[ZONENAME_MAX]; 808 int err; 809 810 if ((err = getrootattr(handle, DTD_ATTR_NAME, curname, 811 sizeof (curname))) != Z_OK) 812 return (err); 813 814 if (strcmp(name, curname) == 0) 815 return (Z_OK); 816 817 /* 818 * Switching zone names to one beginning with SUNW is not permitted. 819 */ 820 if (strncmp(name, "SUNW", 4) == 0) 821 return (Z_BOGUS_ZONE_NAME); 822 823 if ((err = zonecfg_validate_zonename(name)) != Z_OK) 824 return (err); 825 826 /* 827 * Setting the name back to the original name (effectively a revert of 828 * the name) is fine. But if we carry on, we'll falsely identify the 829 * name as "in use," so special case here. 830 */ 831 if (strcmp(name, handle->zone_dh_delete_name) == 0) { 832 err = setrootattr(handle, DTD_ATTR_NAME, name); 833 handle->zone_dh_delete_name[0] = '\0'; 834 return (err); 835 } 836 837 /* Check to see if new name chosen is already in use */ 838 if (zone_get_state(name, &state) != Z_NO_ZONE) 839 return (Z_NAME_IN_USE); 840 841 /* 842 * If this isn't already "new" or in a renaming transition, then 843 * we're initiating a rename here; so stash the "delete name" 844 * (i.e. the name of the zone we'll be removing) for the rename. 845 */ 846 (void) strlcpy(old_delname, handle->zone_dh_delete_name, 847 sizeof (old_delname)); 848 if (!is_new(handle) && !is_renaming(handle)) { 849 /* 850 * Name change is allowed only when the zone we're altering 851 * is not ready or running. 852 */ 853 err = zone_get_state(curname, &state); 854 if (err == Z_OK) { 855 if (state > ZONE_STATE_INSTALLED) 856 return (Z_BAD_ZONE_STATE); 857 } else if (err != Z_NO_ZONE) { 858 return (err); 859 } 860 861 (void) strlcpy(handle->zone_dh_delete_name, curname, 862 sizeof (handle->zone_dh_delete_name)); 863 assert(is_renaming(handle)); 864 } else if (is_renaming(handle)) { 865 err = zone_get_state(handle->zone_dh_delete_name, &state); 866 if (err == Z_OK) { 867 if (state > ZONE_STATE_INSTALLED) 868 return (Z_BAD_ZONE_STATE); 869 } else if (err != Z_NO_ZONE) { 870 return (err); 871 } 872 } 873 874 if ((err = setrootattr(handle, DTD_ATTR_NAME, name)) != Z_OK) { 875 /* 876 * Restore the deletename to whatever it was at the 877 * top of the routine, since we've had a failure. 878 */ 879 (void) strlcpy(handle->zone_dh_delete_name, old_delname, 880 sizeof (handle->zone_dh_delete_name)); 881 return (err); 882 } 883 884 return (Z_OK); 885 } 886 887 int 888 zonecfg_get_zonepath(zone_dochandle_t handle, char *path, size_t pathsize) 889 { 890 size_t len; 891 892 if ((len = strlcpy(path, zonecfg_root, pathsize)) >= pathsize) 893 return (Z_TOO_BIG); 894 return (getrootattr(handle, DTD_ATTR_ZONEPATH, path + len, 895 pathsize - len)); 896 } 897 898 int 899 zonecfg_set_zonepath(zone_dochandle_t handle, char *zonepath) 900 { 901 size_t len; 902 903 /* 904 * The user deals in absolute paths in the running global zone, but the 905 * internal configuration files deal with boot environment relative 906 * paths. Strip out the alternate root when specified. 907 */ 908 len = strlen(zonecfg_root); 909 if (strncmp(zonepath, zonecfg_root, len) != 0 || zonepath[len] != '/') 910 return (Z_BAD_PROPERTY); 911 zonepath += len; 912 return (setrootattr(handle, DTD_ATTR_ZONEPATH, zonepath)); 913 } 914 915 int 916 zonecfg_get_brand(zone_dochandle_t handle, char *brand, size_t brandsize) 917 { 918 int ret, sz; 919 920 ret = getrootattr(handle, DTD_ATTR_BRAND, brand, brandsize); 921 922 /* If the zone has no brand, it is native. */ 923 if (ret == Z_OK && brand[0] == '\0') { 924 sz = strlcpy(brand, NATIVE_BRAND_NAME, brandsize); 925 if (sz >= brandsize) 926 ret = Z_TOO_BIG; 927 else 928 ret = Z_OK; 929 } 930 931 return (ret); 932 } 933 934 int 935 zonecfg_set_brand(zone_dochandle_t handle, char *brand) 936 { 937 return (setrootattr(handle, DTD_ATTR_BRAND, brand)); 938 } 939 940 int 941 zonecfg_get_autoboot(zone_dochandle_t handle, boolean_t *autoboot) 942 { 943 char autobootstr[DTD_ENTITY_BOOL_LEN]; 944 int ret; 945 946 if ((ret = getrootattr(handle, DTD_ATTR_AUTOBOOT, autobootstr, 947 sizeof (autobootstr))) != Z_OK) 948 return (ret); 949 950 if (strcmp(autobootstr, DTD_ENTITY_TRUE) == 0) 951 *autoboot = B_TRUE; 952 else if (strcmp(autobootstr, DTD_ENTITY_FALSE) == 0) 953 *autoboot = B_FALSE; 954 else 955 ret = Z_BAD_PROPERTY; 956 return (ret); 957 } 958 959 int 960 zonecfg_set_autoboot(zone_dochandle_t handle, boolean_t autoboot) 961 { 962 return (setrootattr(handle, DTD_ATTR_AUTOBOOT, 963 autoboot ? DTD_ENTITY_TRUE : DTD_ENTITY_FALSE)); 964 } 965 966 int 967 zonecfg_get_pool(zone_dochandle_t handle, char *pool, size_t poolsize) 968 { 969 return (getrootattr(handle, DTD_ATTR_POOL, pool, poolsize)); 970 } 971 972 int 973 zonecfg_set_pool(zone_dochandle_t handle, char *pool) 974 { 975 return (setrootattr(handle, DTD_ATTR_POOL, pool)); 976 } 977 978 int 979 zonecfg_get_limitpriv(zone_dochandle_t handle, char **limitpriv) 980 { 981 return (get_alloc_rootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv)); 982 } 983 984 int 985 zonecfg_set_limitpriv(zone_dochandle_t handle, char *limitpriv) 986 { 987 return (setrootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv)); 988 } 989 990 int 991 zonecfg_get_bootargs(zone_dochandle_t handle, char *bargs, size_t bargssize) 992 { 993 return (getrootattr(handle, DTD_ATTR_BOOTARGS, bargs, bargssize)); 994 } 995 996 int 997 zonecfg_set_bootargs(zone_dochandle_t handle, char *bargs) 998 { 999 return (setrootattr(handle, DTD_ATTR_BOOTARGS, bargs)); 1000 } 1001 1002 int 1003 zonecfg_get_sched_class(zone_dochandle_t handle, char *sched, size_t schedsize) 1004 { 1005 return (getrootattr(handle, DTD_ATTR_SCHED, sched, schedsize)); 1006 } 1007 1008 int 1009 zonecfg_set_sched(zone_dochandle_t handle, char *sched) 1010 { 1011 return (setrootattr(handle, DTD_ATTR_SCHED, sched)); 1012 } 1013 1014 /* 1015 * /etc/zones/index caches a vital piece of information which is also 1016 * in the <zonename>.xml file: the path to the zone. This is for performance, 1017 * since we need to walk all zonepath's in order to be able to detect conflicts 1018 * (see crosscheck_zonepaths() in the zoneadm command). 1019 * 1020 * An additional complexity is that when doing a rename, we'd like the entire 1021 * index update operation (rename, and potential state changes) to be atomic. 1022 * In general, the operation of this function should succeed or fail as 1023 * a unit. 1024 */ 1025 int 1026 zonecfg_refresh_index_file(zone_dochandle_t handle) 1027 { 1028 char name[ZONENAME_MAX], zonepath[MAXPATHLEN]; 1029 struct zoneent ze; 1030 int err; 1031 int opcode; 1032 char *zn; 1033 1034 bzero(&ze, sizeof (ze)); 1035 ze.zone_state = -1; /* Preserve existing state in index */ 1036 1037 if ((err = zonecfg_get_name(handle, name, sizeof (name))) != Z_OK) 1038 return (err); 1039 (void) strlcpy(ze.zone_name, name, sizeof (ze.zone_name)); 1040 1041 if ((err = zonecfg_get_zonepath(handle, zonepath, 1042 sizeof (zonepath))) != Z_OK) 1043 return (err); 1044 (void) strlcpy(ze.zone_path, zonepath + strlen(zonecfg_root), 1045 sizeof (ze.zone_path)); 1046 1047 if (is_renaming(handle)) { 1048 opcode = PZE_MODIFY; 1049 (void) strlcpy(ze.zone_name, handle->zone_dh_delete_name, 1050 sizeof (ze.zone_name)); 1051 (void) strlcpy(ze.zone_newname, name, sizeof (ze.zone_newname)); 1052 } else if (is_new(handle)) { 1053 FILE *cookie; 1054 /* 1055 * Be tolerant of the zone already existing in the index file, 1056 * since we might be forcibly overwriting an existing 1057 * configuration with a new one (for example 'create -F' 1058 * in zonecfg). 1059 */ 1060 opcode = PZE_ADD; 1061 cookie = setzoneent(); 1062 while ((zn = getzoneent(cookie)) != NULL) { 1063 if (strcmp(zn, name) == 0) { 1064 opcode = PZE_MODIFY; 1065 free(zn); 1066 break; 1067 } 1068 free(zn); 1069 } 1070 endzoneent(cookie); 1071 ze.zone_state = ZONE_STATE_CONFIGURED; 1072 } else { 1073 opcode = PZE_MODIFY; 1074 } 1075 1076 if ((err = putzoneent(&ze, opcode)) != Z_OK) 1077 return (err); 1078 1079 return (Z_OK); 1080 } 1081 1082 /* 1083 * The goal of this routine is to cause the index file update and the 1084 * document save to happen as an atomic operation. We do the document 1085 * first, saving a backup copy using a hard link; if that succeeds, we go 1086 * on to the index. If that fails, we roll the document back into place. 1087 * 1088 * Strategy: 1089 * 1090 * New zone 'foo' configuration: 1091 * Create tmpfile (zonecfg.xxxxxx) 1092 * Write XML to tmpfile 1093 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml) 1094 * Add entry to index file 1095 * If it fails, delete foo.xml, leaving nothing behind. 1096 * 1097 * Save existing zone 'foo': 1098 * Make backup of foo.xml -> .backup 1099 * Create tmpfile (zonecfg.xxxxxx) 1100 * Write XML to tmpfile 1101 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml) 1102 * Modify index file as needed 1103 * If it fails, recover from .backup -> foo.xml 1104 * 1105 * Rename 'foo' to 'bar': 1106 * Create tmpfile (zonecfg.xxxxxx) 1107 * Write XML to tmpfile 1108 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml) 1109 * Add entry for 'bar' to index file, Remove entry for 'foo' (refresh) 1110 * If it fails, delete bar.xml; foo.xml is left behind. 1111 */ 1112 static int 1113 zonecfg_save_impl(zone_dochandle_t handle, char *filename) 1114 { 1115 char tmpfile[MAXPATHLEN]; 1116 char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN]; 1117 int tmpfd, err, valid; 1118 xmlValidCtxt cvp = { NULL }; 1119 boolean_t backup; 1120 1121 (void) strlcpy(tmpfile, filename, sizeof (tmpfile)); 1122 (void) dirname(tmpfile); 1123 (void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile)); 1124 1125 tmpfd = mkstemp(tmpfile); 1126 if (tmpfd == -1) { 1127 (void) unlink(tmpfile); 1128 return (Z_TEMP_FILE); 1129 } 1130 (void) close(tmpfd); 1131 1132 cvp.error = zonecfg_error_func; 1133 cvp.warning = zonecfg_error_func; 1134 1135 /* 1136 * We do a final validation of the document. Since the library has 1137 * malfunctioned if it fails to validate, we follow-up with an 1138 * assert() that the doc is valid. 1139 */ 1140 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc); 1141 assert(valid != 0); 1142 1143 if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0) 1144 goto err; 1145 1146 (void) chmod(tmpfile, 0644); 1147 1148 /* 1149 * In the event we are doing a standard save, hard link a copy of the 1150 * original file in .backup.<pid>.filename so we can restore it if 1151 * something goes wrong. 1152 */ 1153 if (!is_new(handle) && !is_renaming(handle)) { 1154 backup = B_TRUE; 1155 1156 (void) strlcpy(bakdir, filename, sizeof (bakdir)); 1157 (void) strlcpy(bakbase, filename, sizeof (bakbase)); 1158 (void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s", 1159 dirname(bakdir), getpid(), basename(bakbase)); 1160 1161 if (link(filename, bakfile) == -1) { 1162 err = errno; 1163 (void) unlink(tmpfile); 1164 if (errno == EACCES) 1165 return (Z_ACCES); 1166 return (Z_MISC_FS); 1167 } 1168 } 1169 1170 /* 1171 * Move the new document over top of the old. 1172 * i.e.: zonecfg.XXXXXX -> myzone.xml 1173 */ 1174 if (rename(tmpfile, filename) == -1) { 1175 err = errno; 1176 (void) unlink(tmpfile); 1177 if (backup) 1178 (void) unlink(bakfile); 1179 if (err == EACCES) 1180 return (Z_ACCES); 1181 return (Z_MISC_FS); 1182 } 1183 1184 /* 1185 * If this is a snapshot, we're done-- don't add an index entry. 1186 */ 1187 if (is_snapshot(handle)) 1188 return (Z_OK); 1189 1190 /* now update the index file to reflect whatever we just did */ 1191 if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) { 1192 if (backup) { 1193 /* 1194 * Try to restore from our backup. 1195 */ 1196 (void) unlink(filename); 1197 (void) rename(bakfile, filename); 1198 } else { 1199 /* 1200 * Either the zone is new, in which case we can delete 1201 * new.xml, or we're doing a rename, so ditto. 1202 */ 1203 assert(is_new(handle) || is_renaming(handle)); 1204 (void) unlink(filename); 1205 } 1206 return (Z_UPDATING_INDEX); 1207 } 1208 1209 if (backup) 1210 (void) unlink(bakfile); 1211 1212 return (Z_OK); 1213 1214 err: 1215 (void) unlink(tmpfile); 1216 return (Z_SAVING_FILE); 1217 } 1218 1219 int 1220 zonecfg_save(zone_dochandle_t handle) 1221 { 1222 char zname[ZONENAME_MAX], path[MAXPATHLEN]; 1223 char delpath[MAXPATHLEN]; 1224 int err = Z_SAVING_FILE; 1225 1226 if (zonecfg_check_handle(handle) != Z_OK) 1227 return (Z_BAD_HANDLE); 1228 1229 /* 1230 * We don't support saving snapshots or a tree containing a sw 1231 * inventory at this time. 1232 */ 1233 if (handle->zone_dh_snapshot || handle->zone_dh_sw_inv) 1234 return (Z_INVAL); 1235 1236 if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK) 1237 return (err); 1238 1239 if (!config_file_path(zname, path)) 1240 return (Z_MISC_FS); 1241 1242 addcomment(handle, "\n DO NOT EDIT THIS " 1243 "FILE. Use zonecfg(1M) instead.\n"); 1244 1245 err = zonecfg_save_impl(handle, path); 1246 1247 stripcomments(handle); 1248 1249 if (err != Z_OK) 1250 return (err); 1251 1252 handle->zone_dh_newzone = B_FALSE; 1253 1254 if (is_renaming(handle)) { 1255 if (config_file_path(handle->zone_dh_delete_name, delpath)) 1256 (void) unlink(delpath); 1257 handle->zone_dh_delete_name[0] = '\0'; 1258 } 1259 1260 return (Z_OK); 1261 } 1262 1263 int 1264 zonecfg_verify_save(zone_dochandle_t handle, char *filename) 1265 { 1266 int valid; 1267 1268 xmlValidCtxt cvp = { NULL }; 1269 1270 if (zonecfg_check_handle(handle) != Z_OK) 1271 return (Z_BAD_HANDLE); 1272 1273 cvp.error = zonecfg_error_func; 1274 cvp.warning = zonecfg_error_func; 1275 1276 /* 1277 * We do a final validation of the document. Since the library has 1278 * malfunctioned if it fails to validate, we follow-up with an 1279 * assert() that the doc is valid. 1280 */ 1281 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc); 1282 assert(valid != 0); 1283 1284 if (xmlSaveFormatFile(filename, handle->zone_dh_doc, 1) <= 0) 1285 return (Z_SAVING_FILE); 1286 1287 return (Z_OK); 1288 } 1289 1290 int 1291 zonecfg_detach_save(zone_dochandle_t handle, uint_t flags) 1292 { 1293 char zname[ZONENAME_MAX]; 1294 char path[MAXPATHLEN]; 1295 char migpath[MAXPATHLEN]; 1296 xmlValidCtxt cvp = { NULL }; 1297 int err = Z_SAVING_FILE; 1298 int valid; 1299 1300 if (zonecfg_check_handle(handle) != Z_OK) 1301 return (Z_BAD_HANDLE); 1302 1303 if (flags & ZONE_DRY_RUN) { 1304 (void) strlcpy(migpath, "-", sizeof (migpath)); 1305 } else { 1306 if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) 1307 != Z_OK) 1308 return (err); 1309 1310 if ((err = zone_get_zonepath(zname, path, sizeof (path))) 1311 != Z_OK) 1312 return (err); 1313 1314 if (snprintf(migpath, sizeof (migpath), "%s/%s", path, 1315 ZONE_DETACHED) >= sizeof (migpath)) 1316 return (Z_NOMEM); 1317 } 1318 1319 if ((err = operation_prep(handle)) != Z_OK) 1320 return (err); 1321 1322 addcomment(handle, "\n DO NOT EDIT THIS FILE. " 1323 "Use zonecfg(1M) and zoneadm(1M) attach.\n"); 1324 1325 cvp.error = zonecfg_error_func; 1326 cvp.warning = zonecfg_error_func; 1327 1328 /* 1329 * We do a final validation of the document. Since the library has 1330 * malfunctioned if it fails to validate, we follow-up with an 1331 * assert() that the doc is valid. 1332 */ 1333 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc); 1334 assert(valid != 0); 1335 1336 if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0) 1337 return (Z_SAVING_FILE); 1338 1339 if (!(flags & ZONE_DRY_RUN)) 1340 (void) chmod(migpath, 0644); 1341 1342 stripcomments(handle); 1343 1344 handle->zone_dh_newzone = B_FALSE; 1345 1346 return (Z_OK); 1347 } 1348 1349 boolean_t 1350 zonecfg_detached(const char *path) 1351 { 1352 char migpath[MAXPATHLEN]; 1353 struct stat buf; 1354 1355 if (snprintf(migpath, sizeof (migpath), "%s/%s", path, ZONE_DETACHED) >= 1356 sizeof (migpath)) 1357 return (B_FALSE); 1358 1359 if (stat(migpath, &buf) != -1) 1360 return (B_TRUE); 1361 1362 return (B_FALSE); 1363 } 1364 1365 void 1366 zonecfg_rm_detached(zone_dochandle_t handle, boolean_t forced) 1367 { 1368 char zname[ZONENAME_MAX]; 1369 char path[MAXPATHLEN]; 1370 char detached[MAXPATHLEN]; 1371 char attached[MAXPATHLEN]; 1372 1373 if (zonecfg_check_handle(handle) != Z_OK) 1374 return; 1375 1376 if (zonecfg_get_name(handle, zname, sizeof (zname)) != Z_OK) 1377 return; 1378 1379 if (zone_get_zonepath(zname, path, sizeof (path)) != Z_OK) 1380 return; 1381 1382 (void) snprintf(detached, sizeof (detached), "%s/%s", path, 1383 ZONE_DETACHED); 1384 (void) snprintf(attached, sizeof (attached), "%s/%s", path, 1385 ATTACH_FORCED); 1386 1387 if (forced) { 1388 (void) rename(detached, attached); 1389 } else { 1390 (void) unlink(attached); 1391 (void) unlink(detached); 1392 } 1393 } 1394 1395 /* 1396 * Special case: if access(2) fails with ENOENT, then try again using 1397 * ZONE_CONFIG_ROOT instead of config_file_path(zonename). This is how we 1398 * work around the case of a config file which has not been created yet: 1399 * the user will need access to the directory so use that as a heuristic. 1400 */ 1401 1402 int 1403 zonecfg_access(const char *zonename, int amode) 1404 { 1405 char path[MAXPATHLEN]; 1406 1407 if (!config_file_path(zonename, path)) 1408 return (Z_INVAL); 1409 if (access(path, amode) == 0) 1410 return (Z_OK); 1411 if (errno == ENOENT) { 1412 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root, 1413 ZONE_CONFIG_ROOT) >= sizeof (path)) 1414 return (Z_INVAL); 1415 if (access(path, amode) == 0) 1416 return (Z_OK); 1417 } 1418 if (errno == EACCES) 1419 return (Z_ACCES); 1420 if (errno == EINVAL) 1421 return (Z_INVAL); 1422 return (Z_MISC_FS); 1423 } 1424 1425 int 1426 zonecfg_create_snapshot(const char *zonename) 1427 { 1428 zone_dochandle_t handle; 1429 char path[MAXPATHLEN], zonepath[MAXPATHLEN], rpath[MAXPATHLEN]; 1430 int error = Z_OK, res; 1431 1432 if ((handle = zonecfg_init_handle()) == NULL) { 1433 return (Z_NOMEM); 1434 } 1435 1436 handle->zone_dh_newzone = B_TRUE; 1437 handle->zone_dh_snapshot = B_TRUE; 1438 1439 if ((error = zonecfg_get_handle(zonename, handle)) != Z_OK) 1440 goto out; 1441 if ((error = operation_prep(handle)) != Z_OK) 1442 goto out; 1443 error = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)); 1444 if (error != Z_OK) 1445 goto out; 1446 if ((res = resolvepath(zonepath, rpath, sizeof (rpath))) == -1) { 1447 error = Z_RESOLVED_PATH; 1448 goto out; 1449 } 1450 /* 1451 * If the resolved path is not the same as the original path, then 1452 * save the resolved path in the snapshot, thus preventing any 1453 * potential problems down the line when zoneadmd goes to unmount 1454 * file systems and depends on initial string matches with resolved 1455 * paths. 1456 */ 1457 rpath[res] = '\0'; 1458 if (strcmp(zonepath, rpath) != 0) { 1459 if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK) 1460 goto out; 1461 } 1462 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root, 1463 ZONE_SNAPSHOT_ROOT) >= sizeof (path)) { 1464 error = Z_MISC_FS; 1465 goto out; 1466 } 1467 if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) { 1468 error = Z_MISC_FS; 1469 goto out; 1470 } 1471 1472 if (!snap_file_path(zonename, path)) { 1473 error = Z_MISC_FS; 1474 goto out; 1475 } 1476 1477 addcomment(handle, "\n DO NOT EDIT THIS FILE. " 1478 "It is a snapshot of running zone state.\n"); 1479 1480 error = zonecfg_save_impl(handle, path); 1481 1482 stripcomments(handle); 1483 1484 out: 1485 zonecfg_fini_handle(handle); 1486 return (error); 1487 } 1488 1489 int 1490 zonecfg_get_iptype(zone_dochandle_t handle, zone_iptype_t *iptypep) 1491 { 1492 char property[10]; /* 10 is big enough for "shared"/"exclusive" */ 1493 int err; 1494 1495 err = getrootattr(handle, DTD_ATTR_IPTYPE, property, sizeof (property)); 1496 if (err == Z_BAD_PROPERTY) { 1497 /* Return default value */ 1498 *iptypep = ZS_SHARED; 1499 return (Z_OK); 1500 } else if (err != Z_OK) { 1501 return (err); 1502 } 1503 1504 if (strlen(property) == 0 || 1505 strcmp(property, "shared") == 0) 1506 *iptypep = ZS_SHARED; 1507 else if (strcmp(property, "exclusive") == 0) 1508 *iptypep = ZS_EXCLUSIVE; 1509 else 1510 return (Z_INVAL); 1511 1512 return (Z_OK); 1513 } 1514 1515 int 1516 zonecfg_set_iptype(zone_dochandle_t handle, zone_iptype_t iptype) 1517 { 1518 xmlNodePtr cur; 1519 1520 if (handle == NULL) 1521 return (Z_INVAL); 1522 1523 cur = xmlDocGetRootElement(handle->zone_dh_doc); 1524 if (cur == NULL) { 1525 return (Z_EMPTY_DOCUMENT); 1526 } 1527 1528 if (xmlStrcmp(cur->name, DTD_ELEM_ZONE) != 0) { 1529 return (Z_WRONG_DOC_TYPE); 1530 } 1531 switch (iptype) { 1532 case ZS_SHARED: 1533 /* 1534 * Since "shared" is the default, we don't write it to the 1535 * configuration file, so that it's easier to migrate those 1536 * zones elsewhere, eg., to systems which are not IP-Instances 1537 * aware. 1538 * xmlUnsetProp only fails when the attribute doesn't exist, 1539 * which we don't care. 1540 */ 1541 (void) xmlUnsetProp(cur, DTD_ATTR_IPTYPE); 1542 break; 1543 case ZS_EXCLUSIVE: 1544 if (xmlSetProp(cur, DTD_ATTR_IPTYPE, 1545 (const xmlChar *) "exclusive") == NULL) 1546 return (Z_INVAL); 1547 break; 1548 } 1549 return (Z_OK); 1550 } 1551 1552 static int 1553 newprop(xmlNodePtr node, const xmlChar *attrname, char *src) 1554 { 1555 xmlAttrPtr newattr; 1556 1557 newattr = xmlNewProp(node, attrname, (xmlChar *)src); 1558 if (newattr == NULL) { 1559 xmlUnlinkNode(node); 1560 xmlFreeNode(node); 1561 return (Z_BAD_PROPERTY); 1562 } 1563 return (Z_OK); 1564 } 1565 1566 static int 1567 zonecfg_add_filesystem_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1568 { 1569 xmlNodePtr newnode, cur = handle->zone_dh_cur, options_node; 1570 zone_fsopt_t *ptr; 1571 int err; 1572 1573 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_FS, NULL); 1574 if ((err = newprop(newnode, DTD_ATTR_SPECIAL, 1575 tabptr->zone_fs_special)) != Z_OK) 1576 return (err); 1577 if (tabptr->zone_fs_raw[0] != '\0' && 1578 (err = newprop(newnode, DTD_ATTR_RAW, tabptr->zone_fs_raw)) != Z_OK) 1579 return (err); 1580 if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK) 1581 return (err); 1582 if ((err = newprop(newnode, DTD_ATTR_TYPE, 1583 tabptr->zone_fs_type)) != Z_OK) 1584 return (err); 1585 if (tabptr->zone_fs_options != NULL) { 1586 for (ptr = tabptr->zone_fs_options; ptr != NULL; 1587 ptr = ptr->zone_fsopt_next) { 1588 options_node = xmlNewTextChild(newnode, NULL, 1589 DTD_ELEM_FSOPTION, NULL); 1590 if ((err = newprop(options_node, DTD_ATTR_NAME, 1591 ptr->zone_fsopt_opt)) != Z_OK) 1592 return (err); 1593 } 1594 } 1595 return (Z_OK); 1596 } 1597 1598 int 1599 zonecfg_add_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr) 1600 { 1601 int err; 1602 1603 if (tabptr == NULL) 1604 return (Z_INVAL); 1605 1606 if ((err = operation_prep(handle)) != Z_OK) 1607 return (err); 1608 1609 if ((err = zonecfg_add_filesystem_core(handle, tabptr)) != Z_OK) 1610 return (err); 1611 1612 return (Z_OK); 1613 } 1614 1615 static int 1616 zonecfg_add_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1617 { 1618 xmlNodePtr newnode, cur = handle->zone_dh_cur; 1619 int err; 1620 1621 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_IPD, NULL); 1622 if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK) 1623 return (err); 1624 return (Z_OK); 1625 } 1626 1627 int 1628 zonecfg_add_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 1629 { 1630 int err; 1631 1632 if (tabptr == NULL) 1633 return (Z_INVAL); 1634 1635 if ((err = operation_prep(handle)) != Z_OK) 1636 return (err); 1637 1638 if ((err = zonecfg_add_ipd_core(handle, tabptr)) != Z_OK) 1639 return (err); 1640 1641 return (Z_OK); 1642 } 1643 1644 int 1645 zonecfg_add_fs_option(struct zone_fstab *tabptr, char *option) 1646 { 1647 zone_fsopt_t *last, *old, *new; 1648 1649 last = tabptr->zone_fs_options; 1650 for (old = last; old != NULL; old = old->zone_fsopt_next) 1651 last = old; /* walk to the end of the list */ 1652 new = (zone_fsopt_t *)malloc(sizeof (zone_fsopt_t)); 1653 if (new == NULL) 1654 return (Z_NOMEM); 1655 (void) strlcpy(new->zone_fsopt_opt, option, 1656 sizeof (new->zone_fsopt_opt)); 1657 new->zone_fsopt_next = NULL; 1658 if (last == NULL) 1659 tabptr->zone_fs_options = new; 1660 else 1661 last->zone_fsopt_next = new; 1662 return (Z_OK); 1663 } 1664 1665 int 1666 zonecfg_remove_fs_option(struct zone_fstab *tabptr, char *option) 1667 { 1668 zone_fsopt_t *last, *this, *next; 1669 1670 last = tabptr->zone_fs_options; 1671 for (this = last; this != NULL; this = this->zone_fsopt_next) { 1672 if (strcmp(this->zone_fsopt_opt, option) == 0) { 1673 next = this->zone_fsopt_next; 1674 if (this == tabptr->zone_fs_options) 1675 tabptr->zone_fs_options = next; 1676 else 1677 last->zone_fsopt_next = next; 1678 free(this); 1679 return (Z_OK); 1680 } else 1681 last = this; 1682 } 1683 return (Z_NO_PROPERTY_ID); 1684 } 1685 1686 void 1687 zonecfg_free_fs_option_list(zone_fsopt_t *list) 1688 { 1689 zone_fsopt_t *this, *next; 1690 1691 for (this = list; this != NULL; this = next) { 1692 next = this->zone_fsopt_next; 1693 free(this); 1694 } 1695 } 1696 1697 void 1698 zonecfg_free_rctl_value_list(struct zone_rctlvaltab *valtab) 1699 { 1700 if (valtab == NULL) 1701 return; 1702 zonecfg_free_rctl_value_list(valtab->zone_rctlval_next); 1703 free(valtab); 1704 } 1705 1706 static boolean_t 1707 match_prop(xmlNodePtr cur, const xmlChar *attr, char *user_prop) 1708 { 1709 xmlChar *gotten_prop; 1710 int prop_result; 1711 1712 gotten_prop = xmlGetProp(cur, attr); 1713 if (gotten_prop == NULL) /* shouldn't happen */ 1714 return (B_FALSE); 1715 prop_result = xmlStrcmp(gotten_prop, (const xmlChar *) user_prop); 1716 xmlFree(gotten_prop); 1717 return ((prop_result == 0)); 1718 } 1719 1720 static int 1721 zonecfg_delete_filesystem_core(zone_dochandle_t handle, 1722 struct zone_fstab *tabptr) 1723 { 1724 xmlNodePtr cur = handle->zone_dh_cur; 1725 boolean_t dir_match, spec_match, raw_match, type_match; 1726 1727 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1728 if (xmlStrcmp(cur->name, DTD_ELEM_FS)) 1729 continue; 1730 dir_match = match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir); 1731 spec_match = match_prop(cur, DTD_ATTR_SPECIAL, 1732 tabptr->zone_fs_special); 1733 raw_match = match_prop(cur, DTD_ATTR_RAW, 1734 tabptr->zone_fs_raw); 1735 type_match = match_prop(cur, DTD_ATTR_TYPE, 1736 tabptr->zone_fs_type); 1737 if (dir_match && spec_match && raw_match && type_match) { 1738 xmlUnlinkNode(cur); 1739 xmlFreeNode(cur); 1740 return (Z_OK); 1741 } 1742 } 1743 return (Z_NO_RESOURCE_ID); 1744 } 1745 1746 int 1747 zonecfg_delete_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr) 1748 { 1749 int err; 1750 1751 if (tabptr == NULL) 1752 return (Z_INVAL); 1753 1754 if ((err = operation_prep(handle)) != Z_OK) 1755 return (err); 1756 1757 if ((err = zonecfg_delete_filesystem_core(handle, tabptr)) != Z_OK) 1758 return (err); 1759 1760 return (Z_OK); 1761 } 1762 1763 int 1764 zonecfg_modify_filesystem( 1765 zone_dochandle_t handle, 1766 struct zone_fstab *oldtabptr, 1767 struct zone_fstab *newtabptr) 1768 { 1769 int err; 1770 1771 if (oldtabptr == NULL || newtabptr == NULL) 1772 return (Z_INVAL); 1773 1774 if ((err = operation_prep(handle)) != Z_OK) 1775 return (err); 1776 1777 if ((err = zonecfg_delete_filesystem_core(handle, oldtabptr)) != Z_OK) 1778 return (err); 1779 1780 if ((err = zonecfg_add_filesystem_core(handle, newtabptr)) != Z_OK) 1781 return (err); 1782 1783 return (Z_OK); 1784 } 1785 1786 static int 1787 zonecfg_delete_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1788 { 1789 xmlNodePtr cur = handle->zone_dh_cur; 1790 1791 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1792 if (xmlStrcmp(cur->name, DTD_ELEM_IPD)) 1793 continue; 1794 if (match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir)) { 1795 xmlUnlinkNode(cur); 1796 xmlFreeNode(cur); 1797 return (Z_OK); 1798 } 1799 } 1800 return (Z_NO_RESOURCE_ID); 1801 } 1802 1803 int 1804 zonecfg_delete_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 1805 { 1806 int err; 1807 1808 if (tabptr == NULL) 1809 return (Z_INVAL); 1810 1811 if ((err = operation_prep(handle)) != Z_OK) 1812 return (err); 1813 1814 if ((err = zonecfg_delete_ipd_core(handle, tabptr)) != Z_OK) 1815 return (err); 1816 1817 return (Z_OK); 1818 } 1819 1820 int 1821 zonecfg_modify_ipd(zone_dochandle_t handle, struct zone_fstab *oldtabptr, 1822 struct zone_fstab *newtabptr) 1823 { 1824 int err; 1825 1826 if (oldtabptr == NULL || newtabptr == NULL) 1827 return (Z_INVAL); 1828 1829 if ((err = operation_prep(handle)) != Z_OK) 1830 return (err); 1831 1832 if ((err = zonecfg_delete_ipd_core(handle, oldtabptr)) != Z_OK) 1833 return (err); 1834 1835 if ((err = zonecfg_add_ipd_core(handle, newtabptr)) != Z_OK) 1836 return (err); 1837 1838 return (Z_OK); 1839 } 1840 1841 int 1842 zonecfg_lookup_filesystem( 1843 zone_dochandle_t handle, 1844 struct zone_fstab *tabptr) 1845 { 1846 xmlNodePtr cur, options, firstmatch; 1847 int err; 1848 char dirname[MAXPATHLEN], special[MAXPATHLEN], raw[MAXPATHLEN]; 1849 char type[FSTYPSZ]; 1850 char options_str[MAX_MNTOPT_STR]; 1851 1852 if (tabptr == NULL) 1853 return (Z_INVAL); 1854 1855 if ((err = operation_prep(handle)) != Z_OK) 1856 return (err); 1857 1858 /* 1859 * Walk the list of children looking for matches on any properties 1860 * specified in the fstab parameter. If more than one resource 1861 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return 1862 * Z_NO_RESOURCE_ID. 1863 */ 1864 cur = handle->zone_dh_cur; 1865 firstmatch = NULL; 1866 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1867 if (xmlStrcmp(cur->name, DTD_ELEM_FS)) 1868 continue; 1869 if (strlen(tabptr->zone_fs_dir) > 0) { 1870 if ((fetchprop(cur, DTD_ATTR_DIR, dirname, 1871 sizeof (dirname)) == Z_OK) && 1872 (strcmp(tabptr->zone_fs_dir, dirname) == 0)) { 1873 if (firstmatch == NULL) 1874 firstmatch = cur; 1875 else 1876 return (Z_INSUFFICIENT_SPEC); 1877 } 1878 } 1879 if (strlen(tabptr->zone_fs_special) > 0) { 1880 if ((fetchprop(cur, DTD_ATTR_SPECIAL, special, 1881 sizeof (special)) == Z_OK)) { 1882 if (strcmp(tabptr->zone_fs_special, 1883 special) == 0) { 1884 if (firstmatch == NULL) 1885 firstmatch = cur; 1886 else if (firstmatch != cur) 1887 return (Z_INSUFFICIENT_SPEC); 1888 } else { 1889 /* 1890 * If another property matched but this 1891 * one doesn't then reset firstmatch. 1892 */ 1893 if (firstmatch == cur) 1894 firstmatch = NULL; 1895 } 1896 } 1897 } 1898 if (strlen(tabptr->zone_fs_raw) > 0) { 1899 if ((fetchprop(cur, DTD_ATTR_RAW, raw, 1900 sizeof (raw)) == Z_OK)) { 1901 if (strcmp(tabptr->zone_fs_raw, raw) == 0) { 1902 if (firstmatch == NULL) 1903 firstmatch = cur; 1904 else if (firstmatch != cur) 1905 return (Z_INSUFFICIENT_SPEC); 1906 } else { 1907 /* 1908 * If another property matched but this 1909 * one doesn't then reset firstmatch. 1910 */ 1911 if (firstmatch == cur) 1912 firstmatch = NULL; 1913 } 1914 } 1915 } 1916 if (strlen(tabptr->zone_fs_type) > 0) { 1917 if ((fetchprop(cur, DTD_ATTR_TYPE, type, 1918 sizeof (type)) == Z_OK)) { 1919 if (strcmp(tabptr->zone_fs_type, type) == 0) { 1920 if (firstmatch == NULL) 1921 firstmatch = cur; 1922 else if (firstmatch != cur) 1923 return (Z_INSUFFICIENT_SPEC); 1924 } else { 1925 /* 1926 * If another property matched but this 1927 * one doesn't then reset firstmatch. 1928 */ 1929 if (firstmatch == cur) 1930 firstmatch = NULL; 1931 } 1932 } 1933 } 1934 } 1935 1936 if (firstmatch == NULL) 1937 return (Z_NO_RESOURCE_ID); 1938 1939 cur = firstmatch; 1940 1941 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 1942 sizeof (tabptr->zone_fs_dir))) != Z_OK) 1943 return (err); 1944 1945 if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special, 1946 sizeof (tabptr->zone_fs_special))) != Z_OK) 1947 return (err); 1948 1949 if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw, 1950 sizeof (tabptr->zone_fs_raw))) != Z_OK) 1951 return (err); 1952 1953 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type, 1954 sizeof (tabptr->zone_fs_type))) != Z_OK) 1955 return (err); 1956 1957 /* options are optional */ 1958 tabptr->zone_fs_options = NULL; 1959 for (options = cur->xmlChildrenNode; options != NULL; 1960 options = options->next) { 1961 if ((fetchprop(options, DTD_ATTR_NAME, options_str, 1962 sizeof (options_str)) != Z_OK)) 1963 break; 1964 if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK) 1965 break; 1966 } 1967 return (Z_OK); 1968 } 1969 1970 int 1971 zonecfg_lookup_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 1972 { 1973 xmlNodePtr cur, match; 1974 int err; 1975 char dirname[MAXPATHLEN]; 1976 1977 if (tabptr == NULL) 1978 return (Z_INVAL); 1979 1980 if ((err = operation_prep(handle)) != Z_OK) 1981 return (err); 1982 1983 /* 1984 * General algorithm: 1985 * Walk the list of children looking for matches on any properties 1986 * specified in the fstab parameter. If more than one resource 1987 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return 1988 * Z_NO_RESOURCE_ID. 1989 */ 1990 cur = handle->zone_dh_cur; 1991 match = NULL; 1992 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1993 if (xmlStrcmp(cur->name, DTD_ELEM_IPD)) 1994 continue; 1995 if (strlen(tabptr->zone_fs_dir) > 0) { 1996 if ((fetchprop(cur, DTD_ATTR_DIR, dirname, 1997 sizeof (dirname)) == Z_OK) && 1998 (strcmp(tabptr->zone_fs_dir, dirname) == 0)) { 1999 if (match == NULL) 2000 match = cur; 2001 else 2002 return (Z_INSUFFICIENT_SPEC); 2003 } 2004 } 2005 } 2006 2007 if (match == NULL) 2008 return (Z_NO_RESOURCE_ID); 2009 2010 cur = match; 2011 2012 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 2013 sizeof (tabptr->zone_fs_dir))) != Z_OK) 2014 return (err); 2015 2016 return (Z_OK); 2017 } 2018 2019 /* 2020 * Compare two IP addresses in string form. Allow for the possibility that 2021 * one might have "/<prefix-length>" at the end: allow a match on just the 2022 * IP address (or host name) part. 2023 */ 2024 2025 boolean_t 2026 zonecfg_same_net_address(char *a1, char *a2) 2027 { 2028 char *slashp, *slashp1, *slashp2; 2029 int result; 2030 2031 if (strcmp(a1, a2) == 0) 2032 return (B_TRUE); 2033 2034 /* 2035 * If neither has a slash or both do, they need to match to be 2036 * considered the same, but they did not match above, so fail. 2037 */ 2038 slashp1 = strchr(a1, '/'); 2039 slashp2 = strchr(a2, '/'); 2040 if ((slashp1 == NULL && slashp2 == NULL) || 2041 (slashp1 != NULL && slashp2 != NULL)) 2042 return (B_FALSE); 2043 2044 /* 2045 * Only one had a slash: pick that one, zero out the slash, compare 2046 * the "address only" strings, restore the slash, and return the 2047 * result of the comparison. 2048 */ 2049 slashp = (slashp1 == NULL) ? slashp2 : slashp1; 2050 *slashp = '\0'; 2051 result = strcmp(a1, a2); 2052 *slashp = '/'; 2053 return ((result == 0)); 2054 } 2055 2056 int 2057 zonecfg_valid_net_address(char *address, struct lifreq *lifr) 2058 { 2059 struct sockaddr_in *sin4; 2060 struct sockaddr_in6 *sin6; 2061 struct addrinfo hints, *result; 2062 char *slashp = strchr(address, '/'); 2063 2064 bzero(lifr, sizeof (struct lifreq)); 2065 sin4 = (struct sockaddr_in *)&lifr->lifr_addr; 2066 sin6 = (struct sockaddr_in6 *)&lifr->lifr_addr; 2067 if (slashp != NULL) 2068 *slashp = '\0'; 2069 if (inet_pton(AF_INET, address, &sin4->sin_addr) == 1) { 2070 sin4->sin_family = AF_INET; 2071 } else if (inet_pton(AF_INET6, address, &sin6->sin6_addr) == 1) { 2072 if (slashp == NULL) 2073 return (Z_IPV6_ADDR_PREFIX_LEN); 2074 sin6->sin6_family = AF_INET6; 2075 } else { 2076 /* "address" may be a host name */ 2077 (void) memset(&hints, 0, sizeof (hints)); 2078 hints.ai_family = PF_INET; 2079 if (getaddrinfo(address, NULL, &hints, &result) != 0) 2080 return (Z_BOGUS_ADDRESS); 2081 sin4->sin_family = result->ai_family; 2082 2083 (void) memcpy(&sin4->sin_addr, 2084 /* LINTED E_BAD_PTR_CAST_ALIGN */ 2085 &((struct sockaddr_in *)result->ai_addr)->sin_addr, 2086 sizeof (struct in_addr)); 2087 2088 freeaddrinfo(result); 2089 } 2090 return (Z_OK); 2091 } 2092 2093 boolean_t 2094 zonecfg_ifname_exists(sa_family_t af, char *ifname) 2095 { 2096 struct lifreq lifr; 2097 int so; 2098 int save_errno; 2099 2100 (void) memset(&lifr, 0, sizeof (lifr)); 2101 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 2102 lifr.lifr_addr.ss_family = af; 2103 if ((so = socket(af, SOCK_DGRAM, 0)) < 0) { 2104 /* Odd - can't tell if the ifname exists */ 2105 return (B_FALSE); 2106 } 2107 if (ioctl(so, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 2108 save_errno = errno; 2109 (void) close(so); 2110 errno = save_errno; 2111 return (B_FALSE); 2112 } 2113 (void) close(so); 2114 return (B_TRUE); 2115 } 2116 2117 /* 2118 * Determines if the physical interface and IP address specified by 'tabptr' 2119 * are in the zone document to which 'handle' refers. 'tabptr' must have an 2120 * interface or an address or both. If it contains both, then Z_OK is 2121 * returned iff there is exactly one match. If it contains an interface 2122 * or an address, but not both, then Z_OK is returned iff there is exactly 2123 * one entry with that interface or address. If there are multiple entries 2124 * matching the query, then Z_INSUFFICIENT_SPEC is returned. If there 2125 * are no matches, then Z_NO_RESOURCE_ID is returned. 2126 * 2127 * Errors might also be returned if the entry that exactly matches the 2128 * query lacks critical network resource information. 2129 * 2130 * If there is a single exact match, then the matching entry's physical 2131 * interface, IP address, and router information is stored in 'tabptr'. 2132 */ 2133 int 2134 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2135 { 2136 xmlNodePtr cur; 2137 xmlNodePtr firstmatch; 2138 boolean_t physfound; 2139 int err; 2140 char address[INET6_ADDRSTRLEN]; 2141 char physical[LIFNAMSIZ]; 2142 size_t addrspec; /* nonzero if tabptr has IP addr */ 2143 size_t physspec; /* nonzero if tabptr has interface */ 2144 2145 if (tabptr == NULL) 2146 return (Z_INVAL); 2147 2148 /* 2149 * zone_nwif_address and zone_nwif_physical are arrays, so no NULL 2150 * checks are necessary. 2151 */ 2152 addrspec = strlen(tabptr->zone_nwif_address); 2153 physspec = strlen(tabptr->zone_nwif_physical); 2154 assert(addrspec > 0 || physspec > 0); 2155 2156 if ((err = operation_prep(handle)) != Z_OK) 2157 return (err); 2158 2159 firstmatch = NULL; 2160 cur = handle->zone_dh_cur; 2161 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2162 /* Skip non-net elements */ 2163 if (xmlStrcmp(cur->name, DTD_ELEM_NET)) 2164 continue; 2165 2166 /* 2167 * If an interface is specified, then first check if the current 2168 * element's interface matches the query's interface. 2169 */ 2170 if (physspec > 0) { 2171 physfound = B_FALSE; 2172 if ((fetchprop(cur, DTD_ATTR_PHYSICAL, physical, 2173 sizeof (physical)) == Z_OK) && 2174 (strcmp(tabptr->zone_nwif_physical, 2175 physical) == 0)) { 2176 if (addrspec == 0) { 2177 if (firstmatch == NULL) 2178 firstmatch = cur; 2179 else 2180 return (Z_INSUFFICIENT_SPEC); 2181 } else { 2182 /* 2183 * We're also matching based on IP 2184 * address, so we can't say that the 2185 * current element matches the query 2186 * yet. Indicate that the interfaces 2187 * match. 2188 */ 2189 physfound = B_TRUE; 2190 } 2191 } 2192 } 2193 if (addrspec > 0) { 2194 if ((fetchprop(cur, DTD_ATTR_ADDRESS, address, 2195 sizeof (address)) == Z_OK) && 2196 (zonecfg_same_net_address( 2197 tabptr->zone_nwif_address, address))) { 2198 if (physspec == 0) { 2199 /* We're only matching IP addresses. */ 2200 if (firstmatch == NULL) 2201 firstmatch = cur; 2202 else 2203 return (Z_INSUFFICIENT_SPEC); 2204 } else if (physfound) { 2205 /* 2206 * Both the interfaces and the addresses 2207 * match. 2208 */ 2209 if (firstmatch == NULL) 2210 firstmatch = cur; 2211 else 2212 return (Z_INSUFFICIENT_SPEC); 2213 } 2214 } 2215 } 2216 } 2217 if (firstmatch == NULL) 2218 return (Z_NO_RESOURCE_ID); 2219 2220 cur = firstmatch; 2221 2222 if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical, 2223 sizeof (tabptr->zone_nwif_physical))) != Z_OK) 2224 return (err); 2225 2226 if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address, 2227 sizeof (tabptr->zone_nwif_address))) != Z_OK) 2228 return (err); 2229 2230 if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER, 2231 tabptr->zone_nwif_defrouter, 2232 sizeof (tabptr->zone_nwif_defrouter))) != Z_OK) 2233 return (err); 2234 2235 return (Z_OK); 2236 } 2237 2238 static int 2239 zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2240 { 2241 xmlNodePtr newnode, cur = handle->zone_dh_cur; 2242 int err; 2243 2244 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL); 2245 if ((err = newprop(newnode, DTD_ATTR_ADDRESS, 2246 tabptr->zone_nwif_address)) != Z_OK) 2247 return (err); 2248 if ((err = newprop(newnode, DTD_ATTR_PHYSICAL, 2249 tabptr->zone_nwif_physical)) != Z_OK) 2250 return (err); 2251 /* 2252 * Do not add this property when it is not set, for backwards 2253 * compatibility and because it is optional. 2254 */ 2255 if ((strlen(tabptr->zone_nwif_defrouter) > 0) && 2256 ((err = newprop(newnode, DTD_ATTR_DEFROUTER, 2257 tabptr->zone_nwif_defrouter)) != Z_OK)) 2258 return (err); 2259 return (Z_OK); 2260 } 2261 2262 int 2263 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2264 { 2265 int err; 2266 2267 if (tabptr == NULL) 2268 return (Z_INVAL); 2269 2270 if ((err = operation_prep(handle)) != Z_OK) 2271 return (err); 2272 2273 if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK) 2274 return (err); 2275 2276 return (Z_OK); 2277 } 2278 2279 static int 2280 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2281 { 2282 xmlNodePtr cur = handle->zone_dh_cur; 2283 boolean_t addr_match, phys_match; 2284 2285 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2286 if (xmlStrcmp(cur->name, DTD_ELEM_NET)) 2287 continue; 2288 2289 addr_match = match_prop(cur, DTD_ATTR_ADDRESS, 2290 tabptr->zone_nwif_address); 2291 phys_match = match_prop(cur, DTD_ATTR_PHYSICAL, 2292 tabptr->zone_nwif_physical); 2293 2294 if (addr_match && phys_match) { 2295 xmlUnlinkNode(cur); 2296 xmlFreeNode(cur); 2297 return (Z_OK); 2298 } 2299 } 2300 return (Z_NO_RESOURCE_ID); 2301 } 2302 2303 int 2304 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2305 { 2306 int err; 2307 2308 if (tabptr == NULL) 2309 return (Z_INVAL); 2310 2311 if ((err = operation_prep(handle)) != Z_OK) 2312 return (err); 2313 2314 if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK) 2315 return (err); 2316 2317 return (Z_OK); 2318 } 2319 2320 int 2321 zonecfg_modify_nwif( 2322 zone_dochandle_t handle, 2323 struct zone_nwiftab *oldtabptr, 2324 struct zone_nwiftab *newtabptr) 2325 { 2326 int err; 2327 2328 if (oldtabptr == NULL || newtabptr == NULL) 2329 return (Z_INVAL); 2330 2331 if ((err = operation_prep(handle)) != Z_OK) 2332 return (err); 2333 2334 if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK) 2335 return (err); 2336 2337 if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK) 2338 return (err); 2339 2340 return (Z_OK); 2341 } 2342 2343 int 2344 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 2345 { 2346 xmlNodePtr cur, firstmatch; 2347 int err; 2348 char match[MAXPATHLEN]; 2349 2350 if (tabptr == NULL) 2351 return (Z_INVAL); 2352 2353 if ((err = operation_prep(handle)) != Z_OK) 2354 return (err); 2355 2356 cur = handle->zone_dh_cur; 2357 firstmatch = NULL; 2358 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2359 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 2360 continue; 2361 if (strlen(tabptr->zone_dev_match) == 0) 2362 continue; 2363 2364 if ((fetchprop(cur, DTD_ATTR_MATCH, match, 2365 sizeof (match)) == Z_OK)) { 2366 if (strcmp(tabptr->zone_dev_match, 2367 match) == 0) { 2368 if (firstmatch == NULL) 2369 firstmatch = cur; 2370 else if (firstmatch != cur) 2371 return (Z_INSUFFICIENT_SPEC); 2372 } else { 2373 /* 2374 * If another property matched but this 2375 * one doesn't then reset firstmatch. 2376 */ 2377 if (firstmatch == cur) 2378 firstmatch = NULL; 2379 } 2380 } 2381 } 2382 if (firstmatch == NULL) 2383 return (Z_NO_RESOURCE_ID); 2384 2385 cur = firstmatch; 2386 2387 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match, 2388 sizeof (tabptr->zone_dev_match))) != Z_OK) 2389 return (err); 2390 2391 return (Z_OK); 2392 } 2393 2394 static int 2395 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr) 2396 { 2397 xmlNodePtr newnode, cur = handle->zone_dh_cur; 2398 int err; 2399 2400 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL); 2401 2402 if ((err = newprop(newnode, DTD_ATTR_MATCH, 2403 tabptr->zone_dev_match)) != Z_OK) 2404 return (err); 2405 2406 return (Z_OK); 2407 } 2408 2409 int 2410 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 2411 { 2412 int err; 2413 2414 if (tabptr == NULL) 2415 return (Z_INVAL); 2416 2417 if ((err = operation_prep(handle)) != Z_OK) 2418 return (err); 2419 2420 if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK) 2421 return (err); 2422 2423 return (Z_OK); 2424 } 2425 2426 static int 2427 zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr) 2428 { 2429 xmlNodePtr cur = handle->zone_dh_cur; 2430 int match_match; 2431 2432 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2433 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 2434 continue; 2435 2436 match_match = match_prop(cur, DTD_ATTR_MATCH, 2437 tabptr->zone_dev_match); 2438 2439 if (match_match) { 2440 xmlUnlinkNode(cur); 2441 xmlFreeNode(cur); 2442 return (Z_OK); 2443 } 2444 } 2445 return (Z_NO_RESOURCE_ID); 2446 } 2447 2448 int 2449 zonecfg_delete_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 2450 { 2451 int err; 2452 2453 if (tabptr == NULL) 2454 return (Z_INVAL); 2455 2456 if ((err = operation_prep(handle)) != Z_OK) 2457 return (err); 2458 2459 if ((err = zonecfg_delete_dev_core(handle, tabptr)) != Z_OK) 2460 return (err); 2461 2462 return (Z_OK); 2463 } 2464 2465 int 2466 zonecfg_modify_dev( 2467 zone_dochandle_t handle, 2468 struct zone_devtab *oldtabptr, 2469 struct zone_devtab *newtabptr) 2470 { 2471 int err; 2472 2473 if (oldtabptr == NULL || newtabptr == NULL) 2474 return (Z_INVAL); 2475 2476 if ((err = operation_prep(handle)) != Z_OK) 2477 return (err); 2478 2479 if ((err = zonecfg_delete_dev_core(handle, oldtabptr)) != Z_OK) 2480 return (err); 2481 2482 if ((err = zonecfg_add_dev_core(handle, newtabptr)) != Z_OK) 2483 return (err); 2484 2485 return (Z_OK); 2486 } 2487 2488 /* Lock to serialize all devwalks */ 2489 static pthread_mutex_t zonecfg_devwalk_lock = PTHREAD_MUTEX_INITIALIZER; 2490 /* 2491 * Global variables used to pass data from zonecfg_dev_manifest to the nftw 2492 * call-back (zonecfg_devwalk_cb). g_devwalk_data is really the void* 2493 * parameter and g_devwalk_cb is really the *cb parameter from 2494 * zonecfg_dev_manifest. 2495 */ 2496 typedef struct __g_devwalk_data *g_devwalk_data_t; 2497 static g_devwalk_data_t g_devwalk_data; 2498 static int (*g_devwalk_cb)(const char *, uid_t, gid_t, mode_t, const char *, 2499 void *); 2500 static size_t g_devwalk_skip_prefix; 2501 2502 /* 2503 * zonecfg_dev_manifest call-back function used during detach to generate the 2504 * dev info in the manifest. 2505 */ 2506 static int 2507 get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode, 2508 const char *acl, void *hdl) 2509 { 2510 zone_dochandle_t handle = (zone_dochandle_t)hdl; 2511 xmlNodePtr newnode; 2512 xmlNodePtr cur; 2513 int err; 2514 char buf[128]; 2515 2516 if ((err = operation_prep(handle)) != Z_OK) 2517 return (err); 2518 2519 cur = handle->zone_dh_cur; 2520 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL); 2521 if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK) 2522 return (err); 2523 (void) snprintf(buf, sizeof (buf), "%lu", uid); 2524 if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK) 2525 return (err); 2526 (void) snprintf(buf, sizeof (buf), "%lu", gid); 2527 if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK) 2528 return (err); 2529 (void) snprintf(buf, sizeof (buf), "%o", mode); 2530 if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK) 2531 return (err); 2532 if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK) 2533 return (err); 2534 return (Z_OK); 2535 } 2536 2537 /* 2538 * This is the nftw call-back function used by zonecfg_dev_manifest. It is 2539 * responsible for calling the actual call-back. 2540 */ 2541 /* ARGSUSED2 */ 2542 static int 2543 zonecfg_devwalk_cb(const char *path, const struct stat *st, int f, 2544 struct FTW *ftw) 2545 { 2546 acl_t *acl; 2547 char *acl_txt = NULL; 2548 2549 /* skip all but character and block devices */ 2550 if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode)) 2551 return (0); 2552 2553 if ((acl_get(path, ACL_NO_TRIVIAL, &acl) == 0) && 2554 acl != NULL) { 2555 acl_txt = acl_totext(acl, ACL_NORESOLVE); 2556 acl_free(acl); 2557 } 2558 2559 if (strlen(path) <= g_devwalk_skip_prefix) 2560 return (0); 2561 2562 g_devwalk_cb(path + g_devwalk_skip_prefix, st->st_uid, st->st_gid, 2563 st->st_mode & S_IAMB, acl_txt != NULL ? acl_txt : "", 2564 g_devwalk_data); 2565 free(acl_txt); 2566 return (0); 2567 } 2568 2569 /* 2570 * Walk the dev tree for the zone specified by hdl and call the 2571 * get_detach_dev_entry call-back function for each entry in the tree. The 2572 * call-back will be passed the name, uid, gid, mode, acl string and the 2573 * handle input parameter for each dev entry. 2574 * 2575 * Data is passed to get_detach_dev_entry through the global variables 2576 * g_devwalk_data, *g_devwalk_cb, and g_devwalk_skip_prefix. The 2577 * zonecfg_devwalk_cb function will actually call get_detach_dev_entry. 2578 */ 2579 int 2580 zonecfg_dev_manifest(zone_dochandle_t hdl) 2581 { 2582 char path[MAXPATHLEN]; 2583 int ret; 2584 2585 if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK) 2586 return (ret); 2587 2588 if (strlcat(path, "/dev", sizeof (path)) >= sizeof (path)) 2589 return (Z_TOO_BIG); 2590 2591 /* 2592 * We have to serialize all devwalks in the same process 2593 * (which should be fine), since nftw() is so badly designed. 2594 */ 2595 (void) pthread_mutex_lock(&zonecfg_devwalk_lock); 2596 2597 g_devwalk_skip_prefix = strlen(path) + 1; 2598 g_devwalk_data = (g_devwalk_data_t)hdl; 2599 g_devwalk_cb = get_detach_dev_entry; 2600 (void) nftw(path, zonecfg_devwalk_cb, 0, FTW_PHYS); 2601 2602 (void) pthread_mutex_unlock(&zonecfg_devwalk_lock); 2603 return (Z_OK); 2604 } 2605 2606 /* 2607 * Update the owner, group, mode and acl on the specified dev (inpath) for 2608 * the zone (hdl). This function can be used to fix up the dev tree after 2609 * attaching a migrated zone. 2610 */ 2611 int 2612 zonecfg_devperms_apply(zone_dochandle_t hdl, const char *inpath, uid_t owner, 2613 gid_t group, mode_t mode, const char *acltxt) 2614 { 2615 int ret; 2616 char path[MAXPATHLEN]; 2617 struct stat st; 2618 acl_t *aclp; 2619 2620 if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK) 2621 return (ret); 2622 2623 if (strlcat(path, "/dev/", sizeof (path)) >= sizeof (path)) 2624 return (Z_TOO_BIG); 2625 if (strlcat(path, inpath, sizeof (path)) >= sizeof (path)) 2626 return (Z_TOO_BIG); 2627 2628 if (stat(path, &st) == -1) 2629 return (Z_INVAL); 2630 2631 /* make sure we're only touching device nodes */ 2632 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) 2633 return (Z_INVAL); 2634 2635 if (chown(path, owner, group) == -1) 2636 return (Z_SYSTEM); 2637 2638 if (chmod(path, mode) == -1) 2639 return (Z_SYSTEM); 2640 2641 if ((acltxt == NULL) || (strcmp(acltxt, "") == 0)) 2642 return (Z_OK); 2643 2644 if (acl_fromtext(acltxt, &aclp) != 0) { 2645 errno = EINVAL; 2646 return (Z_SYSTEM); 2647 } 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 (strlen(tabptr->zone_rctl_name) == 0) 2998 return (Z_INVAL); 2999 3000 if ((err = operation_prep(handle)) != Z_OK) 3001 return (err); 3002 3003 cur = handle->zone_dh_cur; 3004 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 3005 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 3006 continue; 3007 if ((fetchprop(cur, DTD_ATTR_NAME, savedname, 3008 sizeof (savedname)) == Z_OK) && 3009 (strcmp(savedname, tabptr->zone_rctl_name) == 0)) { 3010 tabptr->zone_rctl_valptr = NULL; 3011 for (val = cur->xmlChildrenNode; val != NULL; 3012 val = val->next) { 3013 valptr = (struct zone_rctlvaltab *)malloc( 3014 sizeof (struct zone_rctlvaltab)); 3015 if (valptr == NULL) 3016 return (Z_NOMEM); 3017 if ((fetchprop(val, DTD_ATTR_PRIV, 3018 valptr->zone_rctlval_priv, 3019 sizeof (valptr->zone_rctlval_priv)) != 3020 Z_OK)) 3021 break; 3022 if ((fetchprop(val, DTD_ATTR_LIMIT, 3023 valptr->zone_rctlval_limit, 3024 sizeof (valptr->zone_rctlval_limit)) != 3025 Z_OK)) 3026 break; 3027 if ((fetchprop(val, DTD_ATTR_ACTION, 3028 valptr->zone_rctlval_action, 3029 sizeof (valptr->zone_rctlval_action)) != 3030 Z_OK)) 3031 break; 3032 if (zonecfg_add_rctl_value(tabptr, valptr) != 3033 Z_OK) 3034 break; 3035 } 3036 return (Z_OK); 3037 } 3038 } 3039 return (Z_NO_RESOURCE_ID); 3040 } 3041 3042 static int 3043 zonecfg_add_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr) 3044 { 3045 xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode; 3046 struct zone_rctlvaltab *valptr; 3047 int err; 3048 3049 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_RCTL, NULL); 3050 err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_rctl_name); 3051 if (err != Z_OK) 3052 return (err); 3053 for (valptr = tabptr->zone_rctl_valptr; valptr != NULL; 3054 valptr = valptr->zone_rctlval_next) { 3055 valnode = xmlNewTextChild(newnode, NULL, 3056 DTD_ELEM_RCTLVALUE, NULL); 3057 err = newprop(valnode, DTD_ATTR_PRIV, 3058 valptr->zone_rctlval_priv); 3059 if (err != Z_OK) 3060 return (err); 3061 err = newprop(valnode, DTD_ATTR_LIMIT, 3062 valptr->zone_rctlval_limit); 3063 if (err != Z_OK) 3064 return (err); 3065 err = newprop(valnode, DTD_ATTR_ACTION, 3066 valptr->zone_rctlval_action); 3067 if (err != Z_OK) 3068 return (err); 3069 } 3070 return (Z_OK); 3071 } 3072 3073 int 3074 zonecfg_add_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 3075 { 3076 int err; 3077 3078 if (tabptr == NULL) 3079 return (Z_INVAL); 3080 3081 if ((err = operation_prep(handle)) != Z_OK) 3082 return (err); 3083 3084 if ((err = zonecfg_add_rctl_core(handle, tabptr)) != Z_OK) 3085 return (err); 3086 3087 return (Z_OK); 3088 } 3089 3090 static int 3091 zonecfg_delete_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr) 3092 { 3093 xmlNodePtr cur = handle->zone_dh_cur; 3094 xmlChar *savedname; 3095 int name_result; 3096 3097 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 3098 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 3099 continue; 3100 3101 savedname = xmlGetProp(cur, DTD_ATTR_NAME); 3102 if (savedname == NULL) /* shouldn't happen */ 3103 continue; 3104 name_result = xmlStrcmp(savedname, 3105 (const xmlChar *) tabptr->zone_rctl_name); 3106 xmlFree(savedname); 3107 3108 if (name_result == 0) { 3109 xmlUnlinkNode(cur); 3110 xmlFreeNode(cur); 3111 return (Z_OK); 3112 } 3113 } 3114 return (Z_NO_RESOURCE_ID); 3115 } 3116 3117 int 3118 zonecfg_delete_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 3119 { 3120 int err; 3121 3122 if (tabptr == NULL) 3123 return (Z_INVAL); 3124 3125 if ((err = operation_prep(handle)) != Z_OK) 3126 return (err); 3127 3128 if ((err = zonecfg_delete_rctl_core(handle, tabptr)) != Z_OK) 3129 return (err); 3130 3131 return (Z_OK); 3132 } 3133 3134 int 3135 zonecfg_modify_rctl( 3136 zone_dochandle_t handle, 3137 struct zone_rctltab *oldtabptr, 3138 struct zone_rctltab *newtabptr) 3139 { 3140 int err; 3141 3142 if (oldtabptr == NULL || newtabptr == NULL) 3143 return (Z_INVAL); 3144 3145 if ((err = operation_prep(handle)) != Z_OK) 3146 return (err); 3147 3148 if ((err = zonecfg_delete_rctl_core(handle, oldtabptr)) != Z_OK) 3149 return (err); 3150 3151 if ((err = zonecfg_add_rctl_core(handle, newtabptr)) != Z_OK) 3152 return (err); 3153 3154 return (Z_OK); 3155 } 3156 3157 int 3158 zonecfg_add_rctl_value( 3159 struct zone_rctltab *tabptr, 3160 struct zone_rctlvaltab *valtabptr) 3161 { 3162 struct zone_rctlvaltab *last, *old, *new; 3163 rctlblk_t *rctlblk = alloca(rctlblk_size()); 3164 3165 last = tabptr->zone_rctl_valptr; 3166 for (old = last; old != NULL; old = old->zone_rctlval_next) 3167 last = old; /* walk to the end of the list */ 3168 new = valtabptr; /* alloc'd by caller */ 3169 new->zone_rctlval_next = NULL; 3170 if (zonecfg_construct_rctlblk(valtabptr, rctlblk) != Z_OK) 3171 return (Z_INVAL); 3172 if (!zonecfg_valid_rctlblk(rctlblk)) 3173 return (Z_INVAL); 3174 if (last == NULL) 3175 tabptr->zone_rctl_valptr = new; 3176 else 3177 last->zone_rctlval_next = new; 3178 return (Z_OK); 3179 } 3180 3181 int 3182 zonecfg_remove_rctl_value( 3183 struct zone_rctltab *tabptr, 3184 struct zone_rctlvaltab *valtabptr) 3185 { 3186 struct zone_rctlvaltab *last, *this, *next; 3187 3188 last = tabptr->zone_rctl_valptr; 3189 for (this = last; this != NULL; this = this->zone_rctlval_next) { 3190 if (strcmp(this->zone_rctlval_priv, 3191 valtabptr->zone_rctlval_priv) == 0 && 3192 strcmp(this->zone_rctlval_limit, 3193 valtabptr->zone_rctlval_limit) == 0 && 3194 strcmp(this->zone_rctlval_action, 3195 valtabptr->zone_rctlval_action) == 0) { 3196 next = this->zone_rctlval_next; 3197 if (this == tabptr->zone_rctl_valptr) 3198 tabptr->zone_rctl_valptr = next; 3199 else 3200 last->zone_rctlval_next = next; 3201 free(this); 3202 return (Z_OK); 3203 } else 3204 last = this; 3205 } 3206 return (Z_NO_PROPERTY_ID); 3207 } 3208 3209 void 3210 zonecfg_set_swinv(zone_dochandle_t handle) 3211 { 3212 handle->zone_dh_sw_inv = B_TRUE; 3213 } 3214 3215 /* 3216 * Add the pkg to the sw inventory on the handle. 3217 */ 3218 int 3219 zonecfg_add_pkg(zone_dochandle_t handle, char *name, char *version) 3220 { 3221 xmlNodePtr newnode; 3222 xmlNodePtr cur; 3223 int err; 3224 3225 if ((err = operation_prep(handle)) != Z_OK) 3226 return (err); 3227 3228 cur = handle->zone_dh_cur; 3229 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL); 3230 if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK) 3231 return (err); 3232 if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK) 3233 return (err); 3234 return (Z_OK); 3235 } 3236 3237 int 3238 zonecfg_add_patch(zone_dochandle_t handle, char *id, void **pnode) 3239 { 3240 xmlNodePtr node = (xmlNodePtr)*pnode; 3241 xmlNodePtr cur; 3242 int err; 3243 3244 if ((err = operation_prep(handle)) != Z_OK) 3245 return (err); 3246 3247 cur = handle->zone_dh_cur; 3248 node = xmlNewTextChild(cur, NULL, DTD_ELEM_PATCH, NULL); 3249 if ((err = newprop(node, DTD_ATTR_ID, id)) != Z_OK) 3250 return (err); 3251 *pnode = (void *)node; 3252 return (Z_OK); 3253 } 3254 3255 int 3256 zonecfg_add_patch_obs(char *id, void *cur) 3257 { 3258 xmlNodePtr node; 3259 int err; 3260 3261 node = xmlNewTextChild((xmlNodePtr)cur, NULL, DTD_ELEM_OBSOLETES, NULL); 3262 if ((err = newprop(node, DTD_ATTR_ID, id)) != Z_OK) 3263 return (err); 3264 return (Z_OK); 3265 } 3266 3267 char * 3268 zonecfg_strerror(int errnum) 3269 { 3270 switch (errnum) { 3271 case Z_OK: 3272 return (dgettext(TEXT_DOMAIN, "OK")); 3273 case Z_EMPTY_DOCUMENT: 3274 return (dgettext(TEXT_DOMAIN, "Empty document")); 3275 case Z_WRONG_DOC_TYPE: 3276 return (dgettext(TEXT_DOMAIN, "Wrong document type")); 3277 case Z_BAD_PROPERTY: 3278 return (dgettext(TEXT_DOMAIN, "Bad document property")); 3279 case Z_TEMP_FILE: 3280 return (dgettext(TEXT_DOMAIN, 3281 "Problem creating temporary file")); 3282 case Z_SAVING_FILE: 3283 return (dgettext(TEXT_DOMAIN, "Problem saving file")); 3284 case Z_NO_ENTRY: 3285 return (dgettext(TEXT_DOMAIN, "No such entry")); 3286 case Z_BOGUS_ZONE_NAME: 3287 return (dgettext(TEXT_DOMAIN, "Bogus zone name")); 3288 case Z_REQD_RESOURCE_MISSING: 3289 return (dgettext(TEXT_DOMAIN, "Required resource missing")); 3290 case Z_REQD_PROPERTY_MISSING: 3291 return (dgettext(TEXT_DOMAIN, "Required property missing")); 3292 case Z_BAD_HANDLE: 3293 return (dgettext(TEXT_DOMAIN, "Bad handle")); 3294 case Z_NOMEM: 3295 return (dgettext(TEXT_DOMAIN, "Out of memory")); 3296 case Z_INVAL: 3297 return (dgettext(TEXT_DOMAIN, "Invalid argument")); 3298 case Z_ACCES: 3299 return (dgettext(TEXT_DOMAIN, "Permission denied")); 3300 case Z_TOO_BIG: 3301 return (dgettext(TEXT_DOMAIN, "Argument list too long")); 3302 case Z_MISC_FS: 3303 return (dgettext(TEXT_DOMAIN, 3304 "Miscellaneous file system error")); 3305 case Z_NO_ZONE: 3306 return (dgettext(TEXT_DOMAIN, "No such zone configured")); 3307 case Z_NO_RESOURCE_TYPE: 3308 return (dgettext(TEXT_DOMAIN, "No such resource type")); 3309 case Z_NO_RESOURCE_ID: 3310 return (dgettext(TEXT_DOMAIN, "No such resource with that id")); 3311 case Z_NO_PROPERTY_TYPE: 3312 return (dgettext(TEXT_DOMAIN, "No such property type")); 3313 case Z_NO_PROPERTY_ID: 3314 return (dgettext(TEXT_DOMAIN, "No such property with that id")); 3315 case Z_BAD_ZONE_STATE: 3316 return (dgettext(TEXT_DOMAIN, 3317 "Zone state is invalid for the requested operation")); 3318 case Z_INVALID_DOCUMENT: 3319 return (dgettext(TEXT_DOMAIN, "Invalid document")); 3320 case Z_NAME_IN_USE: 3321 return (dgettext(TEXT_DOMAIN, "Zone name already in use")); 3322 case Z_NO_SUCH_ID: 3323 return (dgettext(TEXT_DOMAIN, "No such zone ID")); 3324 case Z_UPDATING_INDEX: 3325 return (dgettext(TEXT_DOMAIN, "Problem updating index file")); 3326 case Z_LOCKING_FILE: 3327 return (dgettext(TEXT_DOMAIN, "Locking index file")); 3328 case Z_UNLOCKING_FILE: 3329 return (dgettext(TEXT_DOMAIN, "Unlocking index file")); 3330 case Z_INSUFFICIENT_SPEC: 3331 return (dgettext(TEXT_DOMAIN, "Insufficient specification")); 3332 case Z_RESOLVED_PATH: 3333 return (dgettext(TEXT_DOMAIN, "Resolved path mismatch")); 3334 case Z_IPV6_ADDR_PREFIX_LEN: 3335 return (dgettext(TEXT_DOMAIN, 3336 "IPv6 address missing required prefix length")); 3337 case Z_BOGUS_ADDRESS: 3338 return (dgettext(TEXT_DOMAIN, 3339 "Neither an IPv4 nor an IPv6 address nor a host name")); 3340 case Z_PRIV_PROHIBITED: 3341 return (dgettext(TEXT_DOMAIN, 3342 "Specified privilege is prohibited")); 3343 case Z_PRIV_REQUIRED: 3344 return (dgettext(TEXT_DOMAIN, 3345 "Required privilege is missing")); 3346 case Z_PRIV_UNKNOWN: 3347 return (dgettext(TEXT_DOMAIN, 3348 "Specified privilege is unknown")); 3349 case Z_BRAND_ERROR: 3350 return (dgettext(TEXT_DOMAIN, 3351 "Brand-specific error")); 3352 case Z_INCOMPATIBLE: 3353 return (dgettext(TEXT_DOMAIN, "Incompatible settings")); 3354 case Z_ALIAS_DISALLOW: 3355 return (dgettext(TEXT_DOMAIN, 3356 "An incompatible rctl already exists for this property")); 3357 case Z_CLEAR_DISALLOW: 3358 return (dgettext(TEXT_DOMAIN, 3359 "Clearing this property is not allowed")); 3360 case Z_POOL: 3361 return (dgettext(TEXT_DOMAIN, "libpool(3LIB) error")); 3362 case Z_POOLS_NOT_ACTIVE: 3363 return (dgettext(TEXT_DOMAIN, "Pools facility not active; " 3364 "zone will not be bound to pool")); 3365 case Z_POOL_ENABLE: 3366 return (dgettext(TEXT_DOMAIN, 3367 "Could not enable pools facility")); 3368 case Z_NO_POOL: 3369 return (dgettext(TEXT_DOMAIN, 3370 "Pool not found; using default pool")); 3371 case Z_POOL_CREATE: 3372 return (dgettext(TEXT_DOMAIN, 3373 "Could not create a temporary pool")); 3374 case Z_POOL_BIND: 3375 return (dgettext(TEXT_DOMAIN, "Could not bind zone to pool")); 3376 case Z_SYSTEM: 3377 return (strerror(errno)); 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