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