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