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