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