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 <sys/stat.h> 37 #include <assert.h> 38 #include <libgen.h> 39 #include <libintl.h> 40 #include <alloca.h> 41 #include <ctype.h> 42 #include <sys/mntio.h> 43 #include <sys/mnttab.h> 44 #include <sys/types.h> 45 #include <sys/nvpair.h> 46 #include <sys/acl.h> 47 #include <ftw.h> 48 49 #include <arpa/inet.h> 50 #include <netdb.h> 51 52 #include <libxml/xmlmemory.h> 53 #include <libxml/parser.h> 54 55 #include <libdevinfo.h> 56 #include <uuid/uuid.h> 57 58 #include <dirent.h> 59 60 #include <libzonecfg.h> 61 #include "zonecfg_impl.h" 62 63 64 #define _PATH_TMPFILE "/zonecfg.XXXXXX" 65 #define ZONE_CB_RETRY_COUNT 10 66 #define ZONE_EVENT_PING_SUBCLASS "ping" 67 #define ZONE_EVENT_PING_PUBLISHER "solaris" 68 69 /* Hard-code the DTD element/attribute/entity names just once, here. */ 70 #define DTD_ELEM_ATTR (const xmlChar *) "attr" 71 #define DTD_ELEM_COMMENT (const xmlChar *) "comment" 72 #define DTD_ELEM_DEVICE (const xmlChar *) "device" 73 #define DTD_ELEM_FS (const xmlChar *) "filesystem" 74 #define DTD_ELEM_FSOPTION (const xmlChar *) "fsoption" 75 #define DTD_ELEM_IPD (const xmlChar *) "inherited-pkg-dir" 76 #define DTD_ELEM_NET (const xmlChar *) "network" 77 #define DTD_ELEM_RCTL (const xmlChar *) "rctl" 78 #define DTD_ELEM_RCTLVALUE (const xmlChar *) "rctl-value" 79 #define DTD_ELEM_ZONE (const xmlChar *) "zone" 80 #define DTD_ELEM_DATASET (const xmlChar *) "dataset" 81 #define DTD_ELEM_PACKAGE (const xmlChar *) "package" 82 #define DTD_ELEM_PATCH (const xmlChar *) "patch" 83 #define DTD_ELEM_OBSOLETES (const xmlChar *) "obsoletes" 84 #define DTD_ELEM_INCOMPATIBLE (const xmlChar *) "incompatible" 85 #define DTD_ELEM_DEV_PERM (const xmlChar *) "dev-perm" 86 87 #define DTD_ATTR_ACTION (const xmlChar *) "action" 88 #define DTD_ATTR_ADDRESS (const xmlChar *) "address" 89 #define DTD_ATTR_AUTOBOOT (const xmlChar *) "autoboot" 90 #define DTD_ATTR_DIR (const xmlChar *) "directory" 91 #define DTD_ATTR_LIMIT (const xmlChar *) "limit" 92 #define DTD_ATTR_LIMITPRIV (const xmlChar *) "limitpriv" 93 #define DTD_ATTR_BOOTARGS (const xmlChar *) "bootargs" 94 #define DTD_ATTR_MATCH (const xmlChar *) "match" 95 #define DTD_ATTR_NAME (const xmlChar *) "name" 96 #define DTD_ATTR_PHYSICAL (const xmlChar *) "physical" 97 #define DTD_ATTR_POOL (const xmlChar *) "pool" 98 #define DTD_ATTR_PRIV (const xmlChar *) "priv" 99 #define DTD_ATTR_RAW (const xmlChar *) "raw" 100 #define DTD_ATTR_SPECIAL (const xmlChar *) "special" 101 #define DTD_ATTR_TYPE (const xmlChar *) "type" 102 #define DTD_ATTR_VALUE (const xmlChar *) "value" 103 #define DTD_ATTR_ZONEPATH (const xmlChar *) "zonepath" 104 #define DTD_ATTR_VERSION (const xmlChar *) "version" 105 #define DTD_ATTR_ID (const xmlChar *) "id" 106 #define DTD_ATTR_UID (const xmlChar *) "uid" 107 #define DTD_ATTR_GID (const xmlChar *) "gid" 108 #define DTD_ATTR_MODE (const xmlChar *) "mode" 109 #define DTD_ATTR_ACL (const xmlChar *) "acl" 110 111 #define DTD_ENTITY_BOOLEAN "boolean" 112 #define DTD_ENTITY_DEVPATH "devpath" 113 #define DTD_ENTITY_DRIVER "driver" 114 #define DTD_ENTITY_DRVMIN "drv_min" 115 #define DTD_ENTITY_FALSE "false" 116 #define DTD_ENTITY_INT "int" 117 #define DTD_ENTITY_STRING "string" 118 #define DTD_ENTITY_TRUE "true" 119 #define DTD_ENTITY_UINT "uint" 120 121 #define DTD_ENTITY_BOOL_LEN 6 /* "false" */ 122 123 #define DETACHED "SUNWdetached.xml" 124 #define ATTACH_FORCED "SUNWattached.xml" 125 #define PKG_PATH "/var/sadm/pkg" 126 #define CONTENTS_FILE "/var/sadm/install/contents" 127 #define SUNW_PKG_ALL_ZONES "SUNW_PKG_ALLZONES=true\n" 128 #define SUNW_PKG_THIS_ZONE "SUNW_PKG_THISZONE=true\n" 129 #define VERSION "VERSION=" 130 #define PATCHLIST "PATCHLIST=" 131 #define PATCHINFO "PATCH_INFO_" 132 #define PKGINFO_RD_LEN 128 133 134 struct zone_dochandle { 135 char *zone_dh_rootdir; 136 xmlDocPtr zone_dh_doc; 137 xmlNodePtr zone_dh_cur; 138 xmlNodePtr zone_dh_top; 139 boolean_t zone_dh_newzone; 140 boolean_t zone_dh_snapshot; 141 boolean_t zone_dh_sw_inv; 142 char zone_dh_delete_name[ZONENAME_MAX]; 143 }; 144 145 struct znotify { 146 void * zn_private; 147 evchan_t *zn_eventchan; 148 int (*zn_callback)(const char *zonename, zoneid_t zid, 149 const char *newstate, const char *oldstate, hrtime_t when, void *p); 150 pthread_mutex_t zn_mutex; 151 pthread_cond_t zn_cond; 152 pthread_mutex_t zn_bigmutex; 153 volatile enum {ZN_UNLOCKED, ZN_LOCKED, ZN_PING_INFLIGHT, 154 ZN_PING_RECEIVED} zn_state; 155 char zn_subscriber_id[MAX_SUBID_LEN]; 156 volatile boolean_t zn_failed; 157 int zn_failure_count; 158 }; 159 160 struct zone_pkginfo { 161 boolean_t zpi_all_zones; 162 boolean_t zpi_this_zone; 163 int zpi_patch_cnt; 164 char *zpi_version; 165 char **zpi_patchinfo; 166 }; 167 168 char *zonecfg_root = ""; 169 170 /* 171 * For functions which return int, which is most of the functions herein, 172 * the return values should be from the Z_foo set defined in <libzonecfg.h>. 173 * In some instances, we take pains mapping some libc errno values to Z_foo 174 * values from this set. 175 */ 176 177 /* 178 * Set the root (/) path for all zonecfg configuration files. This is a 179 * private interface used by Live Upgrade extensions to access zone 180 * configuration inside mounted alternate boot environments. 181 */ 182 void 183 zonecfg_set_root(const char *rootpath) 184 { 185 if (*zonecfg_root != '\0') 186 free(zonecfg_root); 187 if (rootpath == NULL || rootpath[0] == '\0' || rootpath[1] == '\0' || 188 (zonecfg_root = strdup(rootpath)) == NULL) 189 zonecfg_root = ""; 190 } 191 192 const char * 193 zonecfg_get_root(void) 194 { 195 return (zonecfg_root); 196 } 197 198 boolean_t 199 zonecfg_in_alt_root(void) 200 { 201 return (*zonecfg_root != '\0'); 202 } 203 204 /* 205 * Callers of the _file_path() functions are expected to have the second 206 * parameter be a (char foo[MAXPATHLEN]). 207 */ 208 209 static boolean_t 210 config_file_path(const char *zonename, char *answer) 211 { 212 return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root, 213 ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN); 214 } 215 216 static boolean_t 217 snap_file_path(const char *zonename, char *answer) 218 { 219 return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml", 220 zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN); 221 } 222 223 /*ARGSUSED*/ 224 static void 225 zonecfg_error_func(void *ctx, const char *msg, ...) 226 { 227 /* 228 * This function does nothing by design. Its purpose is to prevent 229 * libxml from dumping unwanted messages to stdout/stderr. 230 */ 231 } 232 233 zone_dochandle_t 234 zonecfg_init_handle(void) 235 { 236 zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle)); 237 if (handle == NULL) { 238 errno = Z_NOMEM; 239 return (NULL); 240 } 241 242 /* generic libxml initialization */ 243 xmlLineNumbersDefault(1); 244 xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS; 245 xmlDoValidityCheckingDefaultValue = 1; 246 (void) xmlKeepBlanksDefault(0); 247 xmlGetWarningsDefaultValue = 0; 248 xmlSetGenericErrorFunc(NULL, zonecfg_error_func); 249 250 return (handle); 251 } 252 253 int 254 zonecfg_check_handle(zone_dochandle_t handle) 255 { 256 if (handle == NULL || handle->zone_dh_doc == NULL) 257 return (Z_BAD_HANDLE); 258 return (Z_OK); 259 } 260 261 void 262 zonecfg_fini_handle(zone_dochandle_t handle) 263 { 264 if (zonecfg_check_handle(handle) == Z_OK) 265 xmlFreeDoc(handle->zone_dh_doc); 266 if (handle != NULL) 267 free(handle); 268 } 269 270 static int 271 zonecfg_destroy_impl(char *filename) 272 { 273 if (unlink(filename) == -1) { 274 if (errno == EACCES) 275 return (Z_ACCES); 276 if (errno == ENOENT) 277 return (Z_NO_ZONE); 278 return (Z_MISC_FS); 279 } 280 return (Z_OK); 281 } 282 283 int 284 zonecfg_destroy(const char *zonename, boolean_t force) 285 { 286 char path[MAXPATHLEN]; 287 struct zoneent ze; 288 int err, state_err; 289 zone_state_t state; 290 291 if (!config_file_path(zonename, path)) 292 return (Z_MISC_FS); 293 294 state_err = zone_get_state((char *)zonename, &state); 295 err = access(path, W_OK); 296 297 /* 298 * If there is no file, and no index entry, reliably indicate that no 299 * such zone exists. 300 */ 301 if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT)) 302 return (Z_NO_ZONE); 303 304 /* 305 * Handle any other filesystem related errors (except if the XML 306 * file is missing, which we treat silently), unless we're forcing, 307 * in which case we plow on. 308 */ 309 if (err == -1 && errno != ENOENT) { 310 if (errno == EACCES) 311 return (Z_ACCES); 312 else if (!force) 313 return (Z_MISC_FS); 314 } 315 316 if (state > ZONE_STATE_INSTALLED) 317 return (Z_BAD_ZONE_STATE); 318 319 if (!force && state > ZONE_STATE_CONFIGURED) 320 return (Z_BAD_ZONE_STATE); 321 322 /* 323 * Index deletion succeeds even if the entry doesn't exist. So this 324 * will fail only if we've had some more severe problem. 325 */ 326 bzero(&ze, sizeof (ze)); 327 (void) strlcpy(ze.zone_name, zonename, sizeof (ze.zone_name)); 328 if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK) 329 if (!force) 330 return (err); 331 332 err = zonecfg_destroy_impl(path); 333 334 /* 335 * Treat failure to find the XML file silently, since, well, it's 336 * gone, and with the index file cleaned up, we're done. 337 */ 338 if (err == Z_OK || err == Z_NO_ZONE) 339 return (Z_OK); 340 return (err); 341 } 342 343 int 344 zonecfg_destroy_snapshot(const char *zonename) 345 { 346 char path[MAXPATHLEN]; 347 348 if (!snap_file_path(zonename, path)) 349 return (Z_MISC_FS); 350 return (zonecfg_destroy_impl(path)); 351 } 352 353 static int 354 getroot(zone_dochandle_t handle, xmlNodePtr *root) 355 { 356 if (zonecfg_check_handle(handle) == Z_BAD_HANDLE) 357 return (Z_BAD_HANDLE); 358 359 *root = xmlDocGetRootElement(handle->zone_dh_doc); 360 361 if (*root == NULL) 362 return (Z_EMPTY_DOCUMENT); 363 364 if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE)) 365 return (Z_WRONG_DOC_TYPE); 366 367 return (Z_OK); 368 } 369 370 static int 371 operation_prep(zone_dochandle_t handle) 372 { 373 xmlNodePtr root; 374 int err; 375 376 if ((err = getroot(handle, &root)) != 0) 377 return (err); 378 379 handle->zone_dh_cur = root; 380 handle->zone_dh_top = root; 381 return (Z_OK); 382 } 383 384 static int 385 fetchprop(xmlNodePtr cur, const xmlChar *propname, char *dst, size_t dstsize) 386 { 387 xmlChar *property; 388 size_t srcsize; 389 390 if ((property = xmlGetProp(cur, propname)) == NULL) 391 return (Z_BAD_PROPERTY); 392 srcsize = strlcpy(dst, (char *)property, dstsize); 393 xmlFree(property); 394 if (srcsize >= dstsize) 395 return (Z_TOO_BIG); 396 return (Z_OK); 397 } 398 399 static int 400 fetch_alloc_prop(xmlNodePtr cur, const xmlChar *propname, char **dst) 401 { 402 xmlChar *property; 403 404 if ((property = xmlGetProp(cur, propname)) == NULL) 405 return (Z_BAD_PROPERTY); 406 if ((*dst = strdup((char *)property)) == NULL) { 407 xmlFree(property); 408 return (Z_NOMEM); 409 } 410 xmlFree(property); 411 return (Z_OK); 412 } 413 414 static int 415 getrootattr(zone_dochandle_t handle, const xmlChar *propname, 416 char *propval, size_t propsize) 417 { 418 xmlNodePtr root; 419 int err; 420 421 if ((err = getroot(handle, &root)) != 0) 422 return (err); 423 424 return (fetchprop(root, propname, propval, propsize)); 425 } 426 427 static int 428 get_alloc_rootattr(zone_dochandle_t handle, const xmlChar *propname, 429 char **propval) 430 { 431 xmlNodePtr root; 432 int err; 433 434 if ((err = getroot(handle, &root)) != 0) 435 return (err); 436 437 return (fetch_alloc_prop(root, propname, propval)); 438 } 439 440 static int 441 setrootattr(zone_dochandle_t handle, const xmlChar *propname, 442 const char *propval) 443 { 444 int err; 445 xmlNodePtr root; 446 447 if (propval == NULL) 448 return (Z_INVAL); 449 450 if ((err = getroot(handle, &root)) != Z_OK) 451 return (err); 452 453 if (xmlSetProp(root, propname, (const xmlChar *) propval) == NULL) 454 return (Z_INVAL); 455 return (Z_OK); 456 } 457 458 static void 459 addcomment(zone_dochandle_t handle, const char *comment) 460 { 461 xmlNodePtr node; 462 node = xmlNewComment((xmlChar *) comment); 463 464 if (node != NULL) 465 (void) xmlAddPrevSibling(handle->zone_dh_top, node); 466 } 467 468 static void 469 stripcomments(zone_dochandle_t handle) 470 { 471 xmlDocPtr top; 472 xmlNodePtr child, next; 473 474 top = handle->zone_dh_doc; 475 for (child = top->xmlChildrenNode; child != NULL; child = next) { 476 next = child->next; 477 if (child->name == NULL) 478 continue; 479 if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) { 480 next = child->next; 481 xmlUnlinkNode(child); 482 xmlFreeNode(child); 483 } 484 } 485 } 486 487 static void 488 strip_sw_inv(zone_dochandle_t handle) 489 { 490 xmlNodePtr root, child, next; 491 492 root = xmlDocGetRootElement(handle->zone_dh_doc); 493 for (child = root->xmlChildrenNode; child != NULL; child = next) { 494 next = child->next; 495 if (child->name == NULL) 496 continue; 497 if (xmlStrcmp(child->name, DTD_ELEM_PACKAGE) == 0 || 498 xmlStrcmp(child->name, DTD_ELEM_PATCH) == 0) { 499 next = child->next; 500 xmlUnlinkNode(child); 501 xmlFreeNode(child); 502 } 503 } 504 } 505 506 static int 507 zonecfg_get_handle_impl(const char *zonename, const char *filename, 508 zone_dochandle_t handle) 509 { 510 xmlValidCtxtPtr cvp; 511 struct stat statbuf; 512 int valid; 513 514 if (zonename == NULL) 515 return (Z_NO_ZONE); 516 if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) { 517 /* distinguish file not found vs. found but not parsed */ 518 if (stat(filename, &statbuf) == 0) 519 return (Z_INVALID_DOCUMENT); 520 return (Z_NO_ZONE); 521 } 522 if ((cvp = xmlNewValidCtxt()) == NULL) 523 return (Z_NOMEM); 524 cvp->error = zonecfg_error_func; 525 cvp->warning = zonecfg_error_func; 526 valid = xmlValidateDocument(cvp, handle->zone_dh_doc); 527 xmlFreeValidCtxt(cvp); 528 if (valid == 0) 529 return (Z_INVALID_DOCUMENT); 530 531 /* delete any comments such as inherited Sun copyright / ident str */ 532 stripcomments(handle); 533 return (Z_OK); 534 } 535 536 int 537 zonecfg_get_handle(const char *zonename, zone_dochandle_t handle) 538 { 539 char path[MAXPATHLEN]; 540 541 if (!config_file_path(zonename, path)) 542 return (Z_MISC_FS); 543 handle->zone_dh_newzone = B_FALSE; 544 545 return (zonecfg_get_handle_impl(zonename, path, handle)); 546 } 547 548 int 549 zonecfg_get_attach_handle(const char *path, const char *zonename, 550 boolean_t preserve_sw, zone_dochandle_t handle) 551 { 552 char migpath[MAXPATHLEN]; 553 int err; 554 struct stat buf; 555 556 if (snprintf(migpath, sizeof (migpath), "%s/root", path) >= 557 sizeof (migpath)) 558 return (Z_NOMEM); 559 560 if (stat(migpath, &buf) == -1 || !S_ISDIR(buf.st_mode)) 561 return (Z_NO_ZONE); 562 563 if (snprintf(migpath, sizeof (migpath), "%s/%s", path, DETACHED) >= 564 sizeof (migpath)) 565 return (Z_NOMEM); 566 567 if ((err = zonecfg_get_handle_impl(zonename, migpath, handle)) != Z_OK) 568 return (err); 569 570 if (!preserve_sw) 571 strip_sw_inv(handle); 572 573 handle->zone_dh_newzone = B_TRUE; 574 if ((err = setrootattr(handle, DTD_ATTR_ZONEPATH, path)) != Z_OK) 575 return (err); 576 577 return (setrootattr(handle, DTD_ATTR_NAME, zonename)); 578 } 579 580 int 581 zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle) 582 { 583 char path[MAXPATHLEN]; 584 585 if (!snap_file_path(zonename, path)) 586 return (Z_MISC_FS); 587 handle->zone_dh_newzone = B_FALSE; 588 return (zonecfg_get_handle_impl(zonename, path, handle)); 589 } 590 591 int 592 zonecfg_get_template_handle(const char *template, const char *zonename, 593 zone_dochandle_t handle) 594 { 595 char path[MAXPATHLEN]; 596 int err; 597 598 if (!config_file_path(template, path)) 599 return (Z_MISC_FS); 600 601 if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK) 602 return (err); 603 handle->zone_dh_newzone = B_TRUE; 604 return (setrootattr(handle, DTD_ATTR_NAME, zonename)); 605 } 606 607 /* 608 * Initialize two handles from the manifest read on fd. The rem_handle 609 * is initialized from the input file, including the sw inventory. The 610 * local_handle is initialized with the same zone configuration but with 611 * no sw inventory. 612 */ 613 int 614 zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle, 615 zone_dochandle_t rem_handle) 616 { 617 xmlValidCtxtPtr cvp; 618 int valid; 619 620 /* load the manifest into the handle for the remote system */ 621 if ((rem_handle->zone_dh_doc = xmlReadFd(fd, NULL, NULL, 0)) == NULL) { 622 return (Z_INVALID_DOCUMENT); 623 } 624 if ((cvp = xmlNewValidCtxt()) == NULL) 625 return (Z_NOMEM); 626 cvp->error = zonecfg_error_func; 627 cvp->warning = zonecfg_error_func; 628 valid = xmlValidateDocument(cvp, rem_handle->zone_dh_doc); 629 xmlFreeValidCtxt(cvp); 630 if (valid == 0) 631 return (Z_INVALID_DOCUMENT); 632 633 /* delete any comments such as inherited Sun copyright / ident str */ 634 stripcomments(rem_handle); 635 636 rem_handle->zone_dh_newzone = B_TRUE; 637 rem_handle->zone_dh_sw_inv = B_TRUE; 638 639 /* 640 * Now use the remote system handle to generate a local system handle 641 * with an identical zones configuration but no sw inventory. 642 */ 643 if ((local_handle->zone_dh_doc = xmlCopyDoc(rem_handle->zone_dh_doc, 644 1)) == NULL) { 645 return (Z_INVALID_DOCUMENT); 646 } 647 648 /* 649 * We need to re-run xmlValidateDocument on local_handle to properly 650 * update the in-core representation of the configuration. 651 */ 652 if ((cvp = xmlNewValidCtxt()) == NULL) 653 return (Z_NOMEM); 654 cvp->error = zonecfg_error_func; 655 cvp->warning = zonecfg_error_func; 656 valid = xmlValidateDocument(cvp, local_handle->zone_dh_doc); 657 xmlFreeValidCtxt(cvp); 658 if (valid == 0) 659 return (Z_INVALID_DOCUMENT); 660 661 strip_sw_inv(local_handle); 662 663 local_handle->zone_dh_newzone = B_TRUE; 664 local_handle->zone_dh_sw_inv = B_FALSE; 665 666 return (Z_OK); 667 } 668 669 static boolean_t 670 is_renaming(zone_dochandle_t handle) 671 { 672 if (handle->zone_dh_newzone) 673 return (B_FALSE); 674 if (strlen(handle->zone_dh_delete_name) > 0) 675 return (B_TRUE); 676 return (B_FALSE); 677 } 678 679 static boolean_t 680 is_new(zone_dochandle_t handle) 681 { 682 return (handle->zone_dh_newzone || handle->zone_dh_snapshot); 683 } 684 685 static boolean_t 686 is_snapshot(zone_dochandle_t handle) 687 { 688 return (handle->zone_dh_snapshot); 689 } 690 691 /* 692 * It would be great to be able to use libc's ctype(3c) macros, but we 693 * can't, as they are locale sensitive, and it would break our limited thread 694 * safety if this routine had to change the app locale on the fly. 695 */ 696 int 697 zonecfg_validate_zonename(const char *zone) 698 { 699 int i; 700 701 if (strcmp(zone, GLOBAL_ZONENAME) == 0) 702 return (Z_BOGUS_ZONE_NAME); 703 704 if (strlen(zone) >= ZONENAME_MAX) 705 return (Z_BOGUS_ZONE_NAME); 706 707 if (!((zone[0] >= 'a' && zone[0] <= 'z') || 708 (zone[0] >= 'A' && zone[0] <= 'Z') || 709 (zone[0] >= '0' && zone[0] <= '9'))) 710 return (Z_BOGUS_ZONE_NAME); 711 712 for (i = 1; zone[i] != '\0'; i++) { 713 if (!((zone[i] >= 'a' && zone[i] <= 'z') || 714 (zone[i] >= 'A' && zone[i] <= 'Z') || 715 (zone[i] >= '0' && zone[i] <= '9') || 716 (zone[i] == '-') || (zone[i] == '_') || (zone[i] == '.'))) 717 return (Z_BOGUS_ZONE_NAME); 718 } 719 720 return (Z_OK); 721 } 722 723 /* 724 * Changing the zone name requires us to track both the old and new 725 * name of the zone until commit time. 726 */ 727 int 728 zonecfg_get_name(zone_dochandle_t handle, char *name, size_t namesize) 729 { 730 return (getrootattr(handle, DTD_ATTR_NAME, name, namesize)); 731 } 732 733 int 734 zonecfg_set_name(zone_dochandle_t handle, char *name) 735 { 736 zone_state_t state; 737 char curname[ZONENAME_MAX], old_delname[ZONENAME_MAX]; 738 int err; 739 740 if ((err = getrootattr(handle, DTD_ATTR_NAME, curname, 741 sizeof (curname))) != Z_OK) 742 return (err); 743 744 if (strcmp(name, curname) == 0) 745 return (Z_OK); 746 747 /* 748 * Switching zone names to one beginning with SUNW is not permitted. 749 */ 750 if (strncmp(name, "SUNW", 4) == 0) 751 return (Z_BOGUS_ZONE_NAME); 752 753 if ((err = zonecfg_validate_zonename(name)) != Z_OK) 754 return (err); 755 756 /* 757 * Setting the name back to the original name (effectively a revert of 758 * the name) is fine. But if we carry on, we'll falsely identify the 759 * name as "in use," so special case here. 760 */ 761 if (strcmp(name, handle->zone_dh_delete_name) == 0) { 762 err = setrootattr(handle, DTD_ATTR_NAME, name); 763 handle->zone_dh_delete_name[0] = '\0'; 764 return (err); 765 } 766 767 /* Check to see if new name chosen is already in use */ 768 if (zone_get_state(name, &state) != Z_NO_ZONE) 769 return (Z_NAME_IN_USE); 770 771 /* 772 * If this isn't already "new" or in a renaming transition, then 773 * we're initiating a rename here; so stash the "delete name" 774 * (i.e. the name of the zone we'll be removing) for the rename. 775 */ 776 (void) strlcpy(old_delname, handle->zone_dh_delete_name, 777 sizeof (old_delname)); 778 if (!is_new(handle) && !is_renaming(handle)) { 779 /* 780 * Name change is allowed only when the zone we're altering 781 * is not ready or running. 782 */ 783 err = zone_get_state(curname, &state); 784 if (err == Z_OK) { 785 if (state > ZONE_STATE_INSTALLED) 786 return (Z_BAD_ZONE_STATE); 787 } else if (err != Z_NO_ZONE) { 788 return (err); 789 } 790 791 (void) strlcpy(handle->zone_dh_delete_name, curname, 792 sizeof (handle->zone_dh_delete_name)); 793 assert(is_renaming(handle)); 794 } else if (is_renaming(handle)) { 795 err = zone_get_state(handle->zone_dh_delete_name, &state); 796 if (err == Z_OK) { 797 if (state > ZONE_STATE_INSTALLED) 798 return (Z_BAD_ZONE_STATE); 799 } else if (err != Z_NO_ZONE) { 800 return (err); 801 } 802 } 803 804 if ((err = setrootattr(handle, DTD_ATTR_NAME, name)) != Z_OK) { 805 /* 806 * Restore the deletename to whatever it was at the 807 * top of the routine, since we've had a failure. 808 */ 809 (void) strlcpy(handle->zone_dh_delete_name, old_delname, 810 sizeof (handle->zone_dh_delete_name)); 811 return (err); 812 } 813 814 return (Z_OK); 815 } 816 817 int 818 zonecfg_get_zonepath(zone_dochandle_t handle, char *path, size_t pathsize) 819 { 820 size_t len; 821 822 if ((len = strlcpy(path, zonecfg_root, pathsize)) >= pathsize) 823 return (Z_TOO_BIG); 824 return (getrootattr(handle, DTD_ATTR_ZONEPATH, path + len, 825 pathsize - len)); 826 } 827 828 int 829 zonecfg_set_zonepath(zone_dochandle_t handle, char *zonepath) 830 { 831 size_t len; 832 833 /* 834 * The user deals in absolute paths in the running global zone, but the 835 * internal configuration files deal with boot environment relative 836 * paths. Strip out the alternate root when specified. 837 */ 838 len = strlen(zonecfg_root); 839 if (strncmp(zonepath, zonecfg_root, len) != 0 || zonepath[len] != '/') 840 return (Z_BAD_PROPERTY); 841 zonepath += len; 842 return (setrootattr(handle, DTD_ATTR_ZONEPATH, zonepath)); 843 } 844 845 int 846 zonecfg_get_autoboot(zone_dochandle_t handle, boolean_t *autoboot) 847 { 848 char autobootstr[DTD_ENTITY_BOOL_LEN]; 849 int ret; 850 851 if ((ret = getrootattr(handle, DTD_ATTR_AUTOBOOT, autobootstr, 852 sizeof (autobootstr))) != Z_OK) 853 return (ret); 854 855 if (strcmp(autobootstr, DTD_ENTITY_TRUE) == 0) 856 *autoboot = B_TRUE; 857 else if (strcmp(autobootstr, DTD_ENTITY_FALSE) == 0) 858 *autoboot = B_FALSE; 859 else 860 ret = Z_BAD_PROPERTY; 861 return (ret); 862 } 863 864 int 865 zonecfg_set_autoboot(zone_dochandle_t handle, boolean_t autoboot) 866 { 867 return (setrootattr(handle, DTD_ATTR_AUTOBOOT, 868 autoboot ? DTD_ENTITY_TRUE : DTD_ENTITY_FALSE)); 869 } 870 871 int 872 zonecfg_get_pool(zone_dochandle_t handle, char *pool, size_t poolsize) 873 { 874 return (getrootattr(handle, DTD_ATTR_POOL, pool, poolsize)); 875 } 876 877 int 878 zonecfg_set_pool(zone_dochandle_t handle, char *pool) 879 { 880 return (setrootattr(handle, DTD_ATTR_POOL, pool)); 881 } 882 883 int 884 zonecfg_get_limitpriv(zone_dochandle_t handle, char **limitpriv) 885 { 886 return (get_alloc_rootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv)); 887 } 888 889 int 890 zonecfg_set_limitpriv(zone_dochandle_t handle, char *limitpriv) 891 { 892 return (setrootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv)); 893 } 894 895 int 896 zonecfg_get_bootargs(zone_dochandle_t handle, char *bargs, size_t bargssize) 897 { 898 return (getrootattr(handle, DTD_ATTR_BOOTARGS, bargs, bargssize)); 899 } 900 901 int 902 zonecfg_set_bootargs(zone_dochandle_t handle, char *bargs) 903 { 904 return (setrootattr(handle, DTD_ATTR_BOOTARGS, bargs)); 905 } 906 907 /* 908 * /etc/zones/index caches a vital piece of information which is also 909 * in the <zonename>.xml file: the path to the zone. This is for performance, 910 * since we need to walk all zonepath's in order to be able to detect conflicts 911 * (see crosscheck_zonepaths() in the zoneadm command). 912 * 913 * An additional complexity is that when doing a rename, we'd like the entire 914 * index update operation (rename, and potential state changes) to be atomic. 915 * In general, the operation of this function should succeed or fail as 916 * a unit. 917 */ 918 int 919 zonecfg_refresh_index_file(zone_dochandle_t handle) 920 { 921 char name[ZONENAME_MAX], zonepath[MAXPATHLEN]; 922 struct zoneent ze; 923 int err; 924 int opcode; 925 char *zn; 926 927 bzero(&ze, sizeof (ze)); 928 ze.zone_state = -1; /* Preserve existing state in index */ 929 930 if ((err = zonecfg_get_name(handle, name, sizeof (name))) != Z_OK) 931 return (err); 932 (void) strlcpy(ze.zone_name, name, sizeof (ze.zone_name)); 933 934 if ((err = zonecfg_get_zonepath(handle, zonepath, 935 sizeof (zonepath))) != Z_OK) 936 return (err); 937 (void) strlcpy(ze.zone_path, zonepath + strlen(zonecfg_root), 938 sizeof (ze.zone_path)); 939 940 if (is_renaming(handle)) { 941 opcode = PZE_MODIFY; 942 (void) strlcpy(ze.zone_name, handle->zone_dh_delete_name, 943 sizeof (ze.zone_name)); 944 (void) strlcpy(ze.zone_newname, name, sizeof (ze.zone_newname)); 945 } else if (is_new(handle)) { 946 FILE *cookie; 947 /* 948 * Be tolerant of the zone already existing in the index file, 949 * since we might be forcibly overwriting an existing 950 * configuration with a new one (for example 'create -F' 951 * in zonecfg). 952 */ 953 opcode = PZE_ADD; 954 cookie = setzoneent(); 955 while ((zn = getzoneent(cookie)) != NULL) { 956 if (strcmp(zn, name) == 0) { 957 opcode = PZE_MODIFY; 958 free(zn); 959 break; 960 } 961 free(zn); 962 } 963 endzoneent(cookie); 964 ze.zone_state = ZONE_STATE_CONFIGURED; 965 } else { 966 opcode = PZE_MODIFY; 967 } 968 969 if ((err = putzoneent(&ze, opcode)) != Z_OK) 970 return (err); 971 972 return (Z_OK); 973 } 974 975 /* 976 * The goal of this routine is to cause the index file update and the 977 * document save to happen as an atomic operation. We do the document 978 * first, saving a backup copy using a hard link; if that succeeds, we go 979 * on to the index. If that fails, we roll the document back into place. 980 * 981 * Strategy: 982 * 983 * New zone 'foo' configuration: 984 * Create tmpfile (zonecfg.xxxxxx) 985 * Write XML to tmpfile 986 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml) 987 * Add entry to index file 988 * If it fails, delete foo.xml, leaving nothing behind. 989 * 990 * Save existing zone 'foo': 991 * Make backup of foo.xml -> .backup 992 * Create tmpfile (zonecfg.xxxxxx) 993 * Write XML to tmpfile 994 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml) 995 * Modify index file as needed 996 * If it fails, recover from .backup -> foo.xml 997 * 998 * Rename 'foo' to 'bar': 999 * Create tmpfile (zonecfg.xxxxxx) 1000 * Write XML to tmpfile 1001 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml) 1002 * Add entry for 'bar' to index file, Remove entry for 'foo' (refresh) 1003 * If it fails, delete bar.xml; foo.xml is left behind. 1004 */ 1005 static int 1006 zonecfg_save_impl(zone_dochandle_t handle, char *filename) 1007 { 1008 char tmpfile[MAXPATHLEN]; 1009 char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN]; 1010 int tmpfd, err; 1011 xmlValidCtxt cvp = { NULL }; 1012 boolean_t backup; 1013 1014 (void) strlcpy(tmpfile, filename, sizeof (tmpfile)); 1015 (void) dirname(tmpfile); 1016 (void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile)); 1017 1018 tmpfd = mkstemp(tmpfile); 1019 if (tmpfd == -1) { 1020 (void) unlink(tmpfile); 1021 return (Z_TEMP_FILE); 1022 } 1023 (void) close(tmpfd); 1024 1025 cvp.error = zonecfg_error_func; 1026 cvp.warning = zonecfg_error_func; 1027 1028 /* 1029 * We do a final validation of the document-- but the library has 1030 * malfunctioned if it fails to validate, so it's an assert. 1031 */ 1032 assert(xmlValidateDocument(&cvp, handle->zone_dh_doc) != 0); 1033 1034 if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0) 1035 goto err; 1036 1037 (void) chmod(tmpfile, 0644); 1038 1039 /* 1040 * In the event we are doing a standard save, hard link a copy of the 1041 * original file in .backup.<pid>.filename so we can restore it if 1042 * something goes wrong. 1043 */ 1044 if (!is_new(handle) && !is_renaming(handle)) { 1045 backup = B_TRUE; 1046 1047 (void) strlcpy(bakdir, filename, sizeof (bakdir)); 1048 (void) strlcpy(bakbase, filename, sizeof (bakbase)); 1049 (void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s", 1050 dirname(bakdir), getpid(), basename(bakbase)); 1051 1052 if (link(filename, bakfile) == -1) { 1053 err = errno; 1054 (void) unlink(tmpfile); 1055 if (errno == EACCES) 1056 return (Z_ACCES); 1057 return (Z_MISC_FS); 1058 } 1059 } 1060 1061 /* 1062 * Move the new document over top of the old. 1063 * i.e.: zonecfg.XXXXXX -> myzone.xml 1064 */ 1065 if (rename(tmpfile, filename) == -1) { 1066 err = errno; 1067 (void) unlink(tmpfile); 1068 if (backup) 1069 (void) unlink(bakfile); 1070 if (err == EACCES) 1071 return (Z_ACCES); 1072 return (Z_MISC_FS); 1073 } 1074 1075 /* 1076 * If this is a snapshot, we're done-- don't add an index entry. 1077 */ 1078 if (is_snapshot(handle)) 1079 return (Z_OK); 1080 1081 /* now update the index file to reflect whatever we just did */ 1082 if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) { 1083 if (backup) { 1084 /* 1085 * Try to restore from our backup. 1086 */ 1087 (void) unlink(filename); 1088 (void) rename(bakfile, filename); 1089 } else { 1090 /* 1091 * Either the zone is new, in which case we can delete 1092 * new.xml, or we're doing a rename, so ditto. 1093 */ 1094 assert(is_new(handle) || is_renaming(handle)); 1095 (void) unlink(filename); 1096 } 1097 return (Z_UPDATING_INDEX); 1098 } 1099 1100 if (backup) 1101 (void) unlink(bakfile); 1102 1103 return (Z_OK); 1104 1105 err: 1106 (void) unlink(tmpfile); 1107 return (Z_SAVING_FILE); 1108 } 1109 1110 int 1111 zonecfg_save(zone_dochandle_t handle) 1112 { 1113 char zname[ZONENAME_MAX], path[MAXPATHLEN]; 1114 char delpath[MAXPATHLEN]; 1115 int err = Z_SAVING_FILE; 1116 1117 if (zonecfg_check_handle(handle) != Z_OK) 1118 return (Z_BAD_HANDLE); 1119 1120 /* 1121 * We don't support saving snapshots or a tree containing a sw 1122 * inventory at this time. 1123 */ 1124 if (handle->zone_dh_snapshot || handle->zone_dh_sw_inv) 1125 return (Z_INVAL); 1126 1127 if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK) 1128 return (err); 1129 1130 if (!config_file_path(zname, path)) 1131 return (Z_MISC_FS); 1132 1133 addcomment(handle, "\n DO NOT EDIT THIS " 1134 "FILE. Use zonecfg(1M) instead.\n"); 1135 1136 err = zonecfg_save_impl(handle, path); 1137 1138 stripcomments(handle); 1139 1140 if (err != Z_OK) 1141 return (err); 1142 1143 handle->zone_dh_newzone = B_FALSE; 1144 1145 if (is_renaming(handle)) { 1146 if (config_file_path(handle->zone_dh_delete_name, delpath)) 1147 (void) unlink(delpath); 1148 handle->zone_dh_delete_name[0] = '\0'; 1149 } 1150 1151 return (Z_OK); 1152 } 1153 1154 int 1155 zonecfg_detach_save(zone_dochandle_t handle, uint_t flags) 1156 { 1157 char zname[ZONENAME_MAX]; 1158 char path[MAXPATHLEN]; 1159 char migpath[MAXPATHLEN]; 1160 xmlValidCtxt cvp = { NULL }; 1161 int err = Z_SAVING_FILE; 1162 1163 if (zonecfg_check_handle(handle) != Z_OK) 1164 return (Z_BAD_HANDLE); 1165 1166 /* 1167 * We can only detach if we have taken a sw inventory. 1168 */ 1169 if (!handle->zone_dh_sw_inv) 1170 return (Z_INVAL); 1171 1172 if (flags & ZONE_DRY_RUN) { 1173 (void) strlcpy(migpath, "-", sizeof (migpath)); 1174 } else { 1175 if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) 1176 != Z_OK) 1177 return (err); 1178 1179 if ((err = zone_get_zonepath(zname, path, sizeof (path))) 1180 != Z_OK) 1181 return (err); 1182 1183 if (snprintf(migpath, sizeof (migpath), "%s/%s", path, DETACHED) 1184 >= sizeof (migpath)) 1185 return (Z_NOMEM); 1186 } 1187 1188 if ((err = operation_prep(handle)) != Z_OK) 1189 return (err); 1190 1191 addcomment(handle, "\n DO NOT EDIT THIS FILE. " 1192 "Use zonecfg(1M) and zoneadm(1M) attach.\n"); 1193 1194 cvp.error = zonecfg_error_func; 1195 cvp.warning = zonecfg_error_func; 1196 1197 /* 1198 * We do a final validation of the document-- but the library has 1199 * malfunctioned if it fails to validate, so it's an assert. 1200 */ 1201 assert(xmlValidateDocument(&cvp, handle->zone_dh_doc) != 0); 1202 1203 if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0) 1204 return (Z_SAVING_FILE); 1205 1206 if (!(flags & ZONE_DRY_RUN)) 1207 (void) chmod(migpath, 0644); 1208 1209 stripcomments(handle); 1210 1211 handle->zone_dh_newzone = B_FALSE; 1212 1213 return (Z_OK); 1214 } 1215 1216 boolean_t 1217 zonecfg_detached(const char *path) 1218 { 1219 char migpath[MAXPATHLEN]; 1220 struct stat buf; 1221 1222 if (snprintf(migpath, sizeof (migpath), "%s/%s", path, DETACHED) >= 1223 sizeof (migpath)) 1224 return (B_FALSE); 1225 1226 if (stat(migpath, &buf) != -1) 1227 return (B_TRUE); 1228 1229 return (B_FALSE); 1230 } 1231 1232 void 1233 zonecfg_rm_detached(zone_dochandle_t handle, boolean_t forced) 1234 { 1235 char zname[ZONENAME_MAX]; 1236 char path[MAXPATHLEN]; 1237 char detached[MAXPATHLEN]; 1238 char attached[MAXPATHLEN]; 1239 1240 if (zonecfg_check_handle(handle) != Z_OK) 1241 return; 1242 1243 if (zonecfg_get_name(handle, zname, sizeof (zname)) != Z_OK) 1244 return; 1245 1246 if (zone_get_zonepath(zname, path, sizeof (path)) != Z_OK) 1247 return; 1248 1249 (void) snprintf(detached, sizeof (detached), "%s/%s", path, DETACHED); 1250 (void) snprintf(attached, sizeof (attached), "%s/%s", path, 1251 ATTACH_FORCED); 1252 1253 if (forced) { 1254 (void) rename(detached, attached); 1255 } else { 1256 (void) unlink(attached); 1257 (void) unlink(detached); 1258 } 1259 } 1260 1261 /* 1262 * Special case: if access(2) fails with ENOENT, then try again using 1263 * ZONE_CONFIG_ROOT instead of config_file_path(zonename). This is how we 1264 * work around the case of a config file which has not been created yet: 1265 * the user will need access to the directory so use that as a heuristic. 1266 */ 1267 1268 int 1269 zonecfg_access(const char *zonename, int amode) 1270 { 1271 char path[MAXPATHLEN]; 1272 1273 if (!config_file_path(zonename, path)) 1274 return (Z_INVAL); 1275 if (access(path, amode) == 0) 1276 return (Z_OK); 1277 if (errno == ENOENT) { 1278 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root, 1279 ZONE_CONFIG_ROOT) >= sizeof (path)) 1280 return (Z_INVAL); 1281 if (access(path, amode) == 0) 1282 return (Z_OK); 1283 } 1284 if (errno == EACCES) 1285 return (Z_ACCES); 1286 if (errno == EINVAL) 1287 return (Z_INVAL); 1288 return (Z_MISC_FS); 1289 } 1290 1291 int 1292 zonecfg_create_snapshot(const char *zonename) 1293 { 1294 zone_dochandle_t handle; 1295 char path[MAXPATHLEN], zonepath[MAXPATHLEN], rpath[MAXPATHLEN]; 1296 int error = Z_OK, res; 1297 1298 if ((handle = zonecfg_init_handle()) == NULL) { 1299 return (Z_NOMEM); 1300 } 1301 1302 handle->zone_dh_newzone = B_TRUE; 1303 handle->zone_dh_snapshot = B_TRUE; 1304 1305 if ((error = zonecfg_get_handle(zonename, handle)) != Z_OK) 1306 goto out; 1307 if ((error = operation_prep(handle)) != Z_OK) 1308 goto out; 1309 error = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)); 1310 if (error != Z_OK) 1311 goto out; 1312 if ((res = resolvepath(zonepath, rpath, sizeof (rpath))) == -1) { 1313 error = Z_RESOLVED_PATH; 1314 goto out; 1315 } 1316 /* 1317 * If the resolved path is not the same as the original path, then 1318 * save the resolved path in the snapshot, thus preventing any 1319 * potential problems down the line when zoneadmd goes to unmount 1320 * file systems and depends on initial string matches with resolved 1321 * paths. 1322 */ 1323 rpath[res] = '\0'; 1324 if (strcmp(zonepath, rpath) != 0) { 1325 if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK) 1326 goto out; 1327 } 1328 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root, 1329 ZONE_SNAPSHOT_ROOT) >= sizeof (path)) { 1330 error = Z_MISC_FS; 1331 goto out; 1332 } 1333 if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) { 1334 error = Z_MISC_FS; 1335 goto out; 1336 } 1337 1338 if (!snap_file_path(zonename, path)) { 1339 error = Z_MISC_FS; 1340 goto out; 1341 } 1342 1343 addcomment(handle, "\n DO NOT EDIT THIS FILE. " 1344 "It is a snapshot of running zone state.\n"); 1345 1346 error = zonecfg_save_impl(handle, path); 1347 1348 stripcomments(handle); 1349 1350 out: 1351 zonecfg_fini_handle(handle); 1352 return (error); 1353 } 1354 1355 static int 1356 newprop(xmlNodePtr node, const xmlChar *attrname, char *src) 1357 { 1358 xmlAttrPtr newattr; 1359 1360 newattr = xmlNewProp(node, attrname, (xmlChar *)src); 1361 if (newattr == NULL) { 1362 xmlUnlinkNode(node); 1363 xmlFreeNode(node); 1364 return (Z_BAD_PROPERTY); 1365 } 1366 return (Z_OK); 1367 } 1368 1369 static int 1370 zonecfg_add_filesystem_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1371 { 1372 xmlNodePtr newnode, cur = handle->zone_dh_cur, options_node; 1373 zone_fsopt_t *ptr; 1374 int err; 1375 1376 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_FS, NULL); 1377 if ((err = newprop(newnode, DTD_ATTR_SPECIAL, 1378 tabptr->zone_fs_special)) != Z_OK) 1379 return (err); 1380 if (tabptr->zone_fs_raw[0] != '\0' && 1381 (err = newprop(newnode, DTD_ATTR_RAW, tabptr->zone_fs_raw)) != Z_OK) 1382 return (err); 1383 if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK) 1384 return (err); 1385 if ((err = newprop(newnode, DTD_ATTR_TYPE, 1386 tabptr->zone_fs_type)) != Z_OK) 1387 return (err); 1388 if (tabptr->zone_fs_options != NULL) { 1389 for (ptr = tabptr->zone_fs_options; ptr != NULL; 1390 ptr = ptr->zone_fsopt_next) { 1391 options_node = xmlNewTextChild(newnode, NULL, 1392 DTD_ELEM_FSOPTION, NULL); 1393 if ((err = newprop(options_node, DTD_ATTR_NAME, 1394 ptr->zone_fsopt_opt)) != Z_OK) 1395 return (err); 1396 } 1397 } 1398 return (Z_OK); 1399 } 1400 1401 int 1402 zonecfg_add_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr) 1403 { 1404 int err; 1405 1406 if (tabptr == NULL) 1407 return (Z_INVAL); 1408 1409 if ((err = operation_prep(handle)) != Z_OK) 1410 return (err); 1411 1412 if ((err = zonecfg_add_filesystem_core(handle, tabptr)) != Z_OK) 1413 return (err); 1414 1415 return (Z_OK); 1416 } 1417 1418 static int 1419 zonecfg_add_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1420 { 1421 xmlNodePtr newnode, cur = handle->zone_dh_cur; 1422 int err; 1423 1424 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_IPD, NULL); 1425 if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK) 1426 return (err); 1427 return (Z_OK); 1428 } 1429 1430 int 1431 zonecfg_add_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 1432 { 1433 int err; 1434 1435 if (tabptr == NULL) 1436 return (Z_INVAL); 1437 1438 if ((err = operation_prep(handle)) != Z_OK) 1439 return (err); 1440 1441 if ((err = zonecfg_add_ipd_core(handle, tabptr)) != Z_OK) 1442 return (err); 1443 1444 return (Z_OK); 1445 } 1446 1447 int 1448 zonecfg_add_fs_option(struct zone_fstab *tabptr, char *option) 1449 { 1450 zone_fsopt_t *last, *old, *new; 1451 1452 last = tabptr->zone_fs_options; 1453 for (old = last; old != NULL; old = old->zone_fsopt_next) 1454 last = old; /* walk to the end of the list */ 1455 new = (zone_fsopt_t *)malloc(sizeof (zone_fsopt_t)); 1456 if (new == NULL) 1457 return (Z_NOMEM); 1458 (void) strlcpy(new->zone_fsopt_opt, option, 1459 sizeof (new->zone_fsopt_opt)); 1460 new->zone_fsopt_next = NULL; 1461 if (last == NULL) 1462 tabptr->zone_fs_options = new; 1463 else 1464 last->zone_fsopt_next = new; 1465 return (Z_OK); 1466 } 1467 1468 int 1469 zonecfg_remove_fs_option(struct zone_fstab *tabptr, char *option) 1470 { 1471 zone_fsopt_t *last, *this, *next; 1472 1473 last = tabptr->zone_fs_options; 1474 for (this = last; this != NULL; this = this->zone_fsopt_next) { 1475 if (strcmp(this->zone_fsopt_opt, option) == 0) { 1476 next = this->zone_fsopt_next; 1477 if (this == tabptr->zone_fs_options) 1478 tabptr->zone_fs_options = next; 1479 else 1480 last->zone_fsopt_next = next; 1481 free(this); 1482 return (Z_OK); 1483 } else 1484 last = this; 1485 } 1486 return (Z_NO_PROPERTY_ID); 1487 } 1488 1489 void 1490 zonecfg_free_fs_option_list(zone_fsopt_t *list) 1491 { 1492 zone_fsopt_t *this, *next; 1493 1494 for (this = list; this != NULL; this = next) { 1495 next = this->zone_fsopt_next; 1496 free(this); 1497 } 1498 } 1499 1500 void 1501 zonecfg_free_rctl_value_list(struct zone_rctlvaltab *valtab) 1502 { 1503 if (valtab == NULL) 1504 return; 1505 zonecfg_free_rctl_value_list(valtab->zone_rctlval_next); 1506 free(valtab); 1507 } 1508 1509 static boolean_t 1510 match_prop(xmlNodePtr cur, const xmlChar *attr, char *user_prop) 1511 { 1512 xmlChar *gotten_prop; 1513 int prop_result; 1514 1515 gotten_prop = xmlGetProp(cur, attr); 1516 if (gotten_prop == NULL) /* shouldn't happen */ 1517 return (B_FALSE); 1518 prop_result = xmlStrcmp(gotten_prop, (const xmlChar *) user_prop); 1519 xmlFree(gotten_prop); 1520 return ((prop_result == 0)); 1521 } 1522 1523 static int 1524 zonecfg_delete_filesystem_core(zone_dochandle_t handle, 1525 struct zone_fstab *tabptr) 1526 { 1527 xmlNodePtr cur = handle->zone_dh_cur; 1528 boolean_t dir_match, spec_match, raw_match, type_match; 1529 1530 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1531 if (xmlStrcmp(cur->name, DTD_ELEM_FS)) 1532 continue; 1533 dir_match = match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir); 1534 spec_match = match_prop(cur, DTD_ATTR_SPECIAL, 1535 tabptr->zone_fs_special); 1536 raw_match = match_prop(cur, DTD_ATTR_RAW, 1537 tabptr->zone_fs_raw); 1538 type_match = match_prop(cur, DTD_ATTR_TYPE, 1539 tabptr->zone_fs_type); 1540 if (dir_match && spec_match && raw_match && type_match) { 1541 xmlUnlinkNode(cur); 1542 xmlFreeNode(cur); 1543 return (Z_OK); 1544 } 1545 } 1546 return (Z_NO_RESOURCE_ID); 1547 } 1548 1549 int 1550 zonecfg_delete_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr) 1551 { 1552 int err; 1553 1554 if (tabptr == NULL) 1555 return (Z_INVAL); 1556 1557 if ((err = operation_prep(handle)) != Z_OK) 1558 return (err); 1559 1560 if ((err = zonecfg_delete_filesystem_core(handle, tabptr)) != Z_OK) 1561 return (err); 1562 1563 return (Z_OK); 1564 } 1565 1566 int 1567 zonecfg_modify_filesystem( 1568 zone_dochandle_t handle, 1569 struct zone_fstab *oldtabptr, 1570 struct zone_fstab *newtabptr) 1571 { 1572 int err; 1573 1574 if (oldtabptr == NULL || newtabptr == NULL) 1575 return (Z_INVAL); 1576 1577 if ((err = operation_prep(handle)) != Z_OK) 1578 return (err); 1579 1580 if ((err = zonecfg_delete_filesystem_core(handle, oldtabptr)) != Z_OK) 1581 return (err); 1582 1583 if ((err = zonecfg_add_filesystem_core(handle, newtabptr)) != Z_OK) 1584 return (err); 1585 1586 return (Z_OK); 1587 } 1588 1589 static int 1590 zonecfg_delete_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1591 { 1592 xmlNodePtr cur = handle->zone_dh_cur; 1593 1594 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1595 if (xmlStrcmp(cur->name, DTD_ELEM_IPD)) 1596 continue; 1597 if (match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir)) { 1598 xmlUnlinkNode(cur); 1599 xmlFreeNode(cur); 1600 return (Z_OK); 1601 } 1602 } 1603 return (Z_NO_RESOURCE_ID); 1604 } 1605 1606 int 1607 zonecfg_delete_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 1608 { 1609 int err; 1610 1611 if (tabptr == NULL) 1612 return (Z_INVAL); 1613 1614 if ((err = operation_prep(handle)) != Z_OK) 1615 return (err); 1616 1617 if ((err = zonecfg_delete_ipd_core(handle, tabptr)) != Z_OK) 1618 return (err); 1619 1620 return (Z_OK); 1621 } 1622 1623 int 1624 zonecfg_modify_ipd(zone_dochandle_t handle, struct zone_fstab *oldtabptr, 1625 struct zone_fstab *newtabptr) 1626 { 1627 int err; 1628 1629 if (oldtabptr == NULL || newtabptr == NULL) 1630 return (Z_INVAL); 1631 1632 if ((err = operation_prep(handle)) != Z_OK) 1633 return (err); 1634 1635 if ((err = zonecfg_delete_ipd_core(handle, oldtabptr)) != Z_OK) 1636 return (err); 1637 1638 if ((err = zonecfg_add_ipd_core(handle, newtabptr)) != Z_OK) 1639 return (err); 1640 1641 return (Z_OK); 1642 } 1643 1644 int 1645 zonecfg_lookup_filesystem( 1646 zone_dochandle_t handle, 1647 struct zone_fstab *tabptr) 1648 { 1649 xmlNodePtr cur, options, firstmatch; 1650 int err; 1651 char dirname[MAXPATHLEN], special[MAXPATHLEN], raw[MAXPATHLEN]; 1652 char type[FSTYPSZ]; 1653 char options_str[MAX_MNTOPT_STR]; 1654 1655 if (tabptr == NULL) 1656 return (Z_INVAL); 1657 1658 if ((err = operation_prep(handle)) != Z_OK) 1659 return (err); 1660 1661 /* 1662 * Walk the list of children looking for matches on any properties 1663 * specified in the fstab parameter. If more than one resource 1664 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return 1665 * Z_NO_RESOURCE_ID. 1666 */ 1667 cur = handle->zone_dh_cur; 1668 firstmatch = NULL; 1669 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1670 if (xmlStrcmp(cur->name, DTD_ELEM_FS)) 1671 continue; 1672 if (strlen(tabptr->zone_fs_dir) > 0) { 1673 if ((fetchprop(cur, DTD_ATTR_DIR, dirname, 1674 sizeof (dirname)) == Z_OK) && 1675 (strcmp(tabptr->zone_fs_dir, dirname) == 0)) { 1676 if (firstmatch == NULL) 1677 firstmatch = cur; 1678 else 1679 return (Z_INSUFFICIENT_SPEC); 1680 } 1681 } 1682 if (strlen(tabptr->zone_fs_special) > 0) { 1683 if ((fetchprop(cur, DTD_ATTR_SPECIAL, special, 1684 sizeof (special)) == Z_OK)) { 1685 if (strcmp(tabptr->zone_fs_special, 1686 special) == 0) { 1687 if (firstmatch == NULL) 1688 firstmatch = cur; 1689 else if (firstmatch != cur) 1690 return (Z_INSUFFICIENT_SPEC); 1691 } else { 1692 /* 1693 * If another property matched but this 1694 * one doesn't then reset firstmatch. 1695 */ 1696 if (firstmatch == cur) 1697 firstmatch = NULL; 1698 } 1699 } 1700 } 1701 if (strlen(tabptr->zone_fs_raw) > 0) { 1702 if ((fetchprop(cur, DTD_ATTR_RAW, raw, 1703 sizeof (raw)) == Z_OK)) { 1704 if (strcmp(tabptr->zone_fs_raw, raw) == 0) { 1705 if (firstmatch == NULL) 1706 firstmatch = cur; 1707 else if (firstmatch != cur) 1708 return (Z_INSUFFICIENT_SPEC); 1709 } else { 1710 /* 1711 * If another property matched but this 1712 * one doesn't then reset firstmatch. 1713 */ 1714 if (firstmatch == cur) 1715 firstmatch = NULL; 1716 } 1717 } 1718 } 1719 if (strlen(tabptr->zone_fs_type) > 0) { 1720 if ((fetchprop(cur, DTD_ATTR_TYPE, type, 1721 sizeof (type)) == Z_OK)) { 1722 if (strcmp(tabptr->zone_fs_type, type) == 0) { 1723 if (firstmatch == NULL) 1724 firstmatch = cur; 1725 else if (firstmatch != cur) 1726 return (Z_INSUFFICIENT_SPEC); 1727 } else { 1728 /* 1729 * If another property matched but this 1730 * one doesn't then reset firstmatch. 1731 */ 1732 if (firstmatch == cur) 1733 firstmatch = NULL; 1734 } 1735 } 1736 } 1737 } 1738 1739 if (firstmatch == NULL) 1740 return (Z_NO_RESOURCE_ID); 1741 1742 cur = firstmatch; 1743 1744 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 1745 sizeof (tabptr->zone_fs_dir))) != Z_OK) 1746 return (err); 1747 1748 if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special, 1749 sizeof (tabptr->zone_fs_special))) != Z_OK) 1750 return (err); 1751 1752 if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw, 1753 sizeof (tabptr->zone_fs_raw))) != Z_OK) 1754 return (err); 1755 1756 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type, 1757 sizeof (tabptr->zone_fs_type))) != Z_OK) 1758 return (err); 1759 1760 /* options are optional */ 1761 tabptr->zone_fs_options = NULL; 1762 for (options = cur->xmlChildrenNode; options != NULL; 1763 options = options->next) { 1764 if ((fetchprop(options, DTD_ATTR_NAME, options_str, 1765 sizeof (options_str)) != Z_OK)) 1766 break; 1767 if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK) 1768 break; 1769 } 1770 return (Z_OK); 1771 } 1772 1773 int 1774 zonecfg_lookup_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 1775 { 1776 xmlNodePtr cur, match; 1777 int err; 1778 char dirname[MAXPATHLEN]; 1779 1780 if (tabptr == NULL) 1781 return (Z_INVAL); 1782 1783 if ((err = operation_prep(handle)) != Z_OK) 1784 return (err); 1785 1786 /* 1787 * General algorithm: 1788 * Walk the list of children looking for matches on any properties 1789 * specified in the fstab parameter. If more than one resource 1790 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return 1791 * Z_NO_RESOURCE_ID. 1792 */ 1793 cur = handle->zone_dh_cur; 1794 match = NULL; 1795 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1796 if (xmlStrcmp(cur->name, DTD_ELEM_IPD)) 1797 continue; 1798 if (strlen(tabptr->zone_fs_dir) > 0) { 1799 if ((fetchprop(cur, DTD_ATTR_DIR, dirname, 1800 sizeof (dirname)) == Z_OK) && 1801 (strcmp(tabptr->zone_fs_dir, dirname) == 0)) { 1802 if (match == NULL) 1803 match = cur; 1804 else 1805 return (Z_INSUFFICIENT_SPEC); 1806 } 1807 } 1808 } 1809 1810 if (match == NULL) 1811 return (Z_NO_RESOURCE_ID); 1812 1813 cur = match; 1814 1815 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 1816 sizeof (tabptr->zone_fs_dir))) != Z_OK) 1817 return (err); 1818 1819 return (Z_OK); 1820 } 1821 1822 /* 1823 * Compare two IP addresses in string form. Allow for the possibility that 1824 * one might have "/<prefix-length>" at the end: allow a match on just the 1825 * IP address (or host name) part. 1826 */ 1827 1828 boolean_t 1829 zonecfg_same_net_address(char *a1, char *a2) 1830 { 1831 char *slashp, *slashp1, *slashp2; 1832 int result; 1833 1834 if (strcmp(a1, a2) == 0) 1835 return (B_TRUE); 1836 1837 /* 1838 * If neither has a slash or both do, they need to match to be 1839 * considered the same, but they did not match above, so fail. 1840 */ 1841 slashp1 = strchr(a1, '/'); 1842 slashp2 = strchr(a2, '/'); 1843 if ((slashp1 == NULL && slashp2 == NULL) || 1844 (slashp1 != NULL && slashp2 != NULL)) 1845 return (B_FALSE); 1846 1847 /* 1848 * Only one had a slash: pick that one, zero out the slash, compare 1849 * the "address only" strings, restore the slash, and return the 1850 * result of the comparison. 1851 */ 1852 slashp = (slashp1 == NULL) ? slashp2 : slashp1; 1853 *slashp = '\0'; 1854 result = strcmp(a1, a2); 1855 *slashp = '/'; 1856 return ((result == 0)); 1857 } 1858 1859 int 1860 zonecfg_valid_net_address(char *address, struct lifreq *lifr) 1861 { 1862 struct sockaddr_in *sin4; 1863 struct sockaddr_in6 *sin6; 1864 struct addrinfo hints, *result; 1865 char *slashp = strchr(address, '/'); 1866 1867 bzero(lifr, sizeof (struct lifreq)); 1868 sin4 = (struct sockaddr_in *)&lifr->lifr_addr; 1869 sin6 = (struct sockaddr_in6 *)&lifr->lifr_addr; 1870 if (slashp != NULL) 1871 *slashp = '\0'; 1872 if (inet_pton(AF_INET, address, &sin4->sin_addr) == 1) { 1873 sin4->sin_family = AF_INET; 1874 } else if (inet_pton(AF_INET6, address, &sin6->sin6_addr) == 1) { 1875 if (slashp == NULL) 1876 return (Z_IPV6_ADDR_PREFIX_LEN); 1877 sin6->sin6_family = AF_INET6; 1878 } else { 1879 /* "address" may be a host name */ 1880 (void) memset(&hints, 0, sizeof (hints)); 1881 hints.ai_family = PF_INET; 1882 if (getaddrinfo(address, NULL, &hints, &result) != 0) 1883 return (Z_BOGUS_ADDRESS); 1884 sin4->sin_family = result->ai_family; 1885 1886 (void) memcpy(&sin4->sin_addr, 1887 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1888 &((struct sockaddr_in *)result->ai_addr)->sin_addr, 1889 sizeof (struct in_addr)); 1890 1891 freeaddrinfo(result); 1892 } 1893 return (Z_OK); 1894 } 1895 1896 int 1897 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 1898 { 1899 xmlNodePtr cur, firstmatch; 1900 int err; 1901 char address[INET6_ADDRSTRLEN], physical[LIFNAMSIZ]; 1902 1903 if (tabptr == NULL) 1904 return (Z_INVAL); 1905 1906 if ((err = operation_prep(handle)) != Z_OK) 1907 return (err); 1908 1909 cur = handle->zone_dh_cur; 1910 firstmatch = NULL; 1911 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1912 if (xmlStrcmp(cur->name, DTD_ELEM_NET)) 1913 continue; 1914 if (strlen(tabptr->zone_nwif_physical) > 0) { 1915 if ((fetchprop(cur, DTD_ATTR_PHYSICAL, physical, 1916 sizeof (physical)) == Z_OK) && 1917 (strcmp(tabptr->zone_nwif_physical, 1918 physical) == 0)) { 1919 if (firstmatch == NULL) 1920 firstmatch = cur; 1921 else 1922 return (Z_INSUFFICIENT_SPEC); 1923 } 1924 } 1925 if (strlen(tabptr->zone_nwif_address) > 0) { 1926 if ((fetchprop(cur, DTD_ATTR_ADDRESS, address, 1927 sizeof (address)) == Z_OK)) { 1928 if (zonecfg_same_net_address( 1929 tabptr->zone_nwif_address, address)) { 1930 if (firstmatch == NULL) 1931 firstmatch = cur; 1932 else if (firstmatch != cur) 1933 return (Z_INSUFFICIENT_SPEC); 1934 } else { 1935 /* 1936 * If another property matched but this 1937 * one doesn't then reset firstmatch. 1938 */ 1939 if (firstmatch == cur) 1940 firstmatch = NULL; 1941 } 1942 } 1943 } 1944 } 1945 if (firstmatch == NULL) 1946 return (Z_NO_RESOURCE_ID); 1947 1948 cur = firstmatch; 1949 1950 if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical, 1951 sizeof (tabptr->zone_nwif_physical))) != Z_OK) 1952 return (err); 1953 1954 if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address, 1955 sizeof (tabptr->zone_nwif_address))) != Z_OK) 1956 return (err); 1957 1958 return (Z_OK); 1959 } 1960 1961 static int 1962 zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 1963 { 1964 xmlNodePtr newnode, cur = handle->zone_dh_cur; 1965 int err; 1966 1967 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL); 1968 if ((err = newprop(newnode, DTD_ATTR_ADDRESS, 1969 tabptr->zone_nwif_address)) != Z_OK) 1970 return (err); 1971 if ((err = newprop(newnode, DTD_ATTR_PHYSICAL, 1972 tabptr->zone_nwif_physical)) != Z_OK) 1973 return (err); 1974 return (Z_OK); 1975 } 1976 1977 int 1978 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 1979 { 1980 int err; 1981 1982 if (tabptr == NULL) 1983 return (Z_INVAL); 1984 1985 if ((err = operation_prep(handle)) != Z_OK) 1986 return (err); 1987 1988 if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK) 1989 return (err); 1990 1991 return (Z_OK); 1992 } 1993 1994 static int 1995 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 1996 { 1997 xmlNodePtr cur = handle->zone_dh_cur; 1998 boolean_t addr_match, phys_match; 1999 2000 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2001 if (xmlStrcmp(cur->name, DTD_ELEM_NET)) 2002 continue; 2003 2004 addr_match = match_prop(cur, DTD_ATTR_ADDRESS, 2005 tabptr->zone_nwif_address); 2006 phys_match = match_prop(cur, DTD_ATTR_PHYSICAL, 2007 tabptr->zone_nwif_physical); 2008 2009 if (addr_match && phys_match) { 2010 xmlUnlinkNode(cur); 2011 xmlFreeNode(cur); 2012 return (Z_OK); 2013 } 2014 } 2015 return (Z_NO_RESOURCE_ID); 2016 } 2017 2018 int 2019 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2020 { 2021 int err; 2022 2023 if (tabptr == NULL) 2024 return (Z_INVAL); 2025 2026 if ((err = operation_prep(handle)) != Z_OK) 2027 return (err); 2028 2029 if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK) 2030 return (err); 2031 2032 return (Z_OK); 2033 } 2034 2035 int 2036 zonecfg_modify_nwif( 2037 zone_dochandle_t handle, 2038 struct zone_nwiftab *oldtabptr, 2039 struct zone_nwiftab *newtabptr) 2040 { 2041 int err; 2042 2043 if (oldtabptr == NULL || newtabptr == NULL) 2044 return (Z_INVAL); 2045 2046 if ((err = operation_prep(handle)) != Z_OK) 2047 return (err); 2048 2049 if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK) 2050 return (err); 2051 2052 if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK) 2053 return (err); 2054 2055 return (Z_OK); 2056 } 2057 2058 int 2059 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 2060 { 2061 xmlNodePtr cur, firstmatch; 2062 int err; 2063 char match[MAXPATHLEN]; 2064 2065 if (tabptr == NULL) 2066 return (Z_INVAL); 2067 2068 if ((err = operation_prep(handle)) != Z_OK) 2069 return (err); 2070 2071 cur = handle->zone_dh_cur; 2072 firstmatch = NULL; 2073 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2074 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 2075 continue; 2076 if (strlen(tabptr->zone_dev_match) == 0) 2077 continue; 2078 2079 if ((fetchprop(cur, DTD_ATTR_MATCH, match, 2080 sizeof (match)) == Z_OK)) { 2081 if (strcmp(tabptr->zone_dev_match, 2082 match) == 0) { 2083 if (firstmatch == NULL) 2084 firstmatch = cur; 2085 else if (firstmatch != cur) 2086 return (Z_INSUFFICIENT_SPEC); 2087 } else { 2088 /* 2089 * If another property matched but this 2090 * one doesn't then reset firstmatch. 2091 */ 2092 if (firstmatch == cur) 2093 firstmatch = NULL; 2094 } 2095 } 2096 } 2097 if (firstmatch == NULL) 2098 return (Z_NO_RESOURCE_ID); 2099 2100 cur = firstmatch; 2101 2102 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match, 2103 sizeof (tabptr->zone_dev_match))) != Z_OK) 2104 return (err); 2105 2106 return (Z_OK); 2107 } 2108 2109 static int 2110 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr) 2111 { 2112 xmlNodePtr newnode, cur = handle->zone_dh_cur; 2113 int err; 2114 2115 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL); 2116 2117 if ((err = newprop(newnode, DTD_ATTR_MATCH, 2118 tabptr->zone_dev_match)) != Z_OK) 2119 return (err); 2120 2121 return (Z_OK); 2122 } 2123 2124 int 2125 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 2126 { 2127 int err; 2128 2129 if (tabptr == NULL) 2130 return (Z_INVAL); 2131 2132 if ((err = operation_prep(handle)) != Z_OK) 2133 return (err); 2134 2135 if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK) 2136 return (err); 2137 2138 return (Z_OK); 2139 } 2140 2141 static int 2142 zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr) 2143 { 2144 xmlNodePtr cur = handle->zone_dh_cur; 2145 int match_match; 2146 2147 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2148 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 2149 continue; 2150 2151 match_match = match_prop(cur, DTD_ATTR_MATCH, 2152 tabptr->zone_dev_match); 2153 2154 if (match_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_dev(zone_dochandle_t handle, struct zone_devtab *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_dev_core(handle, tabptr)) != Z_OK) 2175 return (err); 2176 2177 return (Z_OK); 2178 } 2179 2180 int 2181 zonecfg_modify_dev( 2182 zone_dochandle_t handle, 2183 struct zone_devtab *oldtabptr, 2184 struct zone_devtab *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_dev_core(handle, oldtabptr)) != Z_OK) 2195 return (err); 2196 2197 if ((err = zonecfg_add_dev_core(handle, newtabptr)) != Z_OK) 2198 return (err); 2199 2200 return (Z_OK); 2201 } 2202 2203 /* Lock to serialize all zonecfg_devwalks */ 2204 static pthread_mutex_t zonecfg_devwalk_lock = PTHREAD_MUTEX_INITIALIZER; 2205 /* 2206 * Global variables used to pass data from zonecfg_devwalk to the nftw 2207 * call-back (zonecfg_devwalk_cb). g_devwalk_data is really the void* 2208 * parameter and g_devwalk_cb is really the *cb parameter from zonecfg_devwalk. 2209 */ 2210 static void *g_devwalk_data; 2211 static int (*g_devwalk_cb)(const char *, uid_t, gid_t, mode_t, const char *, 2212 void *); 2213 static size_t g_devwalk_skip_prefix; 2214 2215 /* 2216 * This is the nftw call-back function used by zonecfg_devwalk. It is 2217 * responsible for calling the actual call-back that is passed in to 2218 * zonecfg_devwalk as the *cb argument. 2219 */ 2220 /* ARGSUSED2 */ 2221 static int 2222 zonecfg_devwalk_cb(const char *path, const struct stat *st, int f, 2223 struct FTW *ftw) 2224 { 2225 acl_t *acl; 2226 char *acl_txt = NULL; 2227 2228 /* skip all but character and block devices */ 2229 if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode)) 2230 return (0); 2231 2232 if ((acl_get(path, ACL_NO_TRIVIAL, &acl) == 0) && 2233 acl != NULL) { 2234 acl_txt = acl_totext(acl, ACL_NORESOLVE); 2235 acl_free(acl); 2236 } 2237 2238 if (strlen(path) <= g_devwalk_skip_prefix) 2239 return (0); 2240 2241 g_devwalk_cb(path + g_devwalk_skip_prefix, st->st_uid, st->st_gid, 2242 st->st_mode & S_IAMB, acl_txt != NULL ? acl_txt : "", 2243 g_devwalk_data); 2244 free(acl_txt); 2245 return (0); 2246 } 2247 2248 /* 2249 * Walk the dev tree for the zone specified by hdl and call the call-back (cb) 2250 * function for each entry in the tree. The call-back will be passed the 2251 * name, uid, gid, mode, acl string and the void *data input parameter 2252 * for each dev entry. 2253 * 2254 * Data is passed to the zonecfg_devwalk_cb through the global variables 2255 * g_devwalk_data, *g_devwalk_cb, and g_devwalk_skip_prefix. The 2256 * zonecfg_devwalk_cb function will actually call *cb. 2257 */ 2258 int 2259 zonecfg_devwalk(zone_dochandle_t hdl, 2260 int (*cb)(const char *, uid_t, gid_t, mode_t, const char *, void *), 2261 void *data) 2262 { 2263 char path[MAXPATHLEN]; 2264 int ret; 2265 2266 if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK) 2267 return (ret); 2268 2269 if (strlcat(path, "/dev", sizeof (path)) >= sizeof (path)) 2270 return (Z_TOO_BIG); 2271 g_devwalk_skip_prefix = strlen(path) + 1; 2272 2273 /* 2274 * We have to serialize all zonecfg_devwalks in the same process 2275 * (which should be fine), since nftw() is so badly designed. 2276 */ 2277 (void) pthread_mutex_lock(&zonecfg_devwalk_lock); 2278 2279 g_devwalk_data = data; 2280 g_devwalk_cb = cb; 2281 (void) nftw(path, zonecfg_devwalk_cb, 0, FTW_PHYS); 2282 2283 (void) pthread_mutex_unlock(&zonecfg_devwalk_lock); 2284 return (Z_OK); 2285 } 2286 2287 /* 2288 * Update the owner, group, mode and acl on the specified dev (inpath) for 2289 * the zone (hdl). This function can be used to fix up the dev tree after 2290 * attaching a migrated zone. 2291 */ 2292 int 2293 zonecfg_devperms_apply(zone_dochandle_t hdl, const char *inpath, uid_t owner, 2294 gid_t group, mode_t mode, const char *acltxt) 2295 { 2296 int ret; 2297 char path[MAXPATHLEN]; 2298 struct stat st; 2299 acl_t *aclp; 2300 2301 if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK) 2302 return (ret); 2303 2304 if (strlcat(path, "/dev/", sizeof (path)) >= sizeof (path)) 2305 return (Z_TOO_BIG); 2306 if (strlcat(path, inpath, sizeof (path)) >= sizeof (path)) 2307 return (Z_TOO_BIG); 2308 2309 if (stat(path, &st) == -1) 2310 return (Z_INVAL); 2311 2312 /* make sure we're only touching device nodes */ 2313 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) 2314 return (Z_INVAL); 2315 2316 if (chown(path, owner, group) == -1) 2317 return (Z_SYSTEM); 2318 2319 if (chmod(path, mode) == -1) 2320 return (Z_SYSTEM); 2321 2322 if ((acltxt == NULL) || (strcmp(acltxt, "") == 0)) 2323 return (Z_OK); 2324 2325 if (acl_fromtext(acltxt, &aclp) != 0) 2326 return (Z_SYSTEM); 2327 2328 errno = 0; 2329 if (acl_set(path, aclp) == -1) { 2330 free(aclp); 2331 return (Z_SYSTEM); 2332 } 2333 2334 free(aclp); 2335 return (Z_OK); 2336 } 2337 2338 /* 2339 * This is the set of devices which must be present in every zone. Users 2340 * can augment this list with additional device rules in their zone 2341 * configuration, but at present cannot remove any of the this set of 2342 * standard devices. All matching is done by /dev pathname (the "/dev" 2343 * part is implicit. Try to keep rules which match a large number of 2344 * devices (like the pts rule) first. 2345 */ 2346 static const char *standard_devs[] = { 2347 "pts/*", 2348 "ptmx", 2349 "random", 2350 "urandom", 2351 "poll", 2352 "pool", 2353 "kstat", 2354 "zero", 2355 "null", 2356 "crypto", 2357 "cryptoadm", 2358 "ticots", 2359 "ticotsord", 2360 "ticlts", 2361 "lo0", 2362 "lo1", 2363 "lo2", 2364 "lo3", 2365 "sad/user", 2366 "tty", 2367 "logindmux", 2368 "log", 2369 "conslog", 2370 "arp", 2371 "tcp", 2372 "tcp6", 2373 "udp", 2374 "udp6", 2375 "sysevent", 2376 #ifdef __sparc 2377 "openprom", 2378 #endif 2379 "cpu/self/cpuid", 2380 "dtrace/*", 2381 "dtrace/provider/*", 2382 "zfs", 2383 NULL 2384 }; 2385 2386 /* 2387 * This function finds everything mounted under a zone's rootpath. 2388 * This returns the number of mounts under rootpath, or -1 on error. 2389 * callback is called once per mount found with the first argument 2390 * pointing to the mount point. 2391 * 2392 * If the callback function returns non-zero zonecfg_find_mounts 2393 * aborts with an error. 2394 */ 2395 2396 int 2397 zonecfg_find_mounts(char *rootpath, int (*callback)(const char *, void *), 2398 void *priv) { 2399 FILE *mnttab; 2400 struct mnttab m; 2401 size_t l; 2402 int zfsl; 2403 int rv = 0; 2404 char zfs_path[MAXPATHLEN]; 2405 2406 assert(rootpath != NULL); 2407 2408 if ((zfsl = snprintf(zfs_path, sizeof (zfs_path), "%s/.zfs/", rootpath)) 2409 >= sizeof (zfs_path)) 2410 return (-1); 2411 2412 l = strlen(rootpath); 2413 2414 mnttab = fopen("/etc/mnttab", "r"); 2415 2416 if (mnttab == NULL) 2417 return (-1); 2418 2419 if (ioctl(fileno(mnttab), MNTIOC_SHOWHIDDEN, NULL) < 0) { 2420 rv = -1; 2421 goto out; 2422 } 2423 2424 while (!getmntent(mnttab, &m)) { 2425 if ((strncmp(rootpath, m.mnt_mountp, l) == 0) && 2426 (m.mnt_mountp[l] == '/') && 2427 (strncmp(zfs_path, m.mnt_mountp, zfsl) != 0)) { 2428 rv++; 2429 if (callback == NULL) 2430 continue; 2431 if (callback(m.mnt_mountp, priv)) { 2432 rv = -1; 2433 goto out; 2434 2435 } 2436 } 2437 } 2438 2439 out: 2440 (void) fclose(mnttab); 2441 return (rv); 2442 } 2443 2444 /* 2445 * This routine is used to determine if a given device should appear in the 2446 * zone represented by 'handle'. First it consults the list of "standard" 2447 * zone devices. Then it scans the user-supplied device entries. 2448 */ 2449 int 2450 zonecfg_match_dev(zone_dochandle_t handle, char *devpath, 2451 struct zone_devtab *out_match) 2452 { 2453 int err; 2454 boolean_t found = B_FALSE; 2455 char match[MAXPATHLEN]; 2456 const char **stdmatch; 2457 xmlNodePtr cur; 2458 2459 if (handle == NULL || devpath == NULL) 2460 return (Z_INVAL); 2461 2462 /* 2463 * Check the "standard" devices which we require to be present. 2464 */ 2465 for (stdmatch = &standard_devs[0]; *stdmatch != NULL; stdmatch++) { 2466 /* 2467 * fnmatch gives us simple but powerful shell-style matching. 2468 */ 2469 if (fnmatch(*stdmatch, devpath, FNM_PATHNAME) == 0) { 2470 if (!out_match) 2471 return (Z_OK); 2472 (void) snprintf(out_match->zone_dev_match, 2473 sizeof (out_match->zone_dev_match), 2474 "/dev/%s", *stdmatch); 2475 return (Z_OK); 2476 } 2477 } 2478 2479 /* 2480 * We got no hits in the set of standard devices. On to the user 2481 * supplied ones. 2482 */ 2483 if ((err = operation_prep(handle)) != Z_OK) { 2484 handle->zone_dh_cur = NULL; 2485 return (err); 2486 } 2487 2488 cur = handle->zone_dh_cur; 2489 cur = cur->xmlChildrenNode; 2490 if (cur == NULL) 2491 return (Z_NO_ENTRY); 2492 handle->zone_dh_cur = cur; 2493 2494 for (; cur != NULL; cur = cur->next) { 2495 char *m; 2496 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE) != 0) 2497 continue; 2498 if ((err = fetchprop(cur, DTD_ATTR_MATCH, match, 2499 sizeof (match))) != Z_OK) { 2500 handle->zone_dh_cur = handle->zone_dh_top; 2501 return (err); 2502 } 2503 m = match; 2504 /* 2505 * fnmatch gives us simple but powerful shell-style matching; 2506 * but first, we need to strip out /dev/ from the matching rule. 2507 */ 2508 if (strncmp(m, "/dev/", 5) == 0) 2509 m += 5; 2510 2511 if (fnmatch(m, devpath, FNM_PATHNAME) == 0) { 2512 found = B_TRUE; 2513 break; 2514 } 2515 } 2516 2517 if (!found) 2518 return (Z_NO_ENTRY); 2519 2520 if (!out_match) 2521 return (Z_OK); 2522 2523 (void) strlcpy(out_match->zone_dev_match, match, 2524 sizeof (out_match->zone_dev_match)); 2525 return (Z_OK); 2526 } 2527 2528 int 2529 zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2530 { 2531 xmlNodePtr cur, firstmatch; 2532 int err; 2533 char name[MAXNAMELEN], type[MAXNAMELEN], value[MAXNAMELEN]; 2534 2535 if (tabptr == NULL) 2536 return (Z_INVAL); 2537 2538 if ((err = operation_prep(handle)) != Z_OK) 2539 return (err); 2540 2541 cur = handle->zone_dh_cur; 2542 firstmatch = NULL; 2543 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2544 if (xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 2545 continue; 2546 if (strlen(tabptr->zone_attr_name) > 0) { 2547 if ((fetchprop(cur, DTD_ATTR_NAME, name, 2548 sizeof (name)) == Z_OK) && 2549 (strcmp(tabptr->zone_attr_name, name) == 0)) { 2550 if (firstmatch == NULL) 2551 firstmatch = cur; 2552 else 2553 return (Z_INSUFFICIENT_SPEC); 2554 } 2555 } 2556 if (strlen(tabptr->zone_attr_type) > 0) { 2557 if ((fetchprop(cur, DTD_ATTR_TYPE, type, 2558 sizeof (type)) == Z_OK)) { 2559 if (strcmp(tabptr->zone_attr_type, type) == 0) { 2560 if (firstmatch == NULL) 2561 firstmatch = cur; 2562 else if (firstmatch != cur) 2563 return (Z_INSUFFICIENT_SPEC); 2564 } else { 2565 /* 2566 * If another property matched but this 2567 * one doesn't then reset firstmatch. 2568 */ 2569 if (firstmatch == cur) 2570 firstmatch = NULL; 2571 } 2572 } 2573 } 2574 if (strlen(tabptr->zone_attr_value) > 0) { 2575 if ((fetchprop(cur, DTD_ATTR_VALUE, value, 2576 sizeof (value)) == Z_OK)) { 2577 if (strcmp(tabptr->zone_attr_value, value) == 2578 0) { 2579 if (firstmatch == NULL) 2580 firstmatch = cur; 2581 else if (firstmatch != cur) 2582 return (Z_INSUFFICIENT_SPEC); 2583 } else { 2584 /* 2585 * If another property matched but this 2586 * one doesn't then reset firstmatch. 2587 */ 2588 if (firstmatch == cur) 2589 firstmatch = NULL; 2590 } 2591 } 2592 } 2593 } 2594 if (firstmatch == NULL) 2595 return (Z_NO_RESOURCE_ID); 2596 2597 cur = firstmatch; 2598 2599 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name, 2600 sizeof (tabptr->zone_attr_name))) != Z_OK) 2601 return (err); 2602 2603 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type, 2604 sizeof (tabptr->zone_attr_type))) != Z_OK) 2605 return (err); 2606 2607 if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value, 2608 sizeof (tabptr->zone_attr_value))) != Z_OK) 2609 return (err); 2610 2611 return (Z_OK); 2612 } 2613 2614 static int 2615 zonecfg_add_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2616 { 2617 xmlNodePtr newnode, cur = handle->zone_dh_cur; 2618 int err; 2619 2620 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ATTR, NULL); 2621 err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_attr_name); 2622 if (err != Z_OK) 2623 return (err); 2624 err = newprop(newnode, DTD_ATTR_TYPE, tabptr->zone_attr_type); 2625 if (err != Z_OK) 2626 return (err); 2627 err = newprop(newnode, DTD_ATTR_VALUE, tabptr->zone_attr_value); 2628 if (err != Z_OK) 2629 return (err); 2630 return (Z_OK); 2631 } 2632 2633 int 2634 zonecfg_add_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2635 { 2636 int err; 2637 2638 if (tabptr == NULL) 2639 return (Z_INVAL); 2640 2641 if ((err = operation_prep(handle)) != Z_OK) 2642 return (err); 2643 2644 if ((err = zonecfg_add_attr_core(handle, tabptr)) != Z_OK) 2645 return (err); 2646 2647 return (Z_OK); 2648 } 2649 2650 static int 2651 zonecfg_delete_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2652 { 2653 xmlNodePtr cur = handle->zone_dh_cur; 2654 int name_match, type_match, value_match; 2655 2656 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2657 if (xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 2658 continue; 2659 2660 name_match = match_prop(cur, DTD_ATTR_NAME, 2661 tabptr->zone_attr_name); 2662 type_match = match_prop(cur, DTD_ATTR_TYPE, 2663 tabptr->zone_attr_type); 2664 value_match = match_prop(cur, DTD_ATTR_VALUE, 2665 tabptr->zone_attr_value); 2666 2667 if (name_match && type_match && value_match) { 2668 xmlUnlinkNode(cur); 2669 xmlFreeNode(cur); 2670 return (Z_OK); 2671 } 2672 } 2673 return (Z_NO_RESOURCE_ID); 2674 } 2675 2676 int 2677 zonecfg_delete_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2678 { 2679 int err; 2680 2681 if (tabptr == NULL) 2682 return (Z_INVAL); 2683 2684 if ((err = operation_prep(handle)) != Z_OK) 2685 return (err); 2686 2687 if ((err = zonecfg_delete_attr_core(handle, tabptr)) != Z_OK) 2688 return (err); 2689 2690 return (Z_OK); 2691 } 2692 2693 int 2694 zonecfg_modify_attr( 2695 zone_dochandle_t handle, 2696 struct zone_attrtab *oldtabptr, 2697 struct zone_attrtab *newtabptr) 2698 { 2699 int err; 2700 2701 if (oldtabptr == NULL || newtabptr == NULL) 2702 return (Z_INVAL); 2703 2704 if ((err = operation_prep(handle)) != Z_OK) 2705 return (err); 2706 2707 if ((err = zonecfg_delete_attr_core(handle, oldtabptr)) != Z_OK) 2708 return (err); 2709 2710 if ((err = zonecfg_add_attr_core(handle, newtabptr)) != Z_OK) 2711 return (err); 2712 2713 return (Z_OK); 2714 } 2715 2716 int 2717 zonecfg_get_attr_boolean(const struct zone_attrtab *attr, boolean_t *value) 2718 { 2719 if (attr == NULL) 2720 return (Z_INVAL); 2721 2722 if (strcmp(attr->zone_attr_type, DTD_ENTITY_BOOLEAN) != 0) 2723 return (Z_INVAL); 2724 2725 if (strcmp(attr->zone_attr_value, DTD_ENTITY_TRUE) == 0) { 2726 *value = B_TRUE; 2727 return (Z_OK); 2728 } 2729 if (strcmp(attr->zone_attr_value, DTD_ENTITY_FALSE) == 0) { 2730 *value = B_FALSE; 2731 return (Z_OK); 2732 } 2733 return (Z_INVAL); 2734 } 2735 2736 int 2737 zonecfg_get_attr_int(const struct zone_attrtab *attr, int64_t *value) 2738 { 2739 long long result; 2740 char *endptr; 2741 2742 if (attr == NULL) 2743 return (Z_INVAL); 2744 2745 if (strcmp(attr->zone_attr_type, DTD_ENTITY_INT) != 0) 2746 return (Z_INVAL); 2747 2748 errno = 0; 2749 result = strtoll(attr->zone_attr_value, &endptr, 10); 2750 if (errno != 0 || *endptr != '\0') 2751 return (Z_INVAL); 2752 *value = result; 2753 return (Z_OK); 2754 } 2755 2756 int 2757 zonecfg_get_attr_string(const struct zone_attrtab *attr, char *value, 2758 size_t val_sz) 2759 { 2760 if (attr == NULL) 2761 return (Z_INVAL); 2762 2763 if (strcmp(attr->zone_attr_type, DTD_ENTITY_STRING) != 0) 2764 return (Z_INVAL); 2765 2766 if (strlcpy(value, attr->zone_attr_value, val_sz) >= val_sz) 2767 return (Z_TOO_BIG); 2768 return (Z_OK); 2769 } 2770 2771 int 2772 zonecfg_get_attr_uint(const struct zone_attrtab *attr, uint64_t *value) 2773 { 2774 unsigned long long result; 2775 long long neg_result; 2776 char *endptr; 2777 2778 if (attr == NULL) 2779 return (Z_INVAL); 2780 2781 if (strcmp(attr->zone_attr_type, DTD_ENTITY_UINT) != 0) 2782 return (Z_INVAL); 2783 2784 errno = 0; 2785 result = strtoull(attr->zone_attr_value, &endptr, 10); 2786 if (errno != 0 || *endptr != '\0') 2787 return (Z_INVAL); 2788 errno = 0; 2789 neg_result = strtoll(attr->zone_attr_value, &endptr, 10); 2790 /* 2791 * Incredibly, strtoull("<negative number>", ...) will not fail but 2792 * return whatever (negative) number cast as a u_longlong_t, so we 2793 * need to look for this here. 2794 */ 2795 if (errno == 0 && neg_result < 0) 2796 return (Z_INVAL); 2797 *value = result; 2798 return (Z_OK); 2799 } 2800 2801 int 2802 zonecfg_lookup_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2803 { 2804 xmlNodePtr cur, val; 2805 char savedname[MAXNAMELEN]; 2806 struct zone_rctlvaltab *valptr; 2807 int err; 2808 2809 if (tabptr->zone_rctl_name == NULL || 2810 strlen(tabptr->zone_rctl_name) == 0) 2811 return (Z_INVAL); 2812 2813 if ((err = operation_prep(handle)) != Z_OK) 2814 return (err); 2815 2816 cur = handle->zone_dh_cur; 2817 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2818 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 2819 continue; 2820 if ((fetchprop(cur, DTD_ATTR_NAME, savedname, 2821 sizeof (savedname)) == Z_OK) && 2822 (strcmp(savedname, tabptr->zone_rctl_name) == 0)) { 2823 tabptr->zone_rctl_valptr = NULL; 2824 for (val = cur->xmlChildrenNode; val != NULL; 2825 val = val->next) { 2826 valptr = (struct zone_rctlvaltab *)malloc( 2827 sizeof (struct zone_rctlvaltab)); 2828 if (valptr == NULL) 2829 return (Z_NOMEM); 2830 if ((fetchprop(val, DTD_ATTR_PRIV, 2831 valptr->zone_rctlval_priv, 2832 sizeof (valptr->zone_rctlval_priv)) != 2833 Z_OK)) 2834 break; 2835 if ((fetchprop(val, DTD_ATTR_LIMIT, 2836 valptr->zone_rctlval_limit, 2837 sizeof (valptr->zone_rctlval_limit)) != 2838 Z_OK)) 2839 break; 2840 if ((fetchprop(val, DTD_ATTR_ACTION, 2841 valptr->zone_rctlval_action, 2842 sizeof (valptr->zone_rctlval_action)) != 2843 Z_OK)) 2844 break; 2845 if (zonecfg_add_rctl_value(tabptr, valptr) != 2846 Z_OK) 2847 break; 2848 } 2849 return (Z_OK); 2850 } 2851 } 2852 return (Z_NO_RESOURCE_ID); 2853 } 2854 2855 static int 2856 zonecfg_add_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2857 { 2858 xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode; 2859 struct zone_rctlvaltab *valptr; 2860 int err; 2861 2862 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_RCTL, NULL); 2863 err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_rctl_name); 2864 if (err != Z_OK) 2865 return (err); 2866 for (valptr = tabptr->zone_rctl_valptr; valptr != NULL; 2867 valptr = valptr->zone_rctlval_next) { 2868 valnode = xmlNewTextChild(newnode, NULL, 2869 DTD_ELEM_RCTLVALUE, NULL); 2870 err = newprop(valnode, DTD_ATTR_PRIV, 2871 valptr->zone_rctlval_priv); 2872 if (err != Z_OK) 2873 return (err); 2874 err = newprop(valnode, DTD_ATTR_LIMIT, 2875 valptr->zone_rctlval_limit); 2876 if (err != Z_OK) 2877 return (err); 2878 err = newprop(valnode, DTD_ATTR_ACTION, 2879 valptr->zone_rctlval_action); 2880 if (err != Z_OK) 2881 return (err); 2882 } 2883 return (Z_OK); 2884 } 2885 2886 int 2887 zonecfg_add_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2888 { 2889 int err; 2890 2891 if (tabptr == NULL || tabptr->zone_rctl_name == NULL) 2892 return (Z_INVAL); 2893 2894 if ((err = operation_prep(handle)) != Z_OK) 2895 return (err); 2896 2897 if ((err = zonecfg_add_rctl_core(handle, tabptr)) != Z_OK) 2898 return (err); 2899 2900 return (Z_OK); 2901 } 2902 2903 static int 2904 zonecfg_delete_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2905 { 2906 xmlNodePtr cur = handle->zone_dh_cur; 2907 xmlChar *savedname; 2908 int name_result; 2909 2910 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2911 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 2912 continue; 2913 2914 savedname = xmlGetProp(cur, DTD_ATTR_NAME); 2915 if (savedname == NULL) /* shouldn't happen */ 2916 continue; 2917 name_result = xmlStrcmp(savedname, 2918 (const xmlChar *) tabptr->zone_rctl_name); 2919 xmlFree(savedname); 2920 2921 if (name_result == 0) { 2922 xmlUnlinkNode(cur); 2923 xmlFreeNode(cur); 2924 return (Z_OK); 2925 } 2926 } 2927 return (Z_NO_RESOURCE_ID); 2928 } 2929 2930 int 2931 zonecfg_delete_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2932 { 2933 int err; 2934 2935 if (tabptr == NULL || tabptr->zone_rctl_name == NULL) 2936 return (Z_INVAL); 2937 2938 if ((err = operation_prep(handle)) != Z_OK) 2939 return (err); 2940 2941 if ((err = zonecfg_delete_rctl_core(handle, tabptr)) != Z_OK) 2942 return (err); 2943 2944 return (Z_OK); 2945 } 2946 2947 int 2948 zonecfg_modify_rctl( 2949 zone_dochandle_t handle, 2950 struct zone_rctltab *oldtabptr, 2951 struct zone_rctltab *newtabptr) 2952 { 2953 int err; 2954 2955 if (oldtabptr == NULL || oldtabptr->zone_rctl_name == NULL || 2956 newtabptr == NULL || newtabptr->zone_rctl_name == NULL) 2957 return (Z_INVAL); 2958 2959 if ((err = operation_prep(handle)) != Z_OK) 2960 return (err); 2961 2962 if ((err = zonecfg_delete_rctl_core(handle, oldtabptr)) != Z_OK) 2963 return (err); 2964 2965 if ((err = zonecfg_add_rctl_core(handle, newtabptr)) != Z_OK) 2966 return (err); 2967 2968 return (Z_OK); 2969 } 2970 2971 int 2972 zonecfg_add_rctl_value( 2973 struct zone_rctltab *tabptr, 2974 struct zone_rctlvaltab *valtabptr) 2975 { 2976 struct zone_rctlvaltab *last, *old, *new; 2977 rctlblk_t *rctlblk = alloca(rctlblk_size()); 2978 2979 last = tabptr->zone_rctl_valptr; 2980 for (old = last; old != NULL; old = old->zone_rctlval_next) 2981 last = old; /* walk to the end of the list */ 2982 new = valtabptr; /* alloc'd by caller */ 2983 new->zone_rctlval_next = NULL; 2984 if (zonecfg_construct_rctlblk(valtabptr, rctlblk) != Z_OK) 2985 return (Z_INVAL); 2986 if (!zonecfg_valid_rctlblk(rctlblk)) 2987 return (Z_INVAL); 2988 if (last == NULL) 2989 tabptr->zone_rctl_valptr = new; 2990 else 2991 last->zone_rctlval_next = new; 2992 return (Z_OK); 2993 } 2994 2995 int 2996 zonecfg_remove_rctl_value( 2997 struct zone_rctltab *tabptr, 2998 struct zone_rctlvaltab *valtabptr) 2999 { 3000 struct zone_rctlvaltab *last, *this, *next; 3001 3002 last = tabptr->zone_rctl_valptr; 3003 for (this = last; this != NULL; this = this->zone_rctlval_next) { 3004 if (strcmp(this->zone_rctlval_priv, 3005 valtabptr->zone_rctlval_priv) == 0 && 3006 strcmp(this->zone_rctlval_limit, 3007 valtabptr->zone_rctlval_limit) == 0 && 3008 strcmp(this->zone_rctlval_action, 3009 valtabptr->zone_rctlval_action) == 0) { 3010 next = this->zone_rctlval_next; 3011 if (this == tabptr->zone_rctl_valptr) 3012 tabptr->zone_rctl_valptr = next; 3013 else 3014 last->zone_rctlval_next = next; 3015 free(this); 3016 return (Z_OK); 3017 } else 3018 last = this; 3019 } 3020 return (Z_NO_PROPERTY_ID); 3021 } 3022 3023 char * 3024 zonecfg_strerror(int errnum) 3025 { 3026 switch (errnum) { 3027 case Z_OK: 3028 return (dgettext(TEXT_DOMAIN, "OK")); 3029 case Z_EMPTY_DOCUMENT: 3030 return (dgettext(TEXT_DOMAIN, "Empty document")); 3031 case Z_WRONG_DOC_TYPE: 3032 return (dgettext(TEXT_DOMAIN, "Wrong document type")); 3033 case Z_BAD_PROPERTY: 3034 return (dgettext(TEXT_DOMAIN, "Bad document property")); 3035 case Z_TEMP_FILE: 3036 return (dgettext(TEXT_DOMAIN, 3037 "Problem creating temporary file")); 3038 case Z_SAVING_FILE: 3039 return (dgettext(TEXT_DOMAIN, "Problem saving file")); 3040 case Z_NO_ENTRY: 3041 return (dgettext(TEXT_DOMAIN, "No such entry")); 3042 case Z_BOGUS_ZONE_NAME: 3043 return (dgettext(TEXT_DOMAIN, "Bogus zone name")); 3044 case Z_REQD_RESOURCE_MISSING: 3045 return (dgettext(TEXT_DOMAIN, "Required resource missing")); 3046 case Z_REQD_PROPERTY_MISSING: 3047 return (dgettext(TEXT_DOMAIN, "Required property missing")); 3048 case Z_BAD_HANDLE: 3049 return (dgettext(TEXT_DOMAIN, "Bad handle")); 3050 case Z_NOMEM: 3051 return (dgettext(TEXT_DOMAIN, "Out of memory")); 3052 case Z_INVAL: 3053 return (dgettext(TEXT_DOMAIN, "Invalid argument")); 3054 case Z_ACCES: 3055 return (dgettext(TEXT_DOMAIN, "Permission denied")); 3056 case Z_TOO_BIG: 3057 return (dgettext(TEXT_DOMAIN, "Argument list too long")); 3058 case Z_MISC_FS: 3059 return (dgettext(TEXT_DOMAIN, 3060 "Miscellaneous file system error")); 3061 case Z_NO_ZONE: 3062 return (dgettext(TEXT_DOMAIN, "No such zone configured")); 3063 case Z_NO_RESOURCE_TYPE: 3064 return (dgettext(TEXT_DOMAIN, "No such resource type")); 3065 case Z_NO_RESOURCE_ID: 3066 return (dgettext(TEXT_DOMAIN, "No such resource with that id")); 3067 case Z_NO_PROPERTY_TYPE: 3068 return (dgettext(TEXT_DOMAIN, "No such property type")); 3069 case Z_NO_PROPERTY_ID: 3070 return (dgettext(TEXT_DOMAIN, "No such property with that id")); 3071 case Z_BAD_ZONE_STATE: 3072 return (dgettext(TEXT_DOMAIN, 3073 "Zone state is invalid for the requested operation")); 3074 case Z_INVALID_DOCUMENT: 3075 return (dgettext(TEXT_DOMAIN, "Invalid document")); 3076 case Z_NAME_IN_USE: 3077 return (dgettext(TEXT_DOMAIN, "Zone name already in use")); 3078 case Z_NO_SUCH_ID: 3079 return (dgettext(TEXT_DOMAIN, "No such zone ID")); 3080 case Z_UPDATING_INDEX: 3081 return (dgettext(TEXT_DOMAIN, "Problem updating index file")); 3082 case Z_LOCKING_FILE: 3083 return (dgettext(TEXT_DOMAIN, "Locking index file")); 3084 case Z_UNLOCKING_FILE: 3085 return (dgettext(TEXT_DOMAIN, "Unlocking index file")); 3086 case Z_INSUFFICIENT_SPEC: 3087 return (dgettext(TEXT_DOMAIN, "Insufficient specification")); 3088 case Z_RESOLVED_PATH: 3089 return (dgettext(TEXT_DOMAIN, "Resolved path mismatch")); 3090 case Z_IPV6_ADDR_PREFIX_LEN: 3091 return (dgettext(TEXT_DOMAIN, 3092 "IPv6 address missing required prefix length")); 3093 case Z_BOGUS_ADDRESS: 3094 return (dgettext(TEXT_DOMAIN, 3095 "Neither an IPv4 nor an IPv6 address nor a host name")); 3096 case Z_PRIV_PROHIBITED: 3097 return (dgettext(TEXT_DOMAIN, 3098 "Specified privilege is prohibited")); 3099 case Z_PRIV_REQUIRED: 3100 return (dgettext(TEXT_DOMAIN, 3101 "Required privilege is missing")); 3102 case Z_PRIV_UNKNOWN: 3103 return (dgettext(TEXT_DOMAIN, 3104 "Specified privilege is unknown")); 3105 default: 3106 return (dgettext(TEXT_DOMAIN, "Unknown error")); 3107 } 3108 } 3109 3110 /* 3111 * Note that the zonecfg_setXent() and zonecfg_endXent() calls are all the 3112 * same, as they just turn around and call zonecfg_setent() / zonecfg_endent(). 3113 */ 3114 3115 static int 3116 zonecfg_setent(zone_dochandle_t handle) 3117 { 3118 xmlNodePtr cur; 3119 int err; 3120 3121 if (handle == NULL) 3122 return (Z_INVAL); 3123 3124 if ((err = operation_prep(handle)) != Z_OK) { 3125 handle->zone_dh_cur = NULL; 3126 return (err); 3127 } 3128 cur = handle->zone_dh_cur; 3129 cur = cur->xmlChildrenNode; 3130 handle->zone_dh_cur = cur; 3131 return (Z_OK); 3132 } 3133 3134 static int 3135 zonecfg_endent(zone_dochandle_t handle) 3136 { 3137 if (handle == NULL) 3138 return (Z_INVAL); 3139 3140 handle->zone_dh_cur = handle->zone_dh_top; 3141 return (Z_OK); 3142 } 3143 3144 int 3145 zonecfg_setfsent(zone_dochandle_t handle) 3146 { 3147 return (zonecfg_setent(handle)); 3148 } 3149 3150 int 3151 zonecfg_getfsent(zone_dochandle_t handle, struct zone_fstab *tabptr) 3152 { 3153 xmlNodePtr cur, options; 3154 char options_str[MAX_MNTOPT_STR]; 3155 int err; 3156 3157 if (handle == NULL) 3158 return (Z_INVAL); 3159 3160 if ((cur = handle->zone_dh_cur) == NULL) 3161 return (Z_NO_ENTRY); 3162 3163 for (; cur != NULL; cur = cur->next) 3164 if (!xmlStrcmp(cur->name, DTD_ELEM_FS)) 3165 break; 3166 if (cur == NULL) { 3167 handle->zone_dh_cur = handle->zone_dh_top; 3168 return (Z_NO_ENTRY); 3169 } 3170 3171 if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special, 3172 sizeof (tabptr->zone_fs_special))) != Z_OK) { 3173 handle->zone_dh_cur = handle->zone_dh_top; 3174 return (err); 3175 } 3176 3177 if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw, 3178 sizeof (tabptr->zone_fs_raw))) != Z_OK) { 3179 handle->zone_dh_cur = handle->zone_dh_top; 3180 return (err); 3181 } 3182 3183 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 3184 sizeof (tabptr->zone_fs_dir))) != Z_OK) { 3185 handle->zone_dh_cur = handle->zone_dh_top; 3186 return (err); 3187 } 3188 3189 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type, 3190 sizeof (tabptr->zone_fs_type))) != Z_OK) { 3191 handle->zone_dh_cur = handle->zone_dh_top; 3192 return (err); 3193 } 3194 3195 /* OK for options to be NULL */ 3196 tabptr->zone_fs_options = NULL; 3197 for (options = cur->xmlChildrenNode; options != NULL; 3198 options = options->next) { 3199 if (fetchprop(options, DTD_ATTR_NAME, options_str, 3200 sizeof (options_str)) != Z_OK) 3201 break; 3202 if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK) 3203 break; 3204 } 3205 3206 handle->zone_dh_cur = cur->next; 3207 return (Z_OK); 3208 } 3209 3210 int 3211 zonecfg_endfsent(zone_dochandle_t handle) 3212 { 3213 return (zonecfg_endent(handle)); 3214 } 3215 3216 int 3217 zonecfg_setipdent(zone_dochandle_t handle) 3218 { 3219 return (zonecfg_setent(handle)); 3220 } 3221 3222 int 3223 zonecfg_getipdent(zone_dochandle_t handle, struct zone_fstab *tabptr) 3224 { 3225 xmlNodePtr cur; 3226 int err; 3227 3228 if (handle == NULL) 3229 return (Z_INVAL); 3230 3231 if ((cur = handle->zone_dh_cur) == NULL) 3232 return (Z_NO_ENTRY); 3233 3234 for (; cur != NULL; cur = cur->next) 3235 if (!xmlStrcmp(cur->name, DTD_ELEM_IPD)) 3236 break; 3237 if (cur == NULL) { 3238 handle->zone_dh_cur = handle->zone_dh_top; 3239 return (Z_NO_ENTRY); 3240 } 3241 3242 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 3243 sizeof (tabptr->zone_fs_dir))) != Z_OK) { 3244 handle->zone_dh_cur = handle->zone_dh_top; 3245 return (err); 3246 } 3247 3248 handle->zone_dh_cur = cur->next; 3249 return (Z_OK); 3250 } 3251 3252 int 3253 zonecfg_endipdent(zone_dochandle_t handle) 3254 { 3255 return (zonecfg_endent(handle)); 3256 } 3257 3258 int 3259 zonecfg_setnwifent(zone_dochandle_t handle) 3260 { 3261 return (zonecfg_setent(handle)); 3262 } 3263 3264 int 3265 zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 3266 { 3267 xmlNodePtr cur; 3268 int err; 3269 3270 if (handle == NULL) 3271 return (Z_INVAL); 3272 3273 if ((cur = handle->zone_dh_cur) == NULL) 3274 return (Z_NO_ENTRY); 3275 3276 for (; cur != NULL; cur = cur->next) 3277 if (!xmlStrcmp(cur->name, DTD_ELEM_NET)) 3278 break; 3279 if (cur == NULL) { 3280 handle->zone_dh_cur = handle->zone_dh_top; 3281 return (Z_NO_ENTRY); 3282 } 3283 3284 if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address, 3285 sizeof (tabptr->zone_nwif_address))) != Z_OK) { 3286 handle->zone_dh_cur = handle->zone_dh_top; 3287 return (err); 3288 } 3289 3290 if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical, 3291 sizeof (tabptr->zone_nwif_physical))) != Z_OK) { 3292 handle->zone_dh_cur = handle->zone_dh_top; 3293 return (err); 3294 } 3295 3296 handle->zone_dh_cur = cur->next; 3297 return (Z_OK); 3298 } 3299 3300 int 3301 zonecfg_endnwifent(zone_dochandle_t handle) 3302 { 3303 return (zonecfg_endent(handle)); 3304 } 3305 3306 int 3307 zonecfg_setdevent(zone_dochandle_t handle) 3308 { 3309 return (zonecfg_setent(handle)); 3310 } 3311 3312 int 3313 zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr) 3314 { 3315 xmlNodePtr cur; 3316 int err; 3317 3318 if (handle == NULL) 3319 return (Z_INVAL); 3320 3321 if ((cur = handle->zone_dh_cur) == NULL) 3322 return (Z_NO_ENTRY); 3323 3324 for (; cur != NULL; cur = cur->next) 3325 if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 3326 break; 3327 if (cur == NULL) { 3328 handle->zone_dh_cur = handle->zone_dh_top; 3329 return (Z_NO_ENTRY); 3330 } 3331 3332 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match, 3333 sizeof (tabptr->zone_dev_match))) != Z_OK) { 3334 handle->zone_dh_cur = handle->zone_dh_top; 3335 return (err); 3336 } 3337 3338 handle->zone_dh_cur = cur->next; 3339 return (Z_OK); 3340 } 3341 3342 int 3343 zonecfg_enddevent(zone_dochandle_t handle) 3344 { 3345 return (zonecfg_endent(handle)); 3346 } 3347 3348 int 3349 zonecfg_setrctlent(zone_dochandle_t handle) 3350 { 3351 return (zonecfg_setent(handle)); 3352 } 3353 3354 int 3355 zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr) 3356 { 3357 xmlNodePtr cur, val; 3358 struct zone_rctlvaltab *valptr; 3359 int err; 3360 3361 if (handle == NULL) 3362 return (Z_INVAL); 3363 3364 if ((cur = handle->zone_dh_cur) == NULL) 3365 return (Z_NO_ENTRY); 3366 3367 for (; cur != NULL; cur = cur->next) 3368 if (!xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 3369 break; 3370 if (cur == NULL) { 3371 handle->zone_dh_cur = handle->zone_dh_top; 3372 return (Z_NO_ENTRY); 3373 } 3374 3375 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_rctl_name, 3376 sizeof (tabptr->zone_rctl_name))) != Z_OK) { 3377 handle->zone_dh_cur = handle->zone_dh_top; 3378 return (err); 3379 } 3380 3381 tabptr->zone_rctl_valptr = NULL; 3382 for (val = cur->xmlChildrenNode; val != NULL; val = val->next) { 3383 valptr = (struct zone_rctlvaltab *)malloc( 3384 sizeof (struct zone_rctlvaltab)); 3385 if (valptr == NULL) 3386 return (Z_NOMEM); 3387 if (fetchprop(val, DTD_ATTR_PRIV, valptr->zone_rctlval_priv, 3388 sizeof (valptr->zone_rctlval_priv)) != Z_OK) 3389 break; 3390 if (fetchprop(val, DTD_ATTR_LIMIT, valptr->zone_rctlval_limit, 3391 sizeof (valptr->zone_rctlval_limit)) != Z_OK) 3392 break; 3393 if (fetchprop(val, DTD_ATTR_ACTION, valptr->zone_rctlval_action, 3394 sizeof (valptr->zone_rctlval_action)) != Z_OK) 3395 break; 3396 if (zonecfg_add_rctl_value(tabptr, valptr) != Z_OK) 3397 break; 3398 } 3399 3400 handle->zone_dh_cur = cur->next; 3401 return (Z_OK); 3402 } 3403 3404 int 3405 zonecfg_endrctlent(zone_dochandle_t handle) 3406 { 3407 return (zonecfg_endent(handle)); 3408 } 3409 3410 int 3411 zonecfg_setattrent(zone_dochandle_t handle) 3412 { 3413 return (zonecfg_setent(handle)); 3414 } 3415 3416 int 3417 zonecfg_getattrent(zone_dochandle_t handle, struct zone_attrtab *tabptr) 3418 { 3419 xmlNodePtr cur; 3420 int err; 3421 3422 if (handle == NULL) 3423 return (Z_INVAL); 3424 3425 if ((cur = handle->zone_dh_cur) == NULL) 3426 return (Z_NO_ENTRY); 3427 3428 for (; cur != NULL; cur = cur->next) 3429 if (!xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 3430 break; 3431 if (cur == NULL) { 3432 handle->zone_dh_cur = handle->zone_dh_top; 3433 return (Z_NO_ENTRY); 3434 } 3435 3436 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name, 3437 sizeof (tabptr->zone_attr_name))) != Z_OK) { 3438 handle->zone_dh_cur = handle->zone_dh_top; 3439 return (err); 3440 } 3441 3442 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type, 3443 sizeof (tabptr->zone_attr_type))) != Z_OK) { 3444 handle->zone_dh_cur = handle->zone_dh_top; 3445 return (err); 3446 } 3447 3448 if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value, 3449 sizeof (tabptr->zone_attr_value))) != Z_OK) { 3450 handle->zone_dh_cur = handle->zone_dh_top; 3451 return (err); 3452 } 3453 3454 handle->zone_dh_cur = cur->next; 3455 return (Z_OK); 3456 } 3457 3458 int 3459 zonecfg_endattrent(zone_dochandle_t handle) 3460 { 3461 return (zonecfg_endent(handle)); 3462 } 3463 3464 /* 3465 * The privileges available on the system and described in privileges(5) 3466 * fall into four categories with respect to non-global zones; those that 3467 * are required in order for a non-global zone to boot, those which are in 3468 * the default set of privileges available to non-global zones, those 3469 * privileges which should not be allowed to be given to non-global zones 3470 * and all other privileges, which are optional and potentially useful for 3471 * processes executing inside a non-global zone. 3472 * 3473 * When privileges are added to the system, a determination needs to be 3474 * made as to which category the privilege belongs to. Ideally, 3475 * privileges should be fine-grained enough and the mechanisms they cover 3476 * virtualized enough so that they can be made available to non-global 3477 * zones. 3478 */ 3479 3480 /* 3481 * Set of privileges required in order to get a zone booted and init(1M) 3482 * started. These cannot be removed from the zone's privilege set. 3483 */ 3484 static const char *required_priv_list[] = { 3485 PRIV_PROC_EXEC, 3486 PRIV_PROC_FORK, 3487 PRIV_SYS_MOUNT, 3488 NULL 3489 }; 3490 3491 /* 3492 * Default set of privileges considered safe for all non-global zones. 3493 * These privileges are "safe" in the sense that a privileged process in 3494 * the zone cannot affect processes in other non-global zones on the 3495 * system or in the global zone. Privileges which are considered by 3496 * default, "unsafe", include ones which affect a global resource, such as 3497 * the system clock or physical memory. 3498 */ 3499 static const char *default_priv_list[] = { 3500 PRIV_CONTRACT_EVENT, 3501 PRIV_CONTRACT_OBSERVER, 3502 PRIV_FILE_CHOWN, 3503 PRIV_FILE_CHOWN_SELF, 3504 PRIV_FILE_DAC_EXECUTE, 3505 PRIV_FILE_DAC_READ, 3506 PRIV_FILE_DAC_SEARCH, 3507 PRIV_FILE_DAC_WRITE, 3508 PRIV_FILE_OWNER, 3509 PRIV_FILE_SETID, 3510 PRIV_IPC_DAC_READ, 3511 PRIV_IPC_DAC_WRITE, 3512 PRIV_IPC_OWNER, 3513 PRIV_NET_BINDMLP, 3514 PRIV_NET_ICMPACCESS, 3515 PRIV_NET_MAC_AWARE, 3516 PRIV_NET_PRIVADDR, 3517 PRIV_PROC_CHROOT, 3518 PRIV_SYS_AUDIT, 3519 PRIV_PROC_AUDIT, 3520 PRIV_PROC_OWNER, 3521 PRIV_PROC_SETID, 3522 PRIV_PROC_TASKID, 3523 PRIV_SYS_ACCT, 3524 PRIV_SYS_ADMIN, 3525 PRIV_SYS_MOUNT, 3526 PRIV_SYS_NFS, 3527 PRIV_SYS_RESOURCE, 3528 NULL 3529 }; 3530 3531 /* 3532 * Set of privileges not currently permitted within a non-global zone. 3533 * Some of these privileges are overly broad and cover more than one 3534 * mechanism in the system. In other cases, there has not been sufficient 3535 * virtualization in the parts of the system the privilege covers to allow 3536 * its use within a non-global zone. 3537 */ 3538 static const char *prohibited_priv_list[] = { 3539 PRIV_DTRACE_KERNEL, 3540 PRIV_PROC_ZONE, 3541 PRIV_SYS_CONFIG, 3542 PRIV_SYS_DEVICES, 3543 PRIV_SYS_LINKDIR, 3544 PRIV_SYS_NET_CONFIG, 3545 PRIV_SYS_RES_CONFIG, 3546 PRIV_SYS_SUSER_COMPAT, 3547 NULL 3548 }; 3549 3550 /* 3551 * Define some of the tokens that priv_str_to_set(3C) recognizes. Since 3552 * the privilege string separator can be any character, although it is 3553 * usually a comma character, define these here as well in the event that 3554 * they change or are augmented in the future. 3555 */ 3556 #define BASIC_TOKEN "basic" 3557 #define DEFAULT_TOKEN "default" 3558 #define ZONE_TOKEN "zone" 3559 #define TOKEN_PRIV_CHAR ',' 3560 #define TOKEN_PRIV_STR "," 3561 3562 int 3563 zonecfg_default_privset(priv_set_t *privs) 3564 { 3565 const char **strp; 3566 priv_set_t *basic; 3567 3568 basic = priv_str_to_set(BASIC_TOKEN, TOKEN_PRIV_STR, NULL); 3569 if (basic == NULL) 3570 return (errno == ENOMEM ? Z_NOMEM : Z_INVAL); 3571 3572 priv_union(basic, privs); 3573 priv_freeset(basic); 3574 3575 for (strp = default_priv_list; *strp != NULL; strp++) { 3576 if (priv_addset(privs, *strp) != 0) { 3577 return (Z_INVAL); 3578 } 3579 } 3580 return (Z_OK); 3581 } 3582 3583 void 3584 append_priv_token(char *priv, char *str, size_t strlen) 3585 { 3586 if (*str != '\0') 3587 (void) strlcat(str, TOKEN_PRIV_STR, strlen); 3588 (void) strlcat(str, priv, strlen); 3589 } 3590 3591 /* 3592 * Verify that the supplied string is a valid privilege limit set for a 3593 * non-global zone. This string must not only be acceptable to 3594 * priv_str_to_set(3C) which parses it, but it also must resolve to a 3595 * privilege set that includes certain required privileges and lacks 3596 * certain prohibited privileges. 3597 */ 3598 static int 3599 verify_privset(char *privbuf, priv_set_t *privs, char **privname, 3600 boolean_t add_default) 3601 { 3602 char *cp; 3603 char *lasts; 3604 size_t len; 3605 priv_set_t *mergeset; 3606 const char **strp; 3607 char *tmp; 3608 const char *token; 3609 3610 /* 3611 * The verification of the privilege string occurs in several 3612 * phases. In the first phase, the supplied string is scanned for 3613 * the ZONE_TOKEN token which is not support as part of the 3614 * "limitpriv" property. 3615 * 3616 * Duplicate the supplied privilege string since strtok_r(3C) 3617 * tokenizes its input by null-terminating the tokens. 3618 */ 3619 if ((tmp = strdup(privbuf)) == NULL) 3620 return (Z_NOMEM); 3621 for (cp = strtok_r(tmp, TOKEN_PRIV_STR, &lasts); cp != NULL; 3622 cp = strtok_r(NULL, TOKEN_PRIV_STR, &lasts)) { 3623 if (strcmp(cp, ZONE_TOKEN) == 0) { 3624 free(tmp); 3625 if ((*privname = strdup(ZONE_TOKEN)) == NULL) 3626 return (Z_NOMEM); 3627 else 3628 return (Z_PRIV_UNKNOWN); 3629 } 3630 } 3631 free(tmp); 3632 3633 if (add_default) { 3634 /* 3635 * If DEFAULT_TOKEN was specified, a string needs to be 3636 * built containing the privileges from the default, safe 3637 * set along with those of the "limitpriv" property. 3638 */ 3639 len = strlen(privbuf) + sizeof (BASIC_TOKEN) + 2; 3640 for (strp = default_priv_list; *strp != NULL; strp++) 3641 len += strlen(*strp) + 1; 3642 tmp = alloca(len); 3643 *tmp = '\0'; 3644 3645 append_priv_token(BASIC_TOKEN, tmp, len); 3646 for (strp = default_priv_list; *strp != NULL; strp++) 3647 append_priv_token((char *)*strp, tmp, len); 3648 (void) strlcat(tmp, TOKEN_PRIV_STR, len); 3649 (void) strlcat(tmp, privbuf, len); 3650 } else { 3651 tmp = privbuf; 3652 } 3653 3654 3655 /* 3656 * In the next phase, attempt to convert the merged privilege 3657 * string into a privilege set. In the case of an error, either 3658 * there was a memory allocation failure or there was an invalid 3659 * privilege token in the string. In either case, return an 3660 * appropriate error code but in the event of an invalid token, 3661 * allocate a string containing its name and return that back to 3662 * the caller. 3663 */ 3664 mergeset = priv_str_to_set(tmp, TOKEN_PRIV_STR, &token); 3665 if (mergeset == NULL) { 3666 if (token == NULL) 3667 return (Z_NOMEM); 3668 if ((cp = strchr(token, TOKEN_PRIV_CHAR)) != NULL) 3669 *cp = '\0'; 3670 if ((*privname = strdup(token)) == NULL) 3671 return (Z_NOMEM); 3672 else 3673 return (Z_PRIV_UNKNOWN); 3674 } 3675 3676 /* 3677 * Next, verify that none of the prohibited zone privileges are 3678 * present in the merged privilege set. 3679 */ 3680 for (strp = prohibited_priv_list; *strp != NULL; strp++) { 3681 if (priv_ismember(mergeset, *strp)) { 3682 priv_freeset(mergeset); 3683 if ((*privname = strdup(*strp)) == NULL) 3684 return (Z_NOMEM); 3685 else 3686 return (Z_PRIV_PROHIBITED); 3687 } 3688 } 3689 3690 /* 3691 * Finally, verify that all of the required zone privileges are 3692 * present in the merged privilege set. 3693 */ 3694 for (strp = required_priv_list; *strp != NULL; strp++) { 3695 if (!priv_ismember(mergeset, *strp)) { 3696 priv_freeset(mergeset); 3697 if ((*privname = strdup(*strp)) == NULL) 3698 return (Z_NOMEM); 3699 else 3700 return (Z_PRIV_REQUIRED); 3701 } 3702 } 3703 3704 priv_copyset(mergeset, privs); 3705 priv_freeset(mergeset); 3706 return (Z_OK); 3707 } 3708 3709 /* 3710 * Fill in the supplied privilege set with either the default, safe set of 3711 * privileges suitable for a non-global zone, or one based on the 3712 * "limitpriv" property in the zone's configuration. 3713 * 3714 * In the event of an invalid privilege specification in the 3715 * configuration, a string is allocated and returned containing the 3716 * "privilege" causing the issue. It is the caller's responsibility to 3717 * free this memory when it is done with it. 3718 */ 3719 int 3720 zonecfg_get_privset(zone_dochandle_t handle, priv_set_t *privs, 3721 char **privname) 3722 { 3723 char *cp; 3724 int err; 3725 int limitlen; 3726 char *limitpriv = NULL; 3727 3728 /* 3729 * Attempt to lookup the "limitpriv" property. If it does not 3730 * exist or matches the string DEFAULT_TOKEN exactly, then the 3731 * default, safe privilege set is returned. 3732 */ 3733 err = zonecfg_get_limitpriv(handle, &limitpriv); 3734 if (err != Z_OK) 3735 return (err); 3736 limitlen = strlen(limitpriv); 3737 if (limitlen == 0 || strcmp(limitpriv, DEFAULT_TOKEN) == 0) { 3738 free(limitpriv); 3739 return (zonecfg_default_privset(privs)); 3740 } 3741 3742 /* 3743 * Check if the string DEFAULT_TOKEN is the first token in a list 3744 * of privileges. 3745 */ 3746 cp = strchr(limitpriv, TOKEN_PRIV_CHAR); 3747 if (cp != NULL && 3748 strncmp(limitpriv, DEFAULT_TOKEN, cp - limitpriv) == 0) 3749 err = verify_privset(cp + 1, privs, privname, B_TRUE); 3750 else 3751 err = verify_privset(limitpriv, privs, privname, B_FALSE); 3752 3753 free(limitpriv); 3754 return (err); 3755 } 3756 3757 int 3758 zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz) 3759 { 3760 zone_dochandle_t handle; 3761 boolean_t found = B_FALSE; 3762 struct zoneent *ze; 3763 FILE *cookie; 3764 int err; 3765 char *cp; 3766 3767 if (zone_name == NULL) 3768 return (Z_INVAL); 3769 3770 (void) strlcpy(zonepath, zonecfg_root, rp_sz); 3771 cp = zonepath + strlen(zonepath); 3772 while (cp > zonepath && cp[-1] == '/') 3773 *--cp = '\0'; 3774 3775 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) { 3776 if (zonepath[0] == '\0') 3777 (void) strlcpy(zonepath, "/", rp_sz); 3778 return (Z_OK); 3779 } 3780 3781 /* 3782 * First check the index file. Because older versions did not have 3783 * a copy of the zone path, allow for it to be zero length, in which 3784 * case we ignore this result and fall back to the XML files. 3785 */ 3786 cookie = setzoneent(); 3787 while ((ze = getzoneent_private(cookie)) != NULL) { 3788 if (strcmp(ze->zone_name, zone_name) == 0) { 3789 found = B_TRUE; 3790 if (ze->zone_path[0] != '\0') 3791 (void) strlcpy(cp, ze->zone_path, 3792 rp_sz - (cp - zonepath)); 3793 } 3794 free(ze); 3795 if (found) 3796 break; 3797 } 3798 endzoneent(cookie); 3799 if (found && *cp != '\0') 3800 return (Z_OK); 3801 3802 /* Fall back to the XML files. */ 3803 if ((handle = zonecfg_init_handle()) == NULL) 3804 return (Z_NOMEM); 3805 3806 /* 3807 * Check the snapshot first: if a zone is running, its zonepath 3808 * may have changed. 3809 */ 3810 if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) { 3811 if ((err = zonecfg_get_handle(zone_name, handle)) != Z_OK) 3812 return (err); 3813 } 3814 err = zonecfg_get_zonepath(handle, zonepath, rp_sz); 3815 zonecfg_fini_handle(handle); 3816 return (err); 3817 } 3818 3819 int 3820 zone_get_rootpath(char *zone_name, char *rootpath, size_t rp_sz) 3821 { 3822 int err; 3823 3824 /* This function makes sense for non-global zones only. */ 3825 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) 3826 return (Z_BOGUS_ZONE_NAME); 3827 if ((err = zone_get_zonepath(zone_name, rootpath, rp_sz)) != Z_OK) 3828 return (err); 3829 if (strlcat(rootpath, "/root", rp_sz) >= rp_sz) 3830 return (Z_TOO_BIG); 3831 return (Z_OK); 3832 } 3833 3834 static zone_state_t 3835 kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state) 3836 { 3837 char zoneroot[MAXPATHLEN]; 3838 size_t zlen; 3839 3840 assert(kernel_state <= ZONE_MAX_STATE); 3841 switch (kernel_state) { 3842 case ZONE_IS_UNINITIALIZED: 3843 return (ZONE_STATE_READY); 3844 case ZONE_IS_READY: 3845 /* 3846 * If the zone's root is mounted on $ZONEPATH/lu, then 3847 * it's a mounted scratch zone. 3848 */ 3849 if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot, 3850 sizeof (zoneroot)) >= 0) { 3851 zlen = strlen(zoneroot); 3852 if (zlen > 3 && 3853 strcmp(zoneroot + zlen - 3, "/lu") == 0) 3854 return (ZONE_STATE_MOUNTED); 3855 } 3856 return (ZONE_STATE_READY); 3857 case ZONE_IS_BOOTING: 3858 case ZONE_IS_RUNNING: 3859 return (ZONE_STATE_RUNNING); 3860 case ZONE_IS_SHUTTING_DOWN: 3861 case ZONE_IS_EMPTY: 3862 return (ZONE_STATE_SHUTTING_DOWN); 3863 case ZONE_IS_DOWN: 3864 case ZONE_IS_DYING: 3865 case ZONE_IS_DEAD: 3866 default: 3867 return (ZONE_STATE_DOWN); 3868 } 3869 /* NOTREACHED */ 3870 } 3871 3872 int 3873 zone_get_state(char *zone_name, zone_state_t *state_num) 3874 { 3875 zone_status_t status; 3876 zoneid_t zone_id; 3877 struct zoneent *ze; 3878 boolean_t found = B_FALSE; 3879 FILE *cookie; 3880 char kernzone[ZONENAME_MAX]; 3881 FILE *fp; 3882 3883 if (zone_name == NULL) 3884 return (Z_INVAL); 3885 3886 /* 3887 * If we're looking at an alternate root, then we need to query the 3888 * kernel using the scratch zone name. 3889 */ 3890 zone_id = -1; 3891 if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) { 3892 if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) { 3893 if (zonecfg_find_scratch(fp, zone_name, zonecfg_root, 3894 kernzone, sizeof (kernzone)) == 0) 3895 zone_id = getzoneidbyname(kernzone); 3896 zonecfg_close_scratch(fp); 3897 } 3898 } else { 3899 zone_id = getzoneidbyname(zone_name); 3900 } 3901 3902 /* check to see if zone is running */ 3903 if (zone_id != -1 && 3904 zone_getattr(zone_id, ZONE_ATTR_STATUS, &status, 3905 sizeof (status)) >= 0) { 3906 *state_num = kernel_state_to_user_state(zone_id, status); 3907 return (Z_OK); 3908 } 3909 3910 cookie = setzoneent(); 3911 while ((ze = getzoneent_private(cookie)) != NULL) { 3912 if (strcmp(ze->zone_name, zone_name) == 0) { 3913 found = B_TRUE; 3914 *state_num = ze->zone_state; 3915 } 3916 free(ze); 3917 if (found) 3918 break; 3919 } 3920 endzoneent(cookie); 3921 return ((found) ? Z_OK : Z_NO_ZONE); 3922 } 3923 3924 int 3925 zone_set_state(char *zone, zone_state_t state) 3926 { 3927 struct zoneent ze; 3928 3929 if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED && 3930 state != ZONE_STATE_INCOMPLETE) 3931 return (Z_INVAL); 3932 3933 bzero(&ze, sizeof (ze)); 3934 (void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name)); 3935 ze.zone_state = state; 3936 (void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path)); 3937 return (putzoneent(&ze, PZE_MODIFY)); 3938 } 3939 3940 /* 3941 * Get id (if any) for specified zone. There are four possible outcomes: 3942 * - If the string corresponds to the numeric id of an active (booted) 3943 * zone, sets *zip to the zone id and returns 0. 3944 * - If the string corresponds to the name of an active (booted) zone, 3945 * sets *zip to the zone id and returns 0. 3946 * - If the string is a name in the configuration but is not booted, 3947 * sets *zip to ZONE_ID_UNDEFINED and returns 0. 3948 * - Otherwise, leaves *zip unchanged and returns -1. 3949 * 3950 * This function acts as an auxiliary filter on the function of the same 3951 * name in libc; the linker binds to this version if libzonecfg exists, 3952 * and the libc version if it doesn't. Any changes to this version of 3953 * the function should probably be reflected in the libc version as well. 3954 */ 3955 int 3956 zone_get_id(const char *str, zoneid_t *zip) 3957 { 3958 zone_dochandle_t hdl; 3959 zoneid_t zoneid; 3960 char *cp; 3961 int err; 3962 3963 /* first try looking for active zone by id */ 3964 errno = 0; 3965 zoneid = (zoneid_t)strtol(str, &cp, 0); 3966 if (errno == 0 && cp != str && *cp == '\0' && 3967 getzonenamebyid(zoneid, NULL, 0) != -1) { 3968 *zip = zoneid; 3969 return (0); 3970 } 3971 3972 /* then look for active zone by name */ 3973 if ((zoneid = getzoneidbyname(str)) != -1) { 3974 *zip = zoneid; 3975 return (0); 3976 } 3977 3978 /* if in global zone, try looking up name in configuration database */ 3979 if (getzoneid() != GLOBAL_ZONEID || 3980 (hdl = zonecfg_init_handle()) == NULL) 3981 return (-1); 3982 3983 if (zonecfg_get_handle(str, hdl) == Z_OK) { 3984 /* zone exists but isn't active */ 3985 *zip = ZONE_ID_UNDEFINED; 3986 err = 0; 3987 } else { 3988 err = -1; 3989 } 3990 3991 zonecfg_fini_handle(hdl); 3992 return (err); 3993 } 3994 3995 char * 3996 zone_state_str(zone_state_t state_num) 3997 { 3998 switch (state_num) { 3999 case ZONE_STATE_CONFIGURED: 4000 return (ZONE_STATE_STR_CONFIGURED); 4001 case ZONE_STATE_INCOMPLETE: 4002 return (ZONE_STATE_STR_INCOMPLETE); 4003 case ZONE_STATE_INSTALLED: 4004 return (ZONE_STATE_STR_INSTALLED); 4005 case ZONE_STATE_READY: 4006 return (ZONE_STATE_STR_READY); 4007 case ZONE_STATE_MOUNTED: 4008 return (ZONE_STATE_STR_MOUNTED); 4009 case ZONE_STATE_RUNNING: 4010 return (ZONE_STATE_STR_RUNNING); 4011 case ZONE_STATE_SHUTTING_DOWN: 4012 return (ZONE_STATE_STR_SHUTTING_DOWN); 4013 case ZONE_STATE_DOWN: 4014 return (ZONE_STATE_STR_DOWN); 4015 default: 4016 return ("unknown"); 4017 } 4018 } 4019 4020 /* 4021 * Given a UUID value, find an associated zone name. This is intended to be 4022 * used by callers who set up some 'default' name (corresponding to the 4023 * expected name for the zone) in the zonename buffer, and thus the function 4024 * doesn't touch this buffer on failure. 4025 */ 4026 int 4027 zonecfg_get_name_by_uuid(const uuid_t uuidin, char *zonename, size_t namelen) 4028 { 4029 FILE *fp; 4030 struct zoneent *ze; 4031 uchar_t *uuid; 4032 4033 /* 4034 * A small amount of subterfuge via casts is necessary here because 4035 * libuuid doesn't use const correctly, but we don't want to export 4036 * this brokenness to our clients. 4037 */ 4038 uuid = (uchar_t *)uuidin; 4039 if (uuid_is_null(uuid)) 4040 return (Z_NO_ZONE); 4041 if ((fp = setzoneent()) == NULL) 4042 return (Z_NO_ZONE); 4043 while ((ze = getzoneent_private(fp)) != NULL) { 4044 if (uuid_compare(uuid, ze->zone_uuid) == 0) 4045 break; 4046 free(ze); 4047 } 4048 endzoneent(fp); 4049 if (ze != NULL) { 4050 (void) strlcpy(zonename, ze->zone_name, namelen); 4051 free(ze); 4052 return (Z_OK); 4053 } else { 4054 return (Z_NO_ZONE); 4055 } 4056 } 4057 4058 /* 4059 * Given a zone name, get its UUID. Returns a "NULL" UUID value if the zone 4060 * exists but the file doesn't have a value set yet. Returns an error if the 4061 * zone cannot be located. 4062 */ 4063 int 4064 zonecfg_get_uuid(const char *zonename, uuid_t uuid) 4065 { 4066 FILE *fp; 4067 struct zoneent *ze; 4068 4069 if ((fp = setzoneent()) == NULL) 4070 return (Z_NO_ZONE); 4071 while ((ze = getzoneent_private(fp)) != NULL) { 4072 if (strcmp(ze->zone_name, zonename) == 0) 4073 break; 4074 free(ze); 4075 } 4076 endzoneent(fp); 4077 if (ze != NULL) { 4078 uuid_copy(uuid, ze->zone_uuid); 4079 free(ze); 4080 return (Z_OK); 4081 } else { 4082 return (Z_NO_ZONE); 4083 } 4084 } 4085 4086 /* 4087 * File-system convenience functions. 4088 */ 4089 boolean_t 4090 zonecfg_valid_fs_type(const char *type) 4091 { 4092 /* 4093 * We already know which FS types don't work. 4094 */ 4095 if (strcmp(type, "proc") == 0 || 4096 strcmp(type, "mntfs") == 0 || 4097 strcmp(type, "autofs") == 0 || 4098 strncmp(type, "nfs", sizeof ("nfs") - 1) == 0 || 4099 strcmp(type, "cachefs") == 0) 4100 return (B_FALSE); 4101 /* 4102 * The caller may do more detailed verification to make sure other 4103 * aspects of this filesystem type make sense. 4104 */ 4105 return (B_TRUE); 4106 } 4107 4108 /* 4109 * Generally uninteresting rctl convenience functions. 4110 */ 4111 4112 int 4113 zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval, 4114 rctlblk_t *rctlblk) 4115 { 4116 unsigned long long ull; 4117 char *endp; 4118 rctl_priv_t priv; 4119 rctl_qty_t limit; 4120 uint_t action; 4121 4122 /* Get the privilege */ 4123 if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) { 4124 priv = RCPRIV_BASIC; 4125 } else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) { 4126 priv = RCPRIV_PRIVILEGED; 4127 } else { 4128 /* Invalid privilege */ 4129 return (Z_INVAL); 4130 } 4131 4132 /* deal with negative input; strtoull(3c) doesn't do what we want */ 4133 if (rctlval->zone_rctlval_limit[0] == '-') 4134 return (Z_INVAL); 4135 /* Get the limit */ 4136 errno = 0; 4137 ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0); 4138 if (errno != 0 || *endp != '\0') { 4139 /* parse failed */ 4140 return (Z_INVAL); 4141 } 4142 limit = (rctl_qty_t)ull; 4143 4144 /* Get the action */ 4145 if (strcmp(rctlval->zone_rctlval_action, "none") == 0) { 4146 action = RCTL_LOCAL_NOACTION; 4147 } else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) { 4148 action = RCTL_LOCAL_SIGNAL; 4149 } else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) { 4150 action = RCTL_LOCAL_DENY; 4151 } else { 4152 /* Invalid Action */ 4153 return (Z_INVAL); 4154 } 4155 rctlblk_set_local_action(rctlblk, action, 0); 4156 rctlblk_set_privilege(rctlblk, priv); 4157 rctlblk_set_value(rctlblk, limit); 4158 return (Z_OK); 4159 } 4160 4161 static int 4162 rctl_check(const char *rctlname, void *arg) 4163 { 4164 const char *attrname = arg; 4165 4166 /* 4167 * Returning 1 here is our signal to zonecfg_is_rctl() that it is 4168 * indeed an rctl name recognized by the system. 4169 */ 4170 return (strcmp(rctlname, attrname) == 0 ? 1 : 0); 4171 } 4172 4173 boolean_t 4174 zonecfg_is_rctl(const char *name) 4175 { 4176 return (rctl_walk(rctl_check, (void *)name) == 1); 4177 } 4178 4179 boolean_t 4180 zonecfg_valid_rctlname(const char *name) 4181 { 4182 const char *c; 4183 4184 if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0) 4185 return (B_FALSE); 4186 if (strlen(name) == sizeof ("zone.") - 1) 4187 return (B_FALSE); 4188 for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) { 4189 if (!isalpha(*c) && *c != '-') 4190 return (B_FALSE); 4191 } 4192 return (B_TRUE); 4193 } 4194 4195 boolean_t 4196 zonecfg_valid_rctlblk(const rctlblk_t *rctlblk) 4197 { 4198 rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk); 4199 uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL); 4200 4201 if (priv != RCPRIV_PRIVILEGED) 4202 return (B_FALSE); 4203 if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY) 4204 return (B_FALSE); 4205 return (B_TRUE); 4206 } 4207 4208 boolean_t 4209 zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk) 4210 { 4211 rctlblk_t *current, *next; 4212 rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk); 4213 uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL); 4214 uint_t global_flags; 4215 4216 if (!zonecfg_valid_rctlblk(rctlblk)) 4217 return (B_FALSE); 4218 if (!zonecfg_valid_rctlname(name)) 4219 return (B_FALSE); 4220 4221 current = alloca(rctlblk_size()); 4222 if (getrctl(name, NULL, current, RCTL_FIRST) != 0) 4223 return (B_TRUE); /* not an rctl on this system */ 4224 /* 4225 * Make sure the proposed value isn't greater than the current system 4226 * value. 4227 */ 4228 next = alloca(rctlblk_size()); 4229 while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) { 4230 rctlblk_t *tmp; 4231 4232 if (getrctl(name, current, next, RCTL_NEXT) != 0) 4233 return (B_FALSE); /* shouldn't happen */ 4234 tmp = current; 4235 current = next; 4236 next = tmp; 4237 } 4238 if (limit > rctlblk_get_value(current)) 4239 return (B_FALSE); 4240 4241 /* 4242 * Make sure the proposed action is allowed. 4243 */ 4244 global_flags = rctlblk_get_global_flags(current); 4245 if ((global_flags & RCTL_GLOBAL_DENY_NEVER) && 4246 action == RCTL_LOCAL_DENY) 4247 return (B_FALSE); 4248 if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) && 4249 action == RCTL_LOCAL_NOACTION) 4250 return (B_FALSE); 4251 4252 return (B_TRUE); 4253 } 4254 4255 /* 4256 * There is always a race condition between reading the initial copy of 4257 * a zones state and its state changing. We address this by providing 4258 * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions. 4259 * When zonecfg_critical_enter is called, sets the state field to LOCKED 4260 * and aquires biglock. Biglock protects against other threads executing 4261 * critical_enter and the state field protects against state changes during 4262 * the critical period. 4263 * 4264 * If any state changes occur, zn_cb will set the failed field of the znotify 4265 * structure. This will cause the critical_exit function to re-lock the 4266 * channel and return an error. Since evsnts may be delayed, the critical_exit 4267 * function "flushes" the queue by putting an event on the queue and waiting for 4268 * zn_cb to notify critical_exit that it received the ping event. 4269 */ 4270 static const char * 4271 string_get_tok(const char *in, char delim, int num) 4272 { 4273 int i = 0; 4274 4275 for (; i < num; in++) { 4276 if (*in == delim) 4277 i++; 4278 if (*in == 0) 4279 return (NULL); 4280 } 4281 return (in); 4282 } 4283 4284 static boolean_t 4285 is_ping(sysevent_t *ev) 4286 { 4287 if (strcmp(sysevent_get_subclass_name(ev), 4288 ZONE_EVENT_PING_SUBCLASS) == 0) { 4289 return (B_TRUE); 4290 } else { 4291 return (B_FALSE); 4292 } 4293 } 4294 4295 static boolean_t 4296 is_my_ping(sysevent_t *ev) 4297 { 4298 const char *sender; 4299 char mypid[sizeof (pid_t) * 3 + 1]; 4300 4301 (void) snprintf(mypid, sizeof (mypid), "%i", getpid()); 4302 sender = string_get_tok(sysevent_get_pub(ev), ':', 3); 4303 if (sender == NULL) 4304 return (B_FALSE); 4305 if (strcmp(sender, mypid) != 0) 4306 return (B_FALSE); 4307 return (B_TRUE); 4308 } 4309 4310 static int 4311 do_callback(struct znotify *zevtchan, sysevent_t *ev) 4312 { 4313 nvlist_t *l; 4314 int zid; 4315 char *zonename; 4316 char *newstate; 4317 char *oldstate; 4318 int ret; 4319 hrtime_t when; 4320 4321 if (strcmp(sysevent_get_subclass_name(ev), 4322 ZONE_EVENT_STATUS_SUBCLASS) == 0) { 4323 4324 if (sysevent_get_attr_list(ev, &l) != 0) { 4325 if (errno == ENOMEM) { 4326 zevtchan->zn_failure_count++; 4327 return (EAGAIN); 4328 } 4329 return (0); 4330 } 4331 ret = 0; 4332 4333 if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) && 4334 (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate) 4335 == 0) && 4336 (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate) 4337 == 0) && 4338 (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP, 4339 (uint64_t *)&when) == 0) && 4340 (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) { 4341 ret = zevtchan->zn_callback(zonename, zid, newstate, 4342 oldstate, when, zevtchan->zn_private); 4343 } 4344 4345 zevtchan->zn_failure_count = 0; 4346 nvlist_free(l); 4347 return (ret); 4348 } else { 4349 /* 4350 * We have received an event in an unknown subclass. Ignore. 4351 */ 4352 zevtchan->zn_failure_count = 0; 4353 return (0); 4354 } 4355 } 4356 4357 static int 4358 zn_cb(sysevent_t *ev, void *p) 4359 { 4360 struct znotify *zevtchan = p; 4361 int error; 4362 4363 (void) pthread_mutex_lock(&(zevtchan->zn_mutex)); 4364 4365 if (is_ping(ev) && !is_my_ping(ev)) { 4366 (void) pthread_mutex_unlock((&zevtchan->zn_mutex)); 4367 return (0); 4368 } 4369 4370 if (zevtchan->zn_state == ZN_LOCKED) { 4371 assert(!is_ping(ev)); 4372 zevtchan->zn_failed = B_TRUE; 4373 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4374 return (0); 4375 } 4376 4377 if (zevtchan->zn_state == ZN_PING_INFLIGHT) { 4378 if (is_ping(ev)) { 4379 zevtchan->zn_state = ZN_PING_RECEIVED; 4380 (void) pthread_cond_signal(&(zevtchan->zn_cond)); 4381 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4382 return (0); 4383 } else { 4384 zevtchan->zn_failed = B_TRUE; 4385 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4386 return (0); 4387 } 4388 } 4389 4390 if (zevtchan->zn_state == ZN_UNLOCKED) { 4391 4392 error = do_callback(zevtchan, ev); 4393 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4394 /* 4395 * Every ENOMEM failure causes do_callback to increment 4396 * zn_failure_count and every success causes it to 4397 * set zn_failure_count to zero. If we got EAGAIN, 4398 * we will sleep for zn_failure_count seconds and return 4399 * EAGAIN to gpec to try again. 4400 * 4401 * After 55 seconds, or 10 try's we give up and drop the 4402 * event. 4403 */ 4404 if (error == EAGAIN) { 4405 if (zevtchan->zn_failure_count > ZONE_CB_RETRY_COUNT) { 4406 return (0); 4407 } 4408 (void) sleep(zevtchan->zn_failure_count); 4409 } 4410 return (error); 4411 } 4412 4413 if (zevtchan->zn_state == ZN_PING_RECEIVED) { 4414 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4415 return (0); 4416 } 4417 4418 abort(); 4419 return (0); 4420 } 4421 4422 void 4423 zonecfg_notify_critical_enter(void *h) 4424 { 4425 struct znotify *zevtchan = h; 4426 4427 (void) pthread_mutex_lock(&(zevtchan->zn_bigmutex)); 4428 zevtchan->zn_state = ZN_LOCKED; 4429 } 4430 4431 int 4432 zonecfg_notify_critical_exit(void * h) 4433 { 4434 4435 struct znotify *zevtchan = h; 4436 4437 if (zevtchan->zn_state == ZN_UNLOCKED) 4438 return (0); 4439 4440 (void) pthread_mutex_lock(&(zevtchan->zn_mutex)); 4441 zevtchan->zn_state = ZN_PING_INFLIGHT; 4442 4443 (void) sysevent_evc_publish(zevtchan->zn_eventchan, 4444 ZONE_EVENT_STATUS_CLASS, 4445 ZONE_EVENT_PING_SUBCLASS, ZONE_EVENT_PING_PUBLISHER, 4446 zevtchan->zn_subscriber_id, NULL, EVCH_SLEEP); 4447 4448 while (zevtchan->zn_state != ZN_PING_RECEIVED) { 4449 (void) pthread_cond_wait(&(zevtchan->zn_cond), 4450 &(zevtchan->zn_mutex)); 4451 } 4452 4453 if (zevtchan->zn_failed == B_TRUE) { 4454 zevtchan->zn_state = ZN_LOCKED; 4455 zevtchan->zn_failed = B_FALSE; 4456 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4457 return (1); 4458 } 4459 4460 zevtchan->zn_state = ZN_UNLOCKED; 4461 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 4462 (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex)); 4463 return (0); 4464 } 4465 4466 void 4467 zonecfg_notify_critical_abort(void *h) 4468 { 4469 struct znotify *zevtchan = h; 4470 4471 zevtchan->zn_state = ZN_UNLOCKED; 4472 zevtchan->zn_failed = B_FALSE; 4473 /* 4474 * Don't do anything about zn_lock. If it is held, it could only be 4475 * held by zn_cb and it will be unlocked soon. 4476 */ 4477 (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex)); 4478 } 4479 4480 void * 4481 zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid, 4482 const char *newstate, const char *oldstate, hrtime_t when, void *p), 4483 void *p) 4484 { 4485 struct znotify *zevtchan; 4486 int i = 1; 4487 int r; 4488 4489 zevtchan = malloc(sizeof (struct znotify)); 4490 4491 if (zevtchan == NULL) 4492 return (NULL); 4493 4494 zevtchan->zn_private = p; 4495 zevtchan->zn_callback = func; 4496 zevtchan->zn_state = ZN_UNLOCKED; 4497 zevtchan->zn_failed = B_FALSE; 4498 4499 if (pthread_mutex_init(&(zevtchan->zn_mutex), NULL)) 4500 goto out3; 4501 if (pthread_cond_init(&(zevtchan->zn_cond), NULL)) { 4502 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex)); 4503 goto out3; 4504 } 4505 if (pthread_mutex_init(&(zevtchan->zn_bigmutex), NULL)) { 4506 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex)); 4507 (void) pthread_cond_destroy(&(zevtchan->zn_cond)); 4508 goto out3; 4509 } 4510 4511 if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &(zevtchan->zn_eventchan), 4512 0) != 0) 4513 goto out2; 4514 4515 do { 4516 /* 4517 * At 4 digits the subscriber ID gets too long and we have 4518 * no chance of successfully registering. 4519 */ 4520 if (i > 999) 4521 goto out1; 4522 4523 (void) sprintf(zevtchan->zn_subscriber_id, "zone_%li_%i", 4524 getpid() % 999999l, i); 4525 4526 r = sysevent_evc_subscribe(zevtchan->zn_eventchan, 4527 zevtchan->zn_subscriber_id, ZONE_EVENT_STATUS_CLASS, zn_cb, 4528 zevtchan, 0); 4529 4530 i++; 4531 4532 } while (r); 4533 4534 return (zevtchan); 4535 out1: 4536 sysevent_evc_unbind(zevtchan->zn_eventchan); 4537 out2: 4538 (void) pthread_mutex_destroy(&zevtchan->zn_mutex); 4539 (void) pthread_cond_destroy(&zevtchan->zn_cond); 4540 (void) pthread_mutex_destroy(&(zevtchan->zn_bigmutex)); 4541 out3: 4542 free(zevtchan); 4543 4544 return (NULL); 4545 } 4546 4547 void 4548 zonecfg_notify_unbind(void *handle) 4549 { 4550 4551 int ret; 4552 4553 sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan); 4554 /* 4555 * Check that all evc threads have gone away. This should be 4556 * enforced by sysevent_evc_unbind. 4557 */ 4558 ret = pthread_mutex_trylock(&((struct znotify *)handle)->zn_mutex); 4559 4560 if (ret) 4561 abort(); 4562 4563 (void) pthread_mutex_unlock(&((struct znotify *)handle)->zn_mutex); 4564 (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_mutex); 4565 (void) pthread_cond_destroy(&((struct znotify *)handle)->zn_cond); 4566 (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_bigmutex); 4567 4568 free(handle); 4569 } 4570 4571 static int 4572 zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr) 4573 { 4574 xmlNodePtr newnode, cur = handle->zone_dh_cur; 4575 int err; 4576 4577 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DATASET, NULL); 4578 if ((err = newprop(newnode, DTD_ATTR_NAME, 4579 tabptr->zone_dataset_name)) != Z_OK) 4580 return (err); 4581 return (Z_OK); 4582 } 4583 4584 int 4585 zonecfg_add_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 4586 { 4587 int err; 4588 4589 if (tabptr == NULL) 4590 return (Z_INVAL); 4591 4592 if ((err = operation_prep(handle)) != Z_OK) 4593 return (err); 4594 4595 if ((err = zonecfg_add_ds_core(handle, tabptr)) != Z_OK) 4596 return (err); 4597 4598 return (Z_OK); 4599 } 4600 4601 static int 4602 zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr) 4603 { 4604 xmlNodePtr cur = handle->zone_dh_cur; 4605 4606 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 4607 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 4608 continue; 4609 4610 if (match_prop(cur, DTD_ATTR_NAME, 4611 tabptr->zone_dataset_name)) { 4612 xmlUnlinkNode(cur); 4613 xmlFreeNode(cur); 4614 return (Z_OK); 4615 } 4616 } 4617 return (Z_NO_RESOURCE_ID); 4618 } 4619 4620 int 4621 zonecfg_delete_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 4622 { 4623 int err; 4624 4625 if (tabptr == NULL) 4626 return (Z_INVAL); 4627 4628 if ((err = operation_prep(handle)) != Z_OK) 4629 return (err); 4630 4631 if ((err = zonecfg_delete_ds_core(handle, tabptr)) != Z_OK) 4632 return (err); 4633 4634 return (Z_OK); 4635 } 4636 4637 int 4638 zonecfg_modify_ds( 4639 zone_dochandle_t handle, 4640 struct zone_dstab *oldtabptr, 4641 struct zone_dstab *newtabptr) 4642 { 4643 int err; 4644 4645 if (oldtabptr == NULL || newtabptr == NULL) 4646 return (Z_INVAL); 4647 4648 if ((err = operation_prep(handle)) != Z_OK) 4649 return (err); 4650 4651 if ((err = zonecfg_delete_ds_core(handle, oldtabptr)) != Z_OK) 4652 return (err); 4653 4654 if ((err = zonecfg_add_ds_core(handle, newtabptr)) != Z_OK) 4655 return (err); 4656 4657 return (Z_OK); 4658 } 4659 4660 int 4661 zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 4662 { 4663 xmlNodePtr cur, firstmatch; 4664 int err; 4665 char dataset[MAXNAMELEN]; 4666 4667 if (tabptr == NULL) 4668 return (Z_INVAL); 4669 4670 if ((err = operation_prep(handle)) != Z_OK) 4671 return (err); 4672 4673 cur = handle->zone_dh_cur; 4674 firstmatch = NULL; 4675 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 4676 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 4677 continue; 4678 if (strlen(tabptr->zone_dataset_name) > 0) { 4679 if ((fetchprop(cur, DTD_ATTR_NAME, dataset, 4680 sizeof (dataset)) == Z_OK) && 4681 (strcmp(tabptr->zone_dataset_name, 4682 dataset) == 0)) { 4683 if (firstmatch == NULL) 4684 firstmatch = cur; 4685 else 4686 return (Z_INSUFFICIENT_SPEC); 4687 } 4688 } 4689 } 4690 if (firstmatch == NULL) 4691 return (Z_NO_RESOURCE_ID); 4692 4693 cur = firstmatch; 4694 4695 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name, 4696 sizeof (tabptr->zone_dataset_name))) != Z_OK) 4697 return (err); 4698 4699 return (Z_OK); 4700 } 4701 4702 int 4703 zonecfg_setdsent(zone_dochandle_t handle) 4704 { 4705 return (zonecfg_setent(handle)); 4706 } 4707 4708 int 4709 zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr) 4710 { 4711 xmlNodePtr cur; 4712 int err; 4713 4714 if (handle == NULL) 4715 return (Z_INVAL); 4716 4717 if ((cur = handle->zone_dh_cur) == NULL) 4718 return (Z_NO_ENTRY); 4719 4720 for (; cur != NULL; cur = cur->next) 4721 if (!xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 4722 break; 4723 if (cur == NULL) { 4724 handle->zone_dh_cur = handle->zone_dh_top; 4725 return (Z_NO_ENTRY); 4726 } 4727 4728 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name, 4729 sizeof (tabptr->zone_dataset_name))) != Z_OK) { 4730 handle->zone_dh_cur = handle->zone_dh_top; 4731 return (err); 4732 } 4733 4734 handle->zone_dh_cur = cur->next; 4735 return (Z_OK); 4736 } 4737 4738 int 4739 zonecfg_enddsent(zone_dochandle_t handle) 4740 { 4741 return (zonecfg_endent(handle)); 4742 } 4743 4744 int 4745 zonecfg_setpkgent(zone_dochandle_t handle) 4746 { 4747 return (zonecfg_setent(handle)); 4748 } 4749 4750 int 4751 zonecfg_getpkgent(zone_dochandle_t handle, struct zone_pkgtab *tabptr) 4752 { 4753 xmlNodePtr cur; 4754 int err; 4755 4756 if (handle == NULL) 4757 return (Z_INVAL); 4758 4759 if ((cur = handle->zone_dh_cur) == NULL) 4760 return (Z_NO_ENTRY); 4761 4762 for (; cur != NULL; cur = cur->next) 4763 if (!xmlStrcmp(cur->name, DTD_ELEM_PACKAGE)) 4764 break; 4765 if (cur == NULL) { 4766 handle->zone_dh_cur = handle->zone_dh_top; 4767 return (Z_NO_ENTRY); 4768 } 4769 4770 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_pkg_name, 4771 sizeof (tabptr->zone_pkg_name))) != Z_OK) { 4772 handle->zone_dh_cur = handle->zone_dh_top; 4773 return (err); 4774 } 4775 4776 if ((err = fetchprop(cur, DTD_ATTR_VERSION, tabptr->zone_pkg_version, 4777 sizeof (tabptr->zone_pkg_version))) != Z_OK) { 4778 handle->zone_dh_cur = handle->zone_dh_top; 4779 return (err); 4780 } 4781 4782 handle->zone_dh_cur = cur->next; 4783 return (Z_OK); 4784 } 4785 4786 int 4787 zonecfg_endpkgent(zone_dochandle_t handle) 4788 { 4789 return (zonecfg_endent(handle)); 4790 } 4791 4792 int 4793 zonecfg_setpatchent(zone_dochandle_t handle) 4794 { 4795 return (zonecfg_setent(handle)); 4796 } 4797 4798 int 4799 zonecfg_getpatchent(zone_dochandle_t handle, struct zone_patchtab *tabptr) 4800 { 4801 xmlNodePtr cur; 4802 int err; 4803 4804 if (handle == NULL) 4805 return (Z_INVAL); 4806 4807 if ((cur = handle->zone_dh_cur) == NULL) 4808 return (Z_NO_ENTRY); 4809 4810 for (; cur != NULL; cur = cur->next) 4811 if (!xmlStrcmp(cur->name, DTD_ELEM_PATCH)) 4812 break; 4813 if (cur == NULL) { 4814 handle->zone_dh_cur = handle->zone_dh_top; 4815 return (Z_NO_ENTRY); 4816 } 4817 4818 if ((err = fetchprop(cur, DTD_ATTR_ID, tabptr->zone_patch_id, 4819 sizeof (tabptr->zone_patch_id))) != Z_OK) { 4820 handle->zone_dh_cur = handle->zone_dh_top; 4821 return (err); 4822 } 4823 4824 handle->zone_dh_cur = cur->next; 4825 return (Z_OK); 4826 } 4827 4828 int 4829 zonecfg_endpatchent(zone_dochandle_t handle) 4830 { 4831 return (zonecfg_endent(handle)); 4832 } 4833 4834 int 4835 zonecfg_setdevperment(zone_dochandle_t handle) 4836 { 4837 return (zonecfg_setent(handle)); 4838 } 4839 4840 int 4841 zonecfg_getdevperment(zone_dochandle_t handle, struct zone_devpermtab *tabptr) 4842 { 4843 xmlNodePtr cur; 4844 int err; 4845 char buf[128]; 4846 4847 tabptr->zone_devperm_acl = NULL; 4848 4849 if (handle == NULL) 4850 return (Z_INVAL); 4851 4852 if ((cur = handle->zone_dh_cur) == NULL) 4853 return (Z_NO_ENTRY); 4854 4855 for (; cur != NULL; cur = cur->next) 4856 if (!xmlStrcmp(cur->name, DTD_ELEM_DEV_PERM)) 4857 break; 4858 if (cur == NULL) { 4859 handle->zone_dh_cur = handle->zone_dh_top; 4860 return (Z_NO_ENTRY); 4861 } 4862 4863 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_devperm_name, 4864 sizeof (tabptr->zone_devperm_name))) != Z_OK) { 4865 handle->zone_dh_cur = handle->zone_dh_top; 4866 return (err); 4867 } 4868 4869 if ((err = fetchprop(cur, DTD_ATTR_UID, buf, sizeof (buf))) != Z_OK) { 4870 handle->zone_dh_cur = handle->zone_dh_top; 4871 return (err); 4872 } 4873 tabptr->zone_devperm_uid = (uid_t)atol(buf); 4874 4875 if ((err = fetchprop(cur, DTD_ATTR_GID, buf, sizeof (buf))) != Z_OK) { 4876 handle->zone_dh_cur = handle->zone_dh_top; 4877 return (err); 4878 } 4879 tabptr->zone_devperm_gid = (gid_t)atol(buf); 4880 4881 if ((err = fetchprop(cur, DTD_ATTR_MODE, buf, sizeof (buf))) != Z_OK) { 4882 handle->zone_dh_cur = handle->zone_dh_top; 4883 return (err); 4884 } 4885 tabptr->zone_devperm_mode = (mode_t)strtol(buf, (char **)NULL, 8); 4886 4887 if ((err = fetch_alloc_prop(cur, DTD_ATTR_ACL, 4888 &(tabptr->zone_devperm_acl))) != Z_OK) { 4889 handle->zone_dh_cur = handle->zone_dh_top; 4890 return (err); 4891 } 4892 4893 handle->zone_dh_cur = cur->next; 4894 return (Z_OK); 4895 } 4896 4897 int 4898 zonecfg_enddevperment(zone_dochandle_t handle) 4899 { 4900 return (zonecfg_endent(handle)); 4901 } 4902 4903 /* 4904 * Process a list of pkgs from an entry in the contents file, adding each pkg 4905 * name to the list of pkgs. 4906 * 4907 * It is possible for the pkg name to be preceeded by a special character 4908 * which indicates some bookkeeping information for pkging. Check if the 4909 * first char is not an Alpha char. If so, skip over it. 4910 */ 4911 static int 4912 add_pkg_list(char *lastp, char ***plist, int *pcnt) 4913 { 4914 char *p; 4915 int pkg_cnt = *pcnt; 4916 char **pkgs = *plist; 4917 int res = Z_OK; 4918 4919 while ((p = strtok_r(NULL, " ", &lastp)) != NULL) { 4920 char **tmpp; 4921 int i; 4922 4923 /* skip over any special pkg bookkeeping char */ 4924 if (!isalpha(*p)) 4925 p++; 4926 4927 /* Check if the pkg is already in the list */ 4928 for (i = 0; i < pkg_cnt; i++) { 4929 if (strcmp(p, pkgs[i]) == 0) 4930 break; 4931 } 4932 4933 if (i < pkg_cnt) 4934 continue; 4935 4936 /* The pkg is not in the list; add it. */ 4937 if ((tmpp = (char **)realloc(pkgs, 4938 sizeof (char *) * (pkg_cnt + 1))) == NULL) { 4939 res = Z_NOMEM; 4940 break; 4941 } 4942 pkgs = tmpp; 4943 4944 if ((pkgs[pkg_cnt] = strdup(p)) == NULL) { 4945 res = Z_NOMEM; 4946 break; 4947 } 4948 pkg_cnt++; 4949 } 4950 4951 *plist = pkgs; 4952 *pcnt = pkg_cnt; 4953 4954 return (res); 4955 } 4956 4957 /* 4958 * Process an entry from the contents file (type "directory") and if the 4959 * directory path is in the list of paths, add the associated list of pkgs 4960 * to the pkg list. The input parameter "entry" will be broken up by 4961 * the parser within this function so its value will be modified when this 4962 * function exits. 4963 * 4964 * The entries we are looking for will look something like: 4965 * /usr d none 0755 root sys SUNWctpls SUNWidnl SUNWlibCf .... 4966 */ 4967 static int 4968 get_path_pkgs(char *entry, char **paths, int cnt, char ***pkgs, int *pkg_cnt) 4969 { 4970 char *f1; 4971 char *f2; 4972 char *lastp; 4973 int i; 4974 int res = Z_OK; 4975 4976 if ((f1 = strtok_r(entry, " ", &lastp)) == NULL || 4977 (f2 = strtok_r(NULL, " ", &lastp)) == NULL || strcmp(f2, "d") != 0) 4978 return (Z_OK); 4979 4980 /* Check if this directory entry is in the list of paths. */ 4981 for (i = 0; i < cnt; i++) { 4982 if (fnmatch(paths[i], f1, FNM_PATHNAME) == 0) { 4983 /* 4984 * We do want the pkgs for this path. First, skip 4985 * over the next 4 fields in the entry so that we call 4986 * add_pkg_list starting with the pkg names. 4987 */ 4988 int j; 4989 char *nlp; 4990 4991 for (j = 0; j < 4 && 4992 strtok_r(NULL, " ", &lastp) != NULL; j++) 4993 ; 4994 /* 4995 * If there are < 4 fields this entry is corrupt, 4996 * just skip it. 4997 */ 4998 if (j < 4) 4999 return (Z_OK); 5000 5001 /* strip newline from the line */ 5002 nlp = (lastp + strlen(lastp) - 1); 5003 if (*nlp == '\n') 5004 *nlp = '\0'; 5005 5006 res = add_pkg_list(lastp, pkgs, pkg_cnt); 5007 break; 5008 } 5009 } 5010 5011 return (res); 5012 } 5013 5014 /* 5015 * Read an entry from a pkginfo or contents file. Some of these lines can 5016 * either be arbitrarily long or be continued by a backslash at the end of 5017 * the line. This function coalesces lines that are longer than the read 5018 * buffer, and lines that are continued, into one buffer which is returned. 5019 * The caller must free this memory. NULL is returned when we hit EOF or 5020 * if we run out of memory (errno is set to ENOMEM). 5021 */ 5022 static char * 5023 read_pkg_data(FILE *fp) 5024 { 5025 char *start; 5026 char *inp; 5027 char *p; 5028 int char_cnt = 0; 5029 5030 errno = 0; 5031 if ((start = (char *)malloc(PKGINFO_RD_LEN)) == NULL) { 5032 errno = ENOMEM; 5033 return (NULL); 5034 } 5035 5036 inp = start; 5037 while ((p = fgets(inp, PKGINFO_RD_LEN, fp)) != NULL) { 5038 int len; 5039 5040 len = strlen(inp); 5041 if (inp[len - 1] == '\n' && 5042 (len == 1 || inp[len - 2] != '\\')) { 5043 char_cnt = len; 5044 break; 5045 } 5046 5047 if (inp[len - 2] == '\\') 5048 char_cnt += len - 2; 5049 else 5050 char_cnt += PKGINFO_RD_LEN - 1; 5051 5052 if ((p = realloc(start, char_cnt + PKGINFO_RD_LEN)) == NULL) { 5053 errno = ENOMEM; 5054 break; 5055 } 5056 5057 start = p; 5058 inp = start + char_cnt; 5059 } 5060 5061 if (errno == ENOMEM || (p == NULL && char_cnt == 0)) { 5062 free(start); 5063 start = NULL; 5064 } 5065 5066 return (start); 5067 } 5068 5069 static void 5070 free_ipd_pkgs(char **pkgs, int cnt) 5071 { 5072 int i; 5073 5074 for (i = 0; i < cnt; i++) 5075 free(pkgs[i]); 5076 free(pkgs); 5077 } 5078 5079 /* 5080 * Get the list of inherited-pkg-dirs (ipd) for the zone and then get the 5081 * list of pkgs that deliver into those dirs. 5082 */ 5083 static int 5084 get_ipd_pkgs(zone_dochandle_t handle, char ***pkg_list, int *cnt) 5085 { 5086 int res; 5087 struct zone_fstab fstab; 5088 int ipd_cnt = 0; 5089 char **ipds = NULL; 5090 int pkg_cnt = 0; 5091 char **pkgs = NULL; 5092 int i; 5093 5094 if ((res = zonecfg_setipdent(handle)) != Z_OK) 5095 return (res); 5096 5097 while (zonecfg_getipdent(handle, &fstab) == Z_OK) { 5098 char **p; 5099 int len; 5100 5101 if ((p = (char **)realloc(ipds, 5102 sizeof (char *) * (ipd_cnt + 2))) == NULL) { 5103 res = Z_NOMEM; 5104 break; 5105 } 5106 ipds = p; 5107 5108 if ((ipds[ipd_cnt] = strdup(fstab.zone_fs_dir)) == NULL) { 5109 res = Z_NOMEM; 5110 break; 5111 } 5112 ipd_cnt++; 5113 5114 len = strlen(fstab.zone_fs_dir) + 3; 5115 if ((ipds[ipd_cnt] = malloc(len)) == NULL) { 5116 res = Z_NOMEM; 5117 break; 5118 } 5119 5120 (void) snprintf(ipds[ipd_cnt], len, "%s/*", fstab.zone_fs_dir); 5121 ipd_cnt++; 5122 } 5123 5124 (void) zonecfg_endipdent(handle); 5125 5126 if (res != Z_OK) { 5127 for (i = 0; i < ipd_cnt; i++) 5128 free(ipds[i]); 5129 free(ipds); 5130 return (res); 5131 } 5132 5133 /* We only have to process the contents file if we have ipds. */ 5134 if (ipd_cnt > 0) { 5135 FILE *fp; 5136 5137 if ((fp = fopen(CONTENTS_FILE, "r")) != NULL) { 5138 char *buf; 5139 5140 while ((buf = read_pkg_data(fp)) != NULL) { 5141 res = get_path_pkgs(buf, ipds, ipd_cnt, &pkgs, 5142 &pkg_cnt); 5143 free(buf); 5144 if (res != Z_OK) 5145 break; 5146 } 5147 5148 (void) fclose(fp); 5149 } 5150 } 5151 5152 for (i = 0; i < ipd_cnt; i++) 5153 free(ipds[i]); 5154 free(ipds); 5155 5156 if (res != Z_OK) { 5157 free_ipd_pkgs(pkgs, pkg_cnt); 5158 } else { 5159 *pkg_list = pkgs; 5160 *cnt = pkg_cnt; 5161 } 5162 5163 return (res); 5164 } 5165 5166 /* 5167 * Return true if pkg_name is in the list of pkgs that deliver into an 5168 * inherited pkg directory for the zone. 5169 */ 5170 static boolean_t 5171 dir_pkg(char *pkg_name, char **pkg_list, int cnt) 5172 { 5173 int i; 5174 5175 for (i = 0; i < cnt; i++) { 5176 if (strcmp(pkg_name, pkg_list[i]) == 0) 5177 return (B_TRUE); 5178 } 5179 5180 return (B_FALSE); 5181 } 5182 5183 /* 5184 * Start by adding the patch to the sw inventory on the handle. 5185 * 5186 * The info parameter will be the portion of the PATCH_INFO_ entry following 5187 * the '='. For example: 5188 * Installed: Wed Dec 7 07:13:51 PST 2005 From: mum Obsoletes: 120777-03 \ 5189 * 121087-02 119108-07 Requires: 119575-02 119255-06 Incompatibles: 5190 * 5191 * A backed out patch will have an info line of "backed out\n". We should 5192 * skip these patches. 5193 * 5194 * We also want to add the Obsolete and Incompatible patches to the 5195 * sw inventory description of this patch. 5196 */ 5197 static int 5198 add_patch(zone_dochandle_t handle, char *patch, char *info) 5199 { 5200 xmlNodePtr node; 5201 xmlNodePtr cur; 5202 int err; 5203 char *p; 5204 char *lastp; 5205 boolean_t add_info = B_FALSE; 5206 boolean_t obsolete; 5207 5208 if (strcmp(info, "backed out\n") == 0) 5209 return (Z_OK); 5210 5211 if ((err = operation_prep(handle)) != Z_OK) 5212 return (err); 5213 5214 cur = handle->zone_dh_cur; 5215 node = xmlNewTextChild(cur, NULL, DTD_ELEM_PATCH, NULL); 5216 if ((err = newprop(node, DTD_ATTR_ID, patch)) != Z_OK) 5217 return (err); 5218 5219 /* 5220 * Start with the first token. This will probably be "Installed:". 5221 * If we can't tokenize this entry, just return. 5222 */ 5223 if ((p = strtok_r(info, " ", &lastp)) == NULL) 5224 return (Z_OK); 5225 5226 do { 5227 xmlNodePtr new_node; 5228 char *nlp; 5229 5230 if (strcmp(p, "Installed:") == 0 || 5231 strcmp(p, "Requires:") == 0 || 5232 strcmp(p, "From:") == 0) { 5233 add_info = B_FALSE; 5234 continue; 5235 } else if (strcmp(p, "Obsoletes:") == 0) { 5236 obsolete = B_TRUE; 5237 add_info = B_TRUE; 5238 continue; 5239 } else if (strcmp(p, "Incompatibles:") == 0) { 5240 obsolete = B_FALSE; 5241 add_info = B_TRUE; 5242 continue; 5243 } 5244 5245 if (!add_info) 5246 continue; 5247 5248 /* strip newline from last patch in the line */ 5249 nlp = (p + strlen(p) - 1); 5250 if (*nlp == '\n') 5251 *nlp = '\0'; 5252 5253 if (obsolete) 5254 new_node = xmlNewTextChild(node, NULL, 5255 DTD_ELEM_OBSOLETES, NULL); 5256 else 5257 new_node = xmlNewTextChild(node, NULL, 5258 DTD_ELEM_INCOMPATIBLE, NULL); 5259 5260 if ((err = newprop(new_node, DTD_ATTR_ID, p)) != Z_OK) 5261 return (err); 5262 5263 } while ((p = strtok_r(NULL, " ", &lastp)) != NULL); 5264 5265 return (Z_OK); 5266 } 5267 5268 static boolean_t 5269 unique_patch(zone_dochandle_t handle, char *patch) 5270 { 5271 xmlNodePtr cur; 5272 char id[MAXNAMELEN]; 5273 5274 cur = xmlDocGetRootElement(handle->zone_dh_doc); 5275 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 5276 if (xmlStrcmp(cur->name, DTD_ELEM_PATCH) == 0) { 5277 if (fetchprop(cur, DTD_ATTR_ID, id, sizeof (id)) 5278 != Z_OK) 5279 continue; 5280 5281 if (strcmp(patch, id) == 0) 5282 return (B_FALSE); 5283 } 5284 } 5285 5286 return (B_TRUE); 5287 } 5288 5289 /* 5290 * Add the unique patches associated with this pkg to the sw inventory on the 5291 * handle. 5292 * 5293 * We are processing entries of the form: 5294 * PATCH_INFO_121454-02=Installed: Wed Dec 7 07:13:51 PST 2005 From: mum \ 5295 * Obsoletes: 120777-03 121087-02 119108-07 Requires: 119575-02 \ 5296 * 119255-06 Incompatibles: 5297 * 5298 */ 5299 static int 5300 add_patches(zone_dochandle_t handle, struct zone_pkginfo *infop) 5301 { 5302 int i; 5303 int res = Z_OK; 5304 5305 for (i = 0; i < infop->zpi_patch_cnt; i++) { 5306 char *p, *ep; 5307 5308 if (strlen(infop->zpi_patchinfo[i]) < (sizeof (PATCHINFO) - 1)) 5309 continue; 5310 5311 /* Skip over "PATCH_INFO_" to get the patch id. */ 5312 p = infop->zpi_patchinfo[i] + sizeof (PATCHINFO) - 1; 5313 if ((ep = strchr(p, '=')) == NULL) 5314 continue; 5315 5316 *ep = '\0'; 5317 if (unique_patch(handle, p)) 5318 if ((res = add_patch(handle, p, ep + 1)) != Z_OK) 5319 break; 5320 } 5321 5322 return (res); 5323 } 5324 5325 /* 5326 * Add the pkg to the sw inventory on the handle. 5327 */ 5328 static int 5329 add_pkg(zone_dochandle_t handle, char *name, char *version) 5330 { 5331 xmlNodePtr newnode; 5332 xmlNodePtr cur; 5333 int err; 5334 5335 if ((err = operation_prep(handle)) != Z_OK) 5336 return (err); 5337 5338 cur = handle->zone_dh_cur; 5339 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL); 5340 if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK) 5341 return (err); 5342 if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK) 5343 return (err); 5344 return (Z_OK); 5345 } 5346 5347 static void 5348 free_pkginfo(struct zone_pkginfo *infop) 5349 { 5350 free(infop->zpi_version); 5351 if (infop->zpi_patch_cnt > 0) { 5352 int i; 5353 5354 for (i = 0; i < infop->zpi_patch_cnt; i++) 5355 free(infop->zpi_patchinfo[i]); 5356 free(infop->zpi_patchinfo); 5357 } 5358 } 5359 5360 /* 5361 * Read the pkginfo file and populate the structure with the data we need 5362 * from this pkg for a sw inventory. 5363 */ 5364 static int 5365 get_pkginfo(char *pkginfo, struct zone_pkginfo *infop) 5366 { 5367 FILE *fp; 5368 char *buf; 5369 int err = 0; 5370 5371 infop->zpi_all_zones = B_FALSE; 5372 infop->zpi_this_zone = B_FALSE; 5373 infop->zpi_version = NULL; 5374 infop->zpi_patch_cnt = 0; 5375 infop->zpi_patchinfo = NULL; 5376 5377 if ((fp = fopen(pkginfo, "r")) == NULL) 5378 return (errno); 5379 5380 while ((buf = read_pkg_data(fp)) != NULL) { 5381 if (strncmp(buf, VERSION, sizeof (VERSION) - 1) == 0) { 5382 int len; 5383 5384 if ((infop->zpi_version = 5385 strdup(buf + sizeof (VERSION) - 1)) == NULL) { 5386 err = ENOMEM; 5387 break; 5388 } 5389 5390 /* remove trailing newline */ 5391 len = strlen(infop->zpi_version); 5392 *(infop->zpi_version + len - 1) = 0; 5393 5394 } else if (strcmp(buf, SUNW_PKG_ALL_ZONES) == 0) { 5395 infop->zpi_all_zones = B_TRUE; 5396 5397 } else if (strcmp(buf, SUNW_PKG_THIS_ZONE) == 0) { 5398 infop->zpi_this_zone = B_TRUE; 5399 5400 } else if (strncmp(buf, PATCHINFO, sizeof (PATCHINFO) - 1) 5401 == 0) { 5402 char **p; 5403 5404 if ((p = (char **)realloc(infop->zpi_patchinfo, 5405 sizeof (char *) * (infop->zpi_patch_cnt + 1))) 5406 == NULL) { 5407 err = ENOMEM; 5408 break; 5409 } 5410 infop->zpi_patchinfo = p; 5411 5412 if ((infop->zpi_patchinfo[infop->zpi_patch_cnt] = 5413 strdup(buf)) == NULL) { 5414 err = ENOMEM; 5415 break; 5416 } 5417 infop->zpi_patch_cnt++; 5418 } 5419 5420 free(buf); 5421 } 5422 5423 free(buf); 5424 5425 if (errno == ENOMEM) { 5426 err = ENOMEM; 5427 /* Clean up anything we did manage to allocate. */ 5428 free_pkginfo(infop); 5429 } 5430 5431 (void) fclose(fp); 5432 5433 return (err); 5434 } 5435 5436 /* 5437 * Take a software inventory of the global zone. We need to get the set of 5438 * packages and patches that are on the global zone that the specified 5439 * non-global zone depends on. The packages we need in the inventory are: 5440 * 5441 * - skip the package if SUNW_PKG_THISZONE is 'true' 5442 * otherwise, 5443 * - add the package if 5444 * a) SUNW_PKG_ALLZONES is 'true', 5445 * or 5446 * b) any file delivered by the package is in a file system that is inherited 5447 * from the global zone. 5448 * If the zone does not inherit any file systems (whole root) 5449 * then (b) will be skipped. 5450 * 5451 * For each of the packages that is being added to the inventory, we will also 5452 * add all of the associated, unique patches to the inventory. 5453 */ 5454 static int 5455 zonecfg_sw_inventory(zone_dochandle_t handle) 5456 { 5457 char pkginfo[MAXPATHLEN]; 5458 int res; 5459 struct dirent *dp; 5460 DIR *dirp; 5461 struct stat buf; 5462 struct zone_pkginfo info; 5463 int pkg_cnt = 0; 5464 char **pkgs = NULL; 5465 5466 if ((res = get_ipd_pkgs(handle, &pkgs, &pkg_cnt)) != Z_OK) 5467 return (res); 5468 5469 if ((dirp = opendir(PKG_PATH)) == NULL) { 5470 free_ipd_pkgs(pkgs, pkg_cnt); 5471 return (Z_OK); 5472 } 5473 5474 while ((dp = readdir(dirp)) != (struct dirent *)0) { 5475 if (strcmp(dp->d_name, ".") == 0 || 5476 strcmp(dp->d_name, "..") == 0) 5477 continue; 5478 5479 (void) snprintf(pkginfo, sizeof (pkginfo), "%s/%s/pkginfo", 5480 PKG_PATH, dp->d_name); 5481 5482 if (stat(pkginfo, &buf) == -1 || !S_ISREG(buf.st_mode)) 5483 continue; 5484 5485 if (get_pkginfo(pkginfo, &info) != 0) { 5486 res = Z_NOMEM; 5487 break; 5488 } 5489 5490 if (!info.zpi_this_zone && 5491 (info.zpi_all_zones || 5492 dir_pkg(dp->d_name, pkgs, pkg_cnt))) { 5493 if ((res = add_pkg(handle, dp->d_name, 5494 info.zpi_version)) == Z_OK) { 5495 if (info.zpi_patch_cnt > 0) 5496 res = add_patches(handle, &info); 5497 } 5498 } 5499 5500 free_pkginfo(&info); 5501 5502 if (res != Z_OK) 5503 break; 5504 } 5505 5506 (void) closedir(dirp); 5507 5508 free_ipd_pkgs(pkgs, pkg_cnt); 5509 5510 if (res == Z_OK) 5511 handle->zone_dh_sw_inv = B_TRUE; 5512 5513 return (res); 5514 } 5515 5516 /* 5517 * zonecfg_devwalk call-back function used during detach to generate the 5518 * dev info in the manifest. 5519 */ 5520 static int 5521 get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode, 5522 const char *acl, void *hdl) 5523 { 5524 zone_dochandle_t handle = (zone_dochandle_t)hdl; 5525 xmlNodePtr newnode; 5526 xmlNodePtr cur; 5527 int err; 5528 char buf[128]; 5529 5530 if ((err = operation_prep(handle)) != Z_OK) 5531 return (err); 5532 5533 cur = handle->zone_dh_cur; 5534 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL); 5535 if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK) 5536 return (err); 5537 (void) snprintf(buf, sizeof (buf), "%lu", uid); 5538 if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK) 5539 return (err); 5540 (void) snprintf(buf, sizeof (buf), "%lu", gid); 5541 if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK) 5542 return (err); 5543 (void) snprintf(buf, sizeof (buf), "%o", mode); 5544 if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK) 5545 return (err); 5546 if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK) 5547 return (err); 5548 return (Z_OK); 5549 } 5550 5551 /* 5552 * Get the information required to support detaching a zone. This is 5553 * called on the source system when detaching (the detaching parameter should 5554 * be set to true) and on the destination system before attaching (the 5555 * detaching parameter should be false). 5556 * 5557 * For native Solaris zones, the detach/attach process involves validating 5558 * that the software on the global zone can support the zone when we attach. 5559 * To do this we take a software inventory of the global zone. We also 5560 * have to keep track of the device configuration so that we can properly 5561 * recreate it on the destination. 5562 */ 5563 int 5564 zonecfg_get_detach_info(zone_dochandle_t handle, boolean_t detaching) 5565 { 5566 int res; 5567 5568 if ((res = zonecfg_sw_inventory(handle)) != Z_OK) 5569 return (res); 5570 5571 if (detaching) 5572 res = zonecfg_devwalk(handle, get_detach_dev_entry, handle); 5573 5574 return (res); 5575 } 5576