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