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