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