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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 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 47 #include <arpa/inet.h> 48 #include <netdb.h> 49 50 #include <priv.h> 51 52 #include <libxml/xmlmemory.h> 53 #include <libxml/parser.h> 54 55 #include <libdevinfo.h> 56 #include <uuid/uuid.h> 57 58 #include <libzonecfg.h> 59 #include "zonecfg_impl.h" 60 61 62 #define _PATH_TMPFILE "/zonecfg.XXXXXX" 63 #define ZONE_CB_RETRY_COUNT 10 64 #define ZONE_EVENT_PING_SUBCLASS "ping" 65 #define ZONE_EVENT_PING_PUBLISHER "solaris" 66 67 /* Hard-code the DTD element/attribute/entity names just once, here. */ 68 #define DTD_ELEM_ATTR (const xmlChar *) "attr" 69 #define DTD_ELEM_COMMENT (const xmlChar *) "comment" 70 #define DTD_ELEM_DEVICE (const xmlChar *) "device" 71 #define DTD_ELEM_FS (const xmlChar *) "filesystem" 72 #define DTD_ELEM_FSOPTION (const xmlChar *) "fsoption" 73 #define DTD_ELEM_IPD (const xmlChar *) "inherited-pkg-dir" 74 #define DTD_ELEM_NET (const xmlChar *) "network" 75 #define DTD_ELEM_RCTL (const xmlChar *) "rctl" 76 #define DTD_ELEM_RCTLVALUE (const xmlChar *) "rctl-value" 77 #define DTD_ELEM_ZONE (const xmlChar *) "zone" 78 #define DTD_ELEM_DATASET (const xmlChar *) "dataset" 79 80 #define DTD_ATTR_ACTION (const xmlChar *) "action" 81 #define DTD_ATTR_ADDRESS (const xmlChar *) "address" 82 #define DTD_ATTR_AUTOBOOT (const xmlChar *) "autoboot" 83 #define DTD_ATTR_DIR (const xmlChar *) "directory" 84 #define DTD_ATTR_LIMIT (const xmlChar *) "limit" 85 #define DTD_ATTR_MATCH (const xmlChar *) "match" 86 #define DTD_ATTR_NAME (const xmlChar *) "name" 87 #define DTD_ATTR_PHYSICAL (const xmlChar *) "physical" 88 #define DTD_ATTR_POOL (const xmlChar *) "pool" 89 #define DTD_ATTR_PRIV (const xmlChar *) "priv" 90 #define DTD_ATTR_RAW (const xmlChar *) "raw" 91 #define DTD_ATTR_SPECIAL (const xmlChar *) "special" 92 #define DTD_ATTR_TYPE (const xmlChar *) "type" 93 #define DTD_ATTR_VALUE (const xmlChar *) "value" 94 #define DTD_ATTR_ZONEPATH (const xmlChar *) "zonepath" 95 96 #define DTD_ENTITY_BOOLEAN "boolean" 97 #define DTD_ENTITY_DEVPATH "devpath" 98 #define DTD_ENTITY_DRIVER "driver" 99 #define DTD_ENTITY_DRVMIN "drv_min" 100 #define DTD_ENTITY_FALSE "false" 101 #define DTD_ENTITY_INT "int" 102 #define DTD_ENTITY_STRING "string" 103 #define DTD_ENTITY_TRUE "true" 104 #define DTD_ENTITY_UINT "uint" 105 106 #define DTD_ENTITY_BOOL_LEN 6 /* "false" */ 107 108 struct zone_dochandle { 109 char *zone_dh_rootdir; 110 xmlDocPtr zone_dh_doc; 111 xmlNodePtr zone_dh_cur; 112 xmlNodePtr zone_dh_top; 113 boolean_t zone_dh_newzone; 114 boolean_t zone_dh_snapshot; 115 char zone_dh_delete_name[ZONENAME_MAX]; 116 }; 117 118 struct znotify { 119 void * zn_private; 120 evchan_t *zn_eventchan; 121 int (*zn_callback)(const char *zonename, zoneid_t zid, 122 const char *newstate, const char *oldstate, hrtime_t when, void *p); 123 pthread_mutex_t zn_mutex; 124 pthread_cond_t zn_cond; 125 pthread_mutex_t zn_bigmutex; 126 volatile enum {ZN_UNLOCKED, ZN_LOCKED, ZN_PING_INFLIGHT, 127 ZN_PING_RECEIVED} zn_state; 128 char zn_subscriber_id[MAX_SUBID_LEN]; 129 volatile boolean_t zn_failed; 130 int zn_failure_count; 131 }; 132 133 char *zonecfg_root = ""; 134 135 /* 136 * For functions which return int, which is most of the functions herein, 137 * the return values should be from the Z_foo set defined in <libzonecfg.h>. 138 * In some instances, we take pains mapping some libc errno values to Z_foo 139 * values from this set. 140 */ 141 142 /* 143 * Set the root (/) path for all zonecfg configuration files. This is a 144 * private interface used by Live Upgrade extensions to access zone 145 * configuration inside mounted alternate boot environments. 146 */ 147 void 148 zonecfg_set_root(const char *rootpath) 149 { 150 if (*zonecfg_root != '\0') 151 free(zonecfg_root); 152 if (rootpath == NULL || rootpath[0] == '\0' || rootpath[1] == '\0' || 153 (zonecfg_root = strdup(rootpath)) == NULL) 154 zonecfg_root = ""; 155 } 156 157 const char * 158 zonecfg_get_root(void) 159 { 160 return (zonecfg_root); 161 } 162 163 boolean_t 164 zonecfg_in_alt_root(void) 165 { 166 return (*zonecfg_root != '\0'); 167 } 168 169 /* 170 * Callers of the _file_path() functions are expected to have the second 171 * parameter be a (char foo[MAXPATHLEN]). 172 */ 173 174 static boolean_t 175 config_file_path(const char *zonename, char *answer) 176 { 177 return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root, 178 ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN); 179 } 180 181 static boolean_t 182 snap_file_path(const char *zonename, char *answer) 183 { 184 return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml", 185 zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN); 186 } 187 188 /*ARGSUSED*/ 189 static void 190 zonecfg_error_func(void *ctx, const char *msg, ...) 191 { 192 /* 193 * This function does nothing by design. Its purpose is to prevent 194 * libxml from dumping unwanted messages to stdout/stderr. 195 */ 196 } 197 198 zone_dochandle_t 199 zonecfg_init_handle(void) 200 { 201 zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle)); 202 if (handle == NULL) { 203 errno = Z_NOMEM; 204 return (NULL); 205 } 206 207 /* generic libxml initialization */ 208 xmlLineNumbersDefault(1); 209 xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS; 210 xmlDoValidityCheckingDefaultValue = 1; 211 (void) xmlKeepBlanksDefault(0); 212 xmlGetWarningsDefaultValue = 0; 213 xmlSetGenericErrorFunc(NULL, zonecfg_error_func); 214 215 return (handle); 216 } 217 218 int 219 zonecfg_check_handle(zone_dochandle_t handle) 220 { 221 if (handle == NULL || handle->zone_dh_doc == NULL) 222 return (Z_BAD_HANDLE); 223 return (Z_OK); 224 } 225 226 void 227 zonecfg_fini_handle(zone_dochandle_t handle) 228 { 229 if (zonecfg_check_handle(handle) == Z_OK) 230 xmlFreeDoc(handle->zone_dh_doc); 231 if (handle != NULL) 232 free(handle); 233 } 234 235 static int 236 zonecfg_destroy_impl(char *filename) 237 { 238 if (unlink(filename) == -1) { 239 if (errno == EACCES) 240 return (Z_ACCES); 241 if (errno == ENOENT) 242 return (Z_NO_ZONE); 243 return (Z_MISC_FS); 244 } 245 return (Z_OK); 246 } 247 248 int 249 zonecfg_destroy(const char *zonename, boolean_t force) 250 { 251 char path[MAXPATHLEN]; 252 struct zoneent ze; 253 int err, state_err; 254 zone_state_t state; 255 256 if (!config_file_path(zonename, path)) 257 return (Z_MISC_FS); 258 259 state_err = zone_get_state((char *)zonename, &state); 260 err = access(path, W_OK); 261 262 /* 263 * If there is no file, and no index entry, reliably indicate that no 264 * such zone exists. 265 */ 266 if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT)) 267 return (Z_NO_ZONE); 268 269 /* 270 * Handle any other filesystem related errors (except if the XML 271 * file is missing, which we treat silently), unless we're forcing, 272 * in which case we plow on. 273 */ 274 if (err == -1 && errno != ENOENT) { 275 if (errno == EACCES) 276 return (Z_ACCES); 277 else if (!force) 278 return (Z_MISC_FS); 279 } 280 281 if (state > ZONE_STATE_INSTALLED) 282 return (Z_BAD_ZONE_STATE); 283 284 if (!force && state > ZONE_STATE_CONFIGURED) 285 return (Z_BAD_ZONE_STATE); 286 287 /* 288 * Index deletion succeeds even if the entry doesn't exist. So this 289 * will fail only if we've had some more severe problem. 290 */ 291 bzero(&ze, sizeof (ze)); 292 (void) strlcpy(ze.zone_name, zonename, sizeof (ze.zone_name)); 293 if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK) 294 if (!force) 295 return (err); 296 297 err = zonecfg_destroy_impl(path); 298 299 /* 300 * Treat failure to find the XML file silently, since, well, it's 301 * gone, and with the index file cleaned up, we're done. 302 */ 303 if (err == Z_OK || err == Z_NO_ZONE) 304 return (Z_OK); 305 return (err); 306 } 307 308 int 309 zonecfg_destroy_snapshot(const char *zonename) 310 { 311 char path[MAXPATHLEN]; 312 313 if (!snap_file_path(zonename, path)) 314 return (Z_MISC_FS); 315 return (zonecfg_destroy_impl(path)); 316 } 317 318 static int 319 getroot(zone_dochandle_t handle, xmlNodePtr *root) 320 { 321 if (zonecfg_check_handle(handle) == Z_BAD_HANDLE) 322 return (Z_BAD_HANDLE); 323 324 *root = xmlDocGetRootElement(handle->zone_dh_doc); 325 326 if (*root == NULL) 327 return (Z_EMPTY_DOCUMENT); 328 329 if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE)) 330 return (Z_WRONG_DOC_TYPE); 331 332 return (Z_OK); 333 } 334 335 static int 336 operation_prep(zone_dochandle_t handle) 337 { 338 xmlNodePtr root; 339 int err; 340 341 if ((err = getroot(handle, &root)) != 0) 342 return (err); 343 344 handle->zone_dh_cur = root; 345 handle->zone_dh_top = root; 346 return (Z_OK); 347 } 348 349 static int 350 getrootattr(zone_dochandle_t handle, const xmlChar *propname, 351 char *propval, size_t propsize) 352 { 353 xmlNodePtr root; 354 xmlChar *property; 355 size_t srcsize; 356 int err; 357 358 if ((err = getroot(handle, &root)) != 0) 359 return (err); 360 361 if ((property = xmlGetProp(root, propname)) == NULL) 362 return (Z_BAD_PROPERTY); 363 srcsize = strlcpy(propval, (char *)property, propsize); 364 xmlFree(property); 365 if (srcsize >= propsize) 366 return (Z_TOO_BIG); 367 return (Z_OK); 368 } 369 370 static int 371 setrootattr(zone_dochandle_t handle, const xmlChar *propname, 372 const char *propval) 373 { 374 int err; 375 xmlNodePtr root; 376 377 if (propval == NULL) 378 return (Z_INVAL); 379 380 if ((err = getroot(handle, &root)) != Z_OK) 381 return (err); 382 383 if (xmlSetProp(root, propname, (const xmlChar *) propval) == NULL) 384 return (Z_INVAL); 385 return (Z_OK); 386 } 387 388 static void 389 addcomment(zone_dochandle_t handle, const char *comment) 390 { 391 xmlNodePtr node; 392 node = xmlNewComment((xmlChar *) comment); 393 394 if (node != NULL) 395 (void) xmlAddPrevSibling(handle->zone_dh_top, node); 396 } 397 398 static void 399 stripcomments(zone_dochandle_t handle) 400 { 401 xmlDocPtr top; 402 xmlNodePtr child, next; 403 404 top = handle->zone_dh_doc; 405 for (child = top->xmlChildrenNode; child != NULL; child = next) { 406 next = child->next; 407 if (child->name == NULL) 408 continue; 409 if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) { 410 next = child->next; 411 xmlUnlinkNode(child); 412 xmlFreeNode(child); 413 } 414 } 415 } 416 417 static int 418 zonecfg_get_handle_impl(const char *zonename, const char *filename, 419 zone_dochandle_t handle) 420 { 421 xmlValidCtxtPtr cvp; 422 struct stat statbuf; 423 int valid; 424 425 if (zonename == NULL) 426 return (Z_NO_ZONE); 427 if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) { 428 /* distinguish file not found vs. found but not parsed */ 429 if (stat(filename, &statbuf) == 0) 430 return (Z_INVALID_DOCUMENT); 431 return (Z_NO_ZONE); 432 } 433 if ((cvp = xmlNewValidCtxt()) == NULL) 434 return (Z_NOMEM); 435 cvp->error = zonecfg_error_func; 436 cvp->warning = zonecfg_error_func; 437 valid = xmlValidateDocument(cvp, handle->zone_dh_doc); 438 xmlFreeValidCtxt(cvp); 439 if (valid == 0) 440 return (Z_INVALID_DOCUMENT); 441 442 /* delete any comments such as inherited Sun copyright / ident str */ 443 stripcomments(handle); 444 return (Z_OK); 445 } 446 447 int 448 zonecfg_get_handle(const char *zonename, zone_dochandle_t handle) 449 { 450 char path[MAXPATHLEN]; 451 452 if (!config_file_path(zonename, path)) 453 return (Z_MISC_FS); 454 handle->zone_dh_newzone = B_FALSE; 455 456 return (zonecfg_get_handle_impl(zonename, path, handle)); 457 } 458 459 int 460 zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle) 461 { 462 char path[MAXPATHLEN]; 463 464 if (!snap_file_path(zonename, path)) 465 return (Z_MISC_FS); 466 handle->zone_dh_newzone = B_FALSE; 467 return (zonecfg_get_handle_impl(zonename, path, handle)); 468 } 469 470 int 471 zonecfg_get_template_handle(const char *template, const char *zonename, 472 zone_dochandle_t handle) 473 { 474 char path[MAXPATHLEN]; 475 int err; 476 477 if (!config_file_path(template, path)) 478 return (Z_MISC_FS); 479 480 if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK) 481 return (err); 482 handle->zone_dh_newzone = B_TRUE; 483 return (setrootattr(handle, DTD_ATTR_NAME, zonename)); 484 } 485 486 static boolean_t 487 is_renaming(zone_dochandle_t handle) 488 { 489 if (handle->zone_dh_newzone) 490 return (B_FALSE); 491 if (strlen(handle->zone_dh_delete_name) > 0) 492 return (B_TRUE); 493 return (B_FALSE); 494 } 495 496 static boolean_t 497 is_new(zone_dochandle_t handle) 498 { 499 return (handle->zone_dh_newzone || handle->zone_dh_snapshot); 500 } 501 502 static boolean_t 503 is_snapshot(zone_dochandle_t handle) 504 { 505 return (handle->zone_dh_snapshot); 506 } 507 508 /* 509 * It would be great to be able to use libc's ctype(3c) macros, but we 510 * can't, as they are locale sensitive, and it would break our limited thread 511 * safety if this routine had to change the app locale on the fly. 512 */ 513 int 514 zonecfg_validate_zonename(const char *zone) 515 { 516 int i; 517 518 if (strcmp(zone, GLOBAL_ZONENAME) == 0) 519 return (Z_BOGUS_ZONE_NAME); 520 521 if (strlen(zone) >= ZONENAME_MAX) 522 return (Z_BOGUS_ZONE_NAME); 523 524 if (!((zone[0] >= 'a' && zone[0] <= 'z') || 525 (zone[0] >= 'A' && zone[0] <= 'Z') || 526 (zone[0] >= '0' && zone[0] <= '9'))) 527 return (Z_BOGUS_ZONE_NAME); 528 529 for (i = 1; zone[i] != '\0'; i++) { 530 if (!((zone[i] >= 'a' && zone[i] <= 'z') || 531 (zone[i] >= 'A' && zone[i] <= 'Z') || 532 (zone[i] >= '0' && zone[i] <= '9') || 533 (zone[i] == '-') || (zone[i] == '_') || (zone[i] == '.'))) 534 return (Z_BOGUS_ZONE_NAME); 535 } 536 537 return (Z_OK); 538 } 539 540 /* 541 * Changing the zone name requires us to track both the old and new 542 * name of the zone until commit time. 543 */ 544 int 545 zonecfg_get_name(zone_dochandle_t handle, char *name, size_t namesize) 546 { 547 return (getrootattr(handle, DTD_ATTR_NAME, name, namesize)); 548 } 549 550 int 551 zonecfg_set_name(zone_dochandle_t handle, char *name) 552 { 553 zone_state_t state; 554 char curname[ZONENAME_MAX], old_delname[ZONENAME_MAX]; 555 int err; 556 557 if ((err = getrootattr(handle, DTD_ATTR_NAME, curname, 558 sizeof (curname))) != Z_OK) 559 return (err); 560 561 if (strcmp(name, curname) == 0) 562 return (Z_OK); 563 564 /* 565 * Switching zone names to one beginning with SUNW is not permitted. 566 */ 567 if (strncmp(name, "SUNW", 4) == 0) 568 return (Z_BOGUS_ZONE_NAME); 569 570 if ((err = zonecfg_validate_zonename(name)) != Z_OK) 571 return (err); 572 573 /* 574 * Setting the name back to the original name (effectively a revert of 575 * the name) is fine. But if we carry on, we'll falsely identify the 576 * name as "in use," so special case here. 577 */ 578 if (strcmp(name, handle->zone_dh_delete_name) == 0) { 579 err = setrootattr(handle, DTD_ATTR_NAME, name); 580 handle->zone_dh_delete_name[0] = '\0'; 581 return (err); 582 } 583 584 /* Check to see if new name chosen is already in use */ 585 if (zone_get_state(name, &state) != Z_NO_ZONE) 586 return (Z_NAME_IN_USE); 587 588 /* 589 * If this isn't already "new" or in a renaming transition, then 590 * we're initiating a rename here; so stash the "delete name" 591 * (i.e. the name of the zone we'll be removing) for the rename. 592 */ 593 (void) strlcpy(old_delname, handle->zone_dh_delete_name, 594 sizeof (old_delname)); 595 if (!is_new(handle) && !is_renaming(handle)) { 596 /* 597 * Name change is allowed only when the zone we're altering 598 * is not ready or running. 599 */ 600 err = zone_get_state(curname, &state); 601 if (err == Z_OK) { 602 if (state > ZONE_STATE_INSTALLED) 603 return (Z_BAD_ZONE_STATE); 604 } else if (err != Z_NO_ZONE) { 605 return (err); 606 } 607 608 (void) strlcpy(handle->zone_dh_delete_name, curname, 609 sizeof (handle->zone_dh_delete_name)); 610 assert(is_renaming(handle)); 611 } else if (is_renaming(handle)) { 612 err = zone_get_state(handle->zone_dh_delete_name, &state); 613 if (err == Z_OK) { 614 if (state > ZONE_STATE_INSTALLED) 615 return (Z_BAD_ZONE_STATE); 616 } else if (err != Z_NO_ZONE) { 617 return (err); 618 } 619 } 620 621 if ((err = setrootattr(handle, DTD_ATTR_NAME, name)) != Z_OK) { 622 /* 623 * Restore the deletename to whatever it was at the 624 * top of the routine, since we've had a failure. 625 */ 626 (void) strlcpy(handle->zone_dh_delete_name, old_delname, 627 sizeof (handle->zone_dh_delete_name)); 628 return (err); 629 } 630 631 return (Z_OK); 632 } 633 634 int 635 zonecfg_get_zonepath(zone_dochandle_t handle, char *path, size_t pathsize) 636 { 637 size_t len; 638 639 if ((len = strlcpy(path, zonecfg_root, pathsize)) >= pathsize) 640 return (Z_TOO_BIG); 641 return (getrootattr(handle, DTD_ATTR_ZONEPATH, path + len, 642 pathsize - len)); 643 } 644 645 int 646 zonecfg_set_zonepath(zone_dochandle_t handle, char *zonepath) 647 { 648 return (setrootattr(handle, DTD_ATTR_ZONEPATH, zonepath)); 649 } 650 651 int 652 zonecfg_get_autoboot(zone_dochandle_t handle, boolean_t *autoboot) 653 { 654 char autobootstr[DTD_ENTITY_BOOL_LEN]; 655 int ret; 656 657 if ((ret = getrootattr(handle, DTD_ATTR_AUTOBOOT, autobootstr, 658 sizeof (autobootstr))) != Z_OK) 659 return (ret); 660 661 if (strcmp(autobootstr, DTD_ENTITY_TRUE) == 0) 662 *autoboot = B_TRUE; 663 else if (strcmp(autobootstr, DTD_ENTITY_FALSE) == 0) 664 *autoboot = B_FALSE; 665 else 666 ret = Z_BAD_PROPERTY; 667 return (ret); 668 } 669 670 int 671 zonecfg_set_autoboot(zone_dochandle_t handle, boolean_t autoboot) 672 { 673 return (setrootattr(handle, DTD_ATTR_AUTOBOOT, 674 autoboot ? DTD_ENTITY_TRUE : DTD_ENTITY_FALSE)); 675 } 676 677 int 678 zonecfg_get_pool(zone_dochandle_t handle, char *pool, size_t poolsize) 679 { 680 return (getrootattr(handle, DTD_ATTR_POOL, pool, poolsize)); 681 } 682 683 int 684 zonecfg_set_pool(zone_dochandle_t handle, char *pool) 685 { 686 return (setrootattr(handle, DTD_ATTR_POOL, pool)); 687 } 688 689 /* 690 * /etc/zones/index caches a vital piece of information which is also 691 * in the <zonename>.xml file: the path to the zone. This is for performance, 692 * since we need to walk all zonepath's in order to be able to detect conflicts 693 * (see crosscheck_zonepaths() in the zoneadm command). 694 * 695 * An additional complexity is that when doing a rename, we'd like the entire 696 * index update operation (rename, and potential state changes) to be atomic. 697 * In general, the operation of this function should succeed or fail as 698 * a unit. 699 */ 700 int 701 zonecfg_refresh_index_file(zone_dochandle_t handle) 702 { 703 char name[ZONENAME_MAX], zonepath[MAXPATHLEN]; 704 struct zoneent ze; 705 int err; 706 int opcode; 707 char *zn; 708 709 bzero(&ze, sizeof (ze)); 710 ze.zone_state = -1; /* Preserve existing state in index */ 711 712 if ((err = zonecfg_get_name(handle, name, sizeof (name))) != Z_OK) 713 return (err); 714 (void) strlcpy(ze.zone_name, name, sizeof (ze.zone_name)); 715 716 if ((err = zonecfg_get_zonepath(handle, zonepath, 717 sizeof (zonepath))) != Z_OK) 718 return (err); 719 (void) strlcpy(ze.zone_path, zonepath, sizeof (ze.zone_path)); 720 721 if (is_renaming(handle)) { 722 opcode = PZE_MODIFY; 723 (void) strlcpy(ze.zone_name, handle->zone_dh_delete_name, 724 sizeof (ze.zone_name)); 725 (void) strlcpy(ze.zone_newname, name, sizeof (ze.zone_newname)); 726 } else if (is_new(handle)) { 727 FILE *cookie; 728 /* 729 * Be tolerant of the zone already existing in the index file, 730 * since we might be forcibly overwriting an existing 731 * configuration with a new one (for example 'create -F' 732 * in zonecfg). 733 */ 734 opcode = PZE_ADD; 735 cookie = setzoneent(); 736 while ((zn = getzoneent(cookie)) != NULL) { 737 if (strcmp(zn, name) == 0) { 738 opcode = PZE_MODIFY; 739 free(zn); 740 break; 741 } 742 free(zn); 743 } 744 endzoneent(cookie); 745 ze.zone_state = ZONE_STATE_CONFIGURED; 746 } else { 747 opcode = PZE_MODIFY; 748 } 749 750 if ((err = putzoneent(&ze, opcode)) != Z_OK) 751 return (err); 752 753 return (Z_OK); 754 } 755 756 /* 757 * The goal of this routine is to cause the index file update and the 758 * document save to happen as an atomic operation. We do the document 759 * first, saving a backup copy using a hard link; if that succeeds, we go 760 * on to the index. If that fails, we roll the document back into place. 761 * 762 * Strategy: 763 * 764 * New zone 'foo' configuration: 765 * Create tmpfile (zonecfg.xxxxxx) 766 * Write XML to tmpfile 767 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml) 768 * Add entry to index file 769 * If it fails, delete foo.xml, leaving nothing behind. 770 * 771 * Save existing zone 'foo': 772 * Make backup of foo.xml -> .backup 773 * Create tmpfile (zonecfg.xxxxxx) 774 * Write XML to tmpfile 775 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml) 776 * Modify index file as needed 777 * If it fails, recover from .backup -> foo.xml 778 * 779 * Rename 'foo' to 'bar': 780 * Create tmpfile (zonecfg.xxxxxx) 781 * Write XML to tmpfile 782 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml) 783 * Add entry for 'bar' to index file, Remove entry for 'foo' (refresh) 784 * If it fails, delete bar.xml; foo.xml is left behind. 785 */ 786 static int 787 zonecfg_save_impl(zone_dochandle_t handle, char *filename) 788 { 789 char tmpfile[MAXPATHLEN]; 790 char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN]; 791 int tmpfd, err; 792 xmlValidCtxt cvp = { NULL }; 793 boolean_t backup; 794 795 (void) strlcpy(tmpfile, filename, sizeof (tmpfile)); 796 (void) dirname(tmpfile); 797 (void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile)); 798 799 tmpfd = mkstemp(tmpfile); 800 if (tmpfd == -1) { 801 (void) unlink(tmpfile); 802 return (Z_TEMP_FILE); 803 } 804 (void) close(tmpfd); 805 806 cvp.error = zonecfg_error_func; 807 cvp.warning = zonecfg_error_func; 808 809 /* 810 * We do a final validation of the document-- but the library has 811 * malfunctioned if it fails to validate, so it's an assert. 812 */ 813 assert(xmlValidateDocument(&cvp, handle->zone_dh_doc) != 0); 814 815 if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0) 816 goto err; 817 818 (void) chmod(tmpfile, 0644); 819 820 /* 821 * In the event we are doing a standard save, hard link a copy of the 822 * original file in .backup.<pid>.filename so we can restore it if 823 * something goes wrong. 824 */ 825 if (!is_new(handle) && !is_renaming(handle)) { 826 backup = B_TRUE; 827 828 (void) strlcpy(bakdir, filename, sizeof (bakdir)); 829 (void) strlcpy(bakbase, filename, sizeof (bakbase)); 830 (void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s", 831 dirname(bakdir), getpid(), basename(bakbase)); 832 833 if (link(filename, bakfile) == -1) { 834 err = errno; 835 (void) unlink(tmpfile); 836 if (errno == EACCES) 837 return (Z_ACCES); 838 return (Z_MISC_FS); 839 } 840 } 841 842 /* 843 * Move the new document over top of the old. 844 * i.e.: zonecfg.XXXXXX -> myzone.xml 845 */ 846 if (rename(tmpfile, filename) == -1) { 847 err = errno; 848 (void) unlink(tmpfile); 849 if (backup) 850 (void) unlink(bakfile); 851 if (err == EACCES) 852 return (Z_ACCES); 853 return (Z_MISC_FS); 854 } 855 856 /* 857 * If this is a snapshot, we're done-- don't add an index entry. 858 */ 859 if (is_snapshot(handle)) 860 return (Z_OK); 861 862 /* now update the index file to reflect whatever we just did */ 863 if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) { 864 if (backup) { 865 /* 866 * Try to restore from our backup. 867 */ 868 (void) unlink(filename); 869 (void) rename(bakfile, filename); 870 } else { 871 /* 872 * Either the zone is new, in which case we can delete 873 * new.xml, or we're doing a rename, so ditto. 874 */ 875 assert(is_new(handle) || is_renaming(handle)); 876 (void) unlink(filename); 877 } 878 return (Z_UPDATING_INDEX); 879 } 880 881 if (backup) 882 (void) unlink(bakfile); 883 884 return (Z_OK); 885 886 err: 887 (void) unlink(tmpfile); 888 return (Z_SAVING_FILE); 889 } 890 891 int 892 zonecfg_save(zone_dochandle_t handle) 893 { 894 char zname[ZONENAME_MAX], path[MAXPATHLEN]; 895 char delpath[MAXPATHLEN]; 896 int err = Z_SAVING_FILE; 897 898 if (zonecfg_check_handle(handle) != Z_OK) 899 return (Z_BAD_HANDLE); 900 901 /* 902 * We don't support saving snapshots at this time. 903 */ 904 if (handle->zone_dh_snapshot) 905 return (Z_INVAL); 906 907 if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK) 908 return (err); 909 910 if (!config_file_path(zname, path)) 911 return (Z_MISC_FS); 912 913 addcomment(handle, "\n DO NOT EDIT THIS " 914 "FILE. Use zonecfg(1M) instead.\n"); 915 916 err = zonecfg_save_impl(handle, path); 917 918 stripcomments(handle); 919 920 if (err != Z_OK) 921 return (err); 922 923 handle->zone_dh_newzone = B_FALSE; 924 925 if (is_renaming(handle)) { 926 if (config_file_path(handle->zone_dh_delete_name, delpath)) 927 (void) unlink(delpath); 928 handle->zone_dh_delete_name[0] = '\0'; 929 } 930 931 return (Z_OK); 932 } 933 934 /* 935 * Special case: if access(2) fails with ENOENT, then try again using 936 * ZONE_CONFIG_ROOT instead of config_file_path(zonename). This is how we 937 * work around the case of a config file which has not been created yet: 938 * the user will need access to the directory so use that as a heuristic. 939 */ 940 941 int 942 zonecfg_access(const char *zonename, int amode) 943 { 944 char path[MAXPATHLEN]; 945 946 if (!config_file_path(zonename, path)) 947 return (Z_INVAL); 948 if (access(path, amode) == 0) 949 return (Z_OK); 950 if (errno == ENOENT) { 951 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root, 952 ZONE_CONFIG_ROOT) >= sizeof (path)) 953 return (Z_INVAL); 954 if (access(path, amode) == 0) 955 return (Z_OK); 956 } 957 if (errno == EACCES) 958 return (Z_ACCES); 959 if (errno == EINVAL) 960 return (Z_INVAL); 961 return (Z_MISC_FS); 962 } 963 964 int 965 zonecfg_create_snapshot(const char *zonename) 966 { 967 zone_dochandle_t handle; 968 char path[MAXPATHLEN], zonepath[MAXPATHLEN], rpath[MAXPATHLEN]; 969 int error = Z_OK, res; 970 971 if ((handle = zonecfg_init_handle()) == NULL) { 972 return (Z_NOMEM); 973 } 974 975 handle->zone_dh_newzone = B_TRUE; 976 handle->zone_dh_snapshot = B_TRUE; 977 978 if ((error = zonecfg_get_handle(zonename, handle)) != Z_OK) 979 goto out; 980 if ((error = operation_prep(handle)) != Z_OK) 981 goto out; 982 error = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)); 983 if (error != Z_OK) 984 goto out; 985 if ((res = resolvepath(zonepath, rpath, sizeof (rpath))) == -1) { 986 error = Z_RESOLVED_PATH; 987 goto out; 988 } 989 /* 990 * If the resolved path is not the same as the original path, then 991 * save the resolved path in the snapshot, thus preventing any 992 * potential problems down the line when zoneadmd goes to unmount 993 * file systems and depends on initial string matches with resolved 994 * paths. 995 */ 996 rpath[res] = '\0'; 997 if (strcmp(zonepath, rpath) != 0) { 998 if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK) 999 goto out; 1000 } 1001 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root, 1002 ZONE_SNAPSHOT_ROOT) >= sizeof (path)) { 1003 error = Z_MISC_FS; 1004 goto out; 1005 } 1006 if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) { 1007 error = Z_MISC_FS; 1008 goto out; 1009 } 1010 1011 if (!snap_file_path(zonename, path)) { 1012 error = Z_MISC_FS; 1013 goto out; 1014 } 1015 1016 addcomment(handle, "\n DO NOT EDIT THIS FILE. " 1017 "It is a snapshot of running zone state.\n"); 1018 1019 error = zonecfg_save_impl(handle, path); 1020 1021 stripcomments(handle); 1022 1023 out: 1024 zonecfg_fini_handle(handle); 1025 return (error); 1026 } 1027 1028 static int 1029 newprop(xmlNodePtr node, const xmlChar *attrname, char *src) 1030 { 1031 xmlAttrPtr newattr; 1032 1033 newattr = xmlNewProp(node, attrname, (xmlChar *)src); 1034 if (newattr == NULL) { 1035 xmlUnlinkNode(node); 1036 xmlFreeNode(node); 1037 return (Z_BAD_PROPERTY); 1038 } 1039 return (Z_OK); 1040 } 1041 1042 static int 1043 zonecfg_add_filesystem_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1044 { 1045 xmlNodePtr newnode, cur = handle->zone_dh_cur, options_node; 1046 zone_fsopt_t *ptr; 1047 int err; 1048 1049 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_FS, NULL); 1050 if ((err = newprop(newnode, DTD_ATTR_SPECIAL, 1051 tabptr->zone_fs_special)) != Z_OK) 1052 return (err); 1053 if (tabptr->zone_fs_raw[0] != '\0' && 1054 (err = newprop(newnode, DTD_ATTR_RAW, tabptr->zone_fs_raw)) != Z_OK) 1055 return (err); 1056 if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK) 1057 return (err); 1058 if ((err = newprop(newnode, DTD_ATTR_TYPE, 1059 tabptr->zone_fs_type)) != Z_OK) 1060 return (err); 1061 if (tabptr->zone_fs_options != NULL) { 1062 for (ptr = tabptr->zone_fs_options; ptr != NULL; 1063 ptr = ptr->zone_fsopt_next) { 1064 options_node = xmlNewTextChild(newnode, NULL, 1065 DTD_ELEM_FSOPTION, NULL); 1066 if ((err = newprop(options_node, DTD_ATTR_NAME, 1067 ptr->zone_fsopt_opt)) != Z_OK) 1068 return (err); 1069 } 1070 } 1071 return (Z_OK); 1072 } 1073 1074 int 1075 zonecfg_add_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr) 1076 { 1077 int err; 1078 1079 if (tabptr == NULL) 1080 return (Z_INVAL); 1081 1082 if ((err = operation_prep(handle)) != Z_OK) 1083 return (err); 1084 1085 if ((err = zonecfg_add_filesystem_core(handle, tabptr)) != Z_OK) 1086 return (err); 1087 1088 return (Z_OK); 1089 } 1090 1091 static int 1092 zonecfg_add_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1093 { 1094 xmlNodePtr newnode, cur = handle->zone_dh_cur; 1095 int err; 1096 1097 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_IPD, NULL); 1098 if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK) 1099 return (err); 1100 return (Z_OK); 1101 } 1102 1103 int 1104 zonecfg_add_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 1105 { 1106 int err; 1107 1108 if (tabptr == NULL) 1109 return (Z_INVAL); 1110 1111 if ((err = operation_prep(handle)) != Z_OK) 1112 return (err); 1113 1114 if ((err = zonecfg_add_ipd_core(handle, tabptr)) != Z_OK) 1115 return (err); 1116 1117 return (Z_OK); 1118 } 1119 1120 int 1121 zonecfg_add_fs_option(struct zone_fstab *tabptr, char *option) 1122 { 1123 zone_fsopt_t *last, *old, *new; 1124 1125 last = tabptr->zone_fs_options; 1126 for (old = last; old != NULL; old = old->zone_fsopt_next) 1127 last = old; /* walk to the end of the list */ 1128 new = (zone_fsopt_t *)malloc(sizeof (zone_fsopt_t)); 1129 if (new == NULL) 1130 return (Z_NOMEM); 1131 (void) strlcpy(new->zone_fsopt_opt, option, 1132 sizeof (new->zone_fsopt_opt)); 1133 new->zone_fsopt_next = NULL; 1134 if (last == NULL) 1135 tabptr->zone_fs_options = new; 1136 else 1137 last->zone_fsopt_next = new; 1138 return (Z_OK); 1139 } 1140 1141 int 1142 zonecfg_remove_fs_option(struct zone_fstab *tabptr, char *option) 1143 { 1144 zone_fsopt_t *last, *this, *next; 1145 1146 last = tabptr->zone_fs_options; 1147 for (this = last; this != NULL; this = this->zone_fsopt_next) { 1148 if (strcmp(this->zone_fsopt_opt, option) == 0) { 1149 next = this->zone_fsopt_next; 1150 if (this == tabptr->zone_fs_options) 1151 tabptr->zone_fs_options = next; 1152 else 1153 last->zone_fsopt_next = next; 1154 free(this); 1155 return (Z_OK); 1156 } else 1157 last = this; 1158 } 1159 return (Z_NO_PROPERTY_ID); 1160 } 1161 1162 void 1163 zonecfg_free_fs_option_list(zone_fsopt_t *list) 1164 { 1165 zone_fsopt_t *this, *next; 1166 1167 for (this = list; this != NULL; this = next) { 1168 next = this->zone_fsopt_next; 1169 free(this); 1170 } 1171 } 1172 1173 void 1174 zonecfg_free_rctl_value_list(struct zone_rctlvaltab *valtab) 1175 { 1176 if (valtab == NULL) 1177 return; 1178 zonecfg_free_rctl_value_list(valtab->zone_rctlval_next); 1179 free(valtab); 1180 } 1181 1182 static boolean_t 1183 match_prop(xmlNodePtr cur, const xmlChar *attr, char *user_prop) 1184 { 1185 xmlChar *gotten_prop; 1186 int prop_result; 1187 1188 gotten_prop = xmlGetProp(cur, attr); 1189 if (gotten_prop == NULL) /* shouldn't happen */ 1190 return (B_FALSE); 1191 prop_result = xmlStrcmp(gotten_prop, (const xmlChar *) user_prop); 1192 xmlFree(gotten_prop); 1193 return ((prop_result == 0)); 1194 } 1195 1196 static int 1197 zonecfg_delete_filesystem_core(zone_dochandle_t handle, 1198 struct zone_fstab *tabptr) 1199 { 1200 xmlNodePtr cur = handle->zone_dh_cur; 1201 boolean_t dir_match, spec_match, raw_match, type_match; 1202 1203 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1204 if (xmlStrcmp(cur->name, DTD_ELEM_FS)) 1205 continue; 1206 dir_match = match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir); 1207 spec_match = match_prop(cur, DTD_ATTR_SPECIAL, 1208 tabptr->zone_fs_special); 1209 raw_match = match_prop(cur, DTD_ATTR_RAW, 1210 tabptr->zone_fs_raw); 1211 type_match = match_prop(cur, DTD_ATTR_TYPE, 1212 tabptr->zone_fs_type); 1213 if (dir_match && spec_match && raw_match && type_match) { 1214 xmlUnlinkNode(cur); 1215 xmlFreeNode(cur); 1216 return (Z_OK); 1217 } 1218 } 1219 return (Z_NO_RESOURCE_ID); 1220 } 1221 1222 int 1223 zonecfg_delete_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr) 1224 { 1225 int err; 1226 1227 if (tabptr == NULL) 1228 return (Z_INVAL); 1229 1230 if ((err = operation_prep(handle)) != Z_OK) 1231 return (err); 1232 1233 if ((err = zonecfg_delete_filesystem_core(handle, tabptr)) != Z_OK) 1234 return (err); 1235 1236 return (Z_OK); 1237 } 1238 1239 int 1240 zonecfg_modify_filesystem( 1241 zone_dochandle_t handle, 1242 struct zone_fstab *oldtabptr, 1243 struct zone_fstab *newtabptr) 1244 { 1245 int err; 1246 1247 if (oldtabptr == NULL || newtabptr == NULL) 1248 return (Z_INVAL); 1249 1250 if ((err = operation_prep(handle)) != Z_OK) 1251 return (err); 1252 1253 if ((err = zonecfg_delete_filesystem_core(handle, oldtabptr)) != Z_OK) 1254 return (err); 1255 1256 if ((err = zonecfg_add_filesystem_core(handle, newtabptr)) != Z_OK) 1257 return (err); 1258 1259 return (Z_OK); 1260 } 1261 1262 static int 1263 zonecfg_delete_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1264 { 1265 xmlNodePtr cur = handle->zone_dh_cur; 1266 1267 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1268 if (xmlStrcmp(cur->name, DTD_ELEM_IPD)) 1269 continue; 1270 if (match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir)) { 1271 xmlUnlinkNode(cur); 1272 xmlFreeNode(cur); 1273 return (Z_OK); 1274 } 1275 } 1276 return (Z_NO_RESOURCE_ID); 1277 } 1278 1279 int 1280 zonecfg_delete_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 1281 { 1282 int err; 1283 1284 if (tabptr == NULL) 1285 return (Z_INVAL); 1286 1287 if ((err = operation_prep(handle)) != Z_OK) 1288 return (err); 1289 1290 if ((err = zonecfg_delete_ipd_core(handle, tabptr)) != Z_OK) 1291 return (err); 1292 1293 return (Z_OK); 1294 } 1295 1296 int 1297 zonecfg_modify_ipd(zone_dochandle_t handle, struct zone_fstab *oldtabptr, 1298 struct zone_fstab *newtabptr) 1299 { 1300 int err; 1301 1302 if (oldtabptr == NULL || newtabptr == NULL) 1303 return (Z_INVAL); 1304 1305 if ((err = operation_prep(handle)) != Z_OK) 1306 return (err); 1307 1308 if ((err = zonecfg_delete_ipd_core(handle, oldtabptr)) != Z_OK) 1309 return (err); 1310 1311 if ((err = zonecfg_add_ipd_core(handle, newtabptr)) != Z_OK) 1312 return (err); 1313 1314 return (Z_OK); 1315 } 1316 1317 static int 1318 fetchprop(xmlNodePtr cur, const xmlChar *propname, char *dst, size_t dstsize) 1319 { 1320 xmlChar *property; 1321 size_t srcsize; 1322 1323 if ((property = xmlGetProp(cur, propname)) == NULL) 1324 return (Z_BAD_PROPERTY); 1325 srcsize = strlcpy(dst, (char *)property, dstsize); 1326 xmlFree(property); 1327 if (srcsize >= dstsize) 1328 return (Z_TOO_BIG); 1329 return (Z_OK); 1330 } 1331 1332 int 1333 zonecfg_lookup_filesystem( 1334 zone_dochandle_t handle, 1335 struct zone_fstab *tabptr) 1336 { 1337 xmlNodePtr cur, options, firstmatch; 1338 int err; 1339 char dirname[MAXPATHLEN], special[MAXPATHLEN], raw[MAXPATHLEN]; 1340 char type[FSTYPSZ]; 1341 char options_str[MAX_MNTOPT_STR]; 1342 1343 if (tabptr == NULL) 1344 return (Z_INVAL); 1345 1346 if ((err = operation_prep(handle)) != Z_OK) 1347 return (err); 1348 1349 /* 1350 * Walk the list of children looking for matches on any properties 1351 * specified in the fstab parameter. If more than one resource 1352 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return 1353 * Z_NO_RESOURCE_ID. 1354 */ 1355 cur = handle->zone_dh_cur; 1356 firstmatch = NULL; 1357 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1358 if (xmlStrcmp(cur->name, DTD_ELEM_FS)) 1359 continue; 1360 if (strlen(tabptr->zone_fs_dir) > 0) { 1361 if ((fetchprop(cur, DTD_ATTR_DIR, dirname, 1362 sizeof (dirname)) == Z_OK) && 1363 (strcmp(tabptr->zone_fs_dir, dirname) == 0)) { 1364 if (firstmatch == NULL) 1365 firstmatch = cur; 1366 else 1367 return (Z_INSUFFICIENT_SPEC); 1368 } 1369 } 1370 if (strlen(tabptr->zone_fs_special) > 0) { 1371 if ((fetchprop(cur, DTD_ATTR_SPECIAL, special, 1372 sizeof (special)) == Z_OK)) { 1373 if (strcmp(tabptr->zone_fs_special, 1374 special) == 0) { 1375 if (firstmatch == NULL) 1376 firstmatch = cur; 1377 else if (firstmatch != cur) 1378 return (Z_INSUFFICIENT_SPEC); 1379 } else { 1380 /* 1381 * If another property matched but this 1382 * one doesn't then reset firstmatch. 1383 */ 1384 if (firstmatch == cur) 1385 firstmatch = NULL; 1386 } 1387 } 1388 } 1389 if (strlen(tabptr->zone_fs_raw) > 0) { 1390 if ((fetchprop(cur, DTD_ATTR_RAW, raw, 1391 sizeof (raw)) == Z_OK)) { 1392 if (strcmp(tabptr->zone_fs_raw, raw) == 0) { 1393 if (firstmatch == NULL) 1394 firstmatch = cur; 1395 else if (firstmatch != cur) 1396 return (Z_INSUFFICIENT_SPEC); 1397 } else { 1398 /* 1399 * If another property matched but this 1400 * one doesn't then reset firstmatch. 1401 */ 1402 if (firstmatch == cur) 1403 firstmatch = NULL; 1404 } 1405 } 1406 } 1407 if (strlen(tabptr->zone_fs_type) > 0) { 1408 if ((fetchprop(cur, DTD_ATTR_TYPE, type, 1409 sizeof (type)) == Z_OK)) { 1410 if (strcmp(tabptr->zone_fs_type, type) == 0) { 1411 if (firstmatch == NULL) 1412 firstmatch = cur; 1413 else if (firstmatch != cur) 1414 return (Z_INSUFFICIENT_SPEC); 1415 } else { 1416 /* 1417 * If another property matched but this 1418 * one doesn't then reset firstmatch. 1419 */ 1420 if (firstmatch == cur) 1421 firstmatch = NULL; 1422 } 1423 } 1424 } 1425 } 1426 1427 if (firstmatch == NULL) 1428 return (Z_NO_RESOURCE_ID); 1429 1430 cur = firstmatch; 1431 1432 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 1433 sizeof (tabptr->zone_fs_dir))) != Z_OK) 1434 return (err); 1435 1436 if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special, 1437 sizeof (tabptr->zone_fs_special))) != Z_OK) 1438 return (err); 1439 1440 if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw, 1441 sizeof (tabptr->zone_fs_raw))) != Z_OK) 1442 return (err); 1443 1444 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type, 1445 sizeof (tabptr->zone_fs_type))) != Z_OK) 1446 return (err); 1447 1448 /* options are optional */ 1449 tabptr->zone_fs_options = NULL; 1450 for (options = cur->xmlChildrenNode; options != NULL; 1451 options = options->next) { 1452 if ((fetchprop(options, DTD_ATTR_NAME, options_str, 1453 sizeof (options_str)) != Z_OK)) 1454 break; 1455 if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK) 1456 break; 1457 } 1458 return (Z_OK); 1459 } 1460 1461 int 1462 zonecfg_lookup_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 1463 { 1464 xmlNodePtr cur, match; 1465 int err; 1466 char dirname[MAXPATHLEN]; 1467 1468 if (tabptr == NULL) 1469 return (Z_INVAL); 1470 1471 if ((err = operation_prep(handle)) != Z_OK) 1472 return (err); 1473 1474 /* 1475 * General algorithm: 1476 * Walk the list of children looking for matches on any properties 1477 * specified in the fstab parameter. If more than one resource 1478 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return 1479 * Z_NO_RESOURCE_ID. 1480 */ 1481 cur = handle->zone_dh_cur; 1482 match = NULL; 1483 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1484 if (xmlStrcmp(cur->name, DTD_ELEM_IPD)) 1485 continue; 1486 if (strlen(tabptr->zone_fs_dir) > 0) { 1487 if ((fetchprop(cur, DTD_ATTR_DIR, dirname, 1488 sizeof (dirname)) == Z_OK) && 1489 (strcmp(tabptr->zone_fs_dir, dirname) == 0)) { 1490 if (match == NULL) 1491 match = cur; 1492 else 1493 return (Z_INSUFFICIENT_SPEC); 1494 } 1495 } 1496 } 1497 1498 if (match == NULL) 1499 return (Z_NO_RESOURCE_ID); 1500 1501 cur = match; 1502 1503 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 1504 sizeof (tabptr->zone_fs_dir))) != Z_OK) 1505 return (err); 1506 1507 return (Z_OK); 1508 } 1509 1510 /* 1511 * Compare two IP addresses in string form. Allow for the possibility that 1512 * one might have "/<prefix-length>" at the end: allow a match on just the 1513 * IP address (or host name) part. 1514 */ 1515 1516 boolean_t 1517 zonecfg_same_net_address(char *a1, char *a2) 1518 { 1519 char *slashp, *slashp1, *slashp2; 1520 int result; 1521 1522 if (strcmp(a1, a2) == 0) 1523 return (B_TRUE); 1524 1525 /* 1526 * If neither has a slash or both do, they need to match to be 1527 * considered the same, but they did not match above, so fail. 1528 */ 1529 slashp1 = strchr(a1, '/'); 1530 slashp2 = strchr(a2, '/'); 1531 if ((slashp1 == NULL && slashp2 == NULL) || 1532 (slashp1 != NULL && slashp2 != NULL)) 1533 return (B_FALSE); 1534 1535 /* 1536 * Only one had a slash: pick that one, zero out the slash, compare 1537 * the "address only" strings, restore the slash, and return the 1538 * result of the comparison. 1539 */ 1540 slashp = (slashp1 == NULL) ? slashp2 : slashp1; 1541 *slashp = '\0'; 1542 result = strcmp(a1, a2); 1543 *slashp = '/'; 1544 return ((result == 0)); 1545 } 1546 1547 int 1548 zonecfg_valid_net_address(char *address, struct lifreq *lifr) 1549 { 1550 struct sockaddr_in *sin4; 1551 struct sockaddr_in6 *sin6; 1552 struct addrinfo hints, *result; 1553 char *slashp = strchr(address, '/'); 1554 1555 bzero(lifr, sizeof (struct lifreq)); 1556 sin4 = (struct sockaddr_in *)&lifr->lifr_addr; 1557 sin6 = (struct sockaddr_in6 *)&lifr->lifr_addr; 1558 if (slashp != NULL) 1559 *slashp = '\0'; 1560 if (inet_pton(AF_INET, address, &sin4->sin_addr) == 1) { 1561 sin4->sin_family = AF_INET; 1562 } else if (inet_pton(AF_INET6, address, &sin6->sin6_addr) == 1) { 1563 if (slashp == NULL) 1564 return (Z_IPV6_ADDR_PREFIX_LEN); 1565 sin6->sin6_family = AF_INET6; 1566 } else { 1567 /* "address" may be a host name */ 1568 (void) memset(&hints, 0, sizeof (hints)); 1569 hints.ai_family = PF_INET; 1570 if (getaddrinfo(address, NULL, &hints, &result) != 0) 1571 return (Z_BOGUS_ADDRESS); 1572 sin4->sin_family = result->ai_family; 1573 1574 (void) memcpy(&sin4->sin_addr, 1575 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1576 &((struct sockaddr_in *)result->ai_addr)->sin_addr, 1577 sizeof (struct in_addr)); 1578 1579 freeaddrinfo(result); 1580 } 1581 return (Z_OK); 1582 } 1583 1584 int 1585 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 1586 { 1587 xmlNodePtr cur, firstmatch; 1588 int err; 1589 char address[INET6_ADDRSTRLEN], physical[LIFNAMSIZ]; 1590 1591 if (tabptr == NULL) 1592 return (Z_INVAL); 1593 1594 if ((err = operation_prep(handle)) != Z_OK) 1595 return (err); 1596 1597 cur = handle->zone_dh_cur; 1598 firstmatch = NULL; 1599 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1600 if (xmlStrcmp(cur->name, DTD_ELEM_NET)) 1601 continue; 1602 if (strlen(tabptr->zone_nwif_physical) > 0) { 1603 if ((fetchprop(cur, DTD_ATTR_PHYSICAL, physical, 1604 sizeof (physical)) == Z_OK) && 1605 (strcmp(tabptr->zone_nwif_physical, 1606 physical) == 0)) { 1607 if (firstmatch == NULL) 1608 firstmatch = cur; 1609 else 1610 return (Z_INSUFFICIENT_SPEC); 1611 } 1612 } 1613 if (strlen(tabptr->zone_nwif_address) > 0) { 1614 if ((fetchprop(cur, DTD_ATTR_ADDRESS, address, 1615 sizeof (address)) == Z_OK)) { 1616 if (zonecfg_same_net_address( 1617 tabptr->zone_nwif_address, address)) { 1618 if (firstmatch == NULL) 1619 firstmatch = cur; 1620 else if (firstmatch != cur) 1621 return (Z_INSUFFICIENT_SPEC); 1622 } else { 1623 /* 1624 * If another property matched but this 1625 * one doesn't then reset firstmatch. 1626 */ 1627 if (firstmatch == cur) 1628 firstmatch = NULL; 1629 } 1630 } 1631 } 1632 } 1633 if (firstmatch == NULL) 1634 return (Z_NO_RESOURCE_ID); 1635 1636 cur = firstmatch; 1637 1638 if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical, 1639 sizeof (tabptr->zone_nwif_physical))) != Z_OK) 1640 return (err); 1641 1642 if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address, 1643 sizeof (tabptr->zone_nwif_address))) != Z_OK) 1644 return (err); 1645 1646 return (Z_OK); 1647 } 1648 1649 static int 1650 zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 1651 { 1652 xmlNodePtr newnode, cur = handle->zone_dh_cur; 1653 int err; 1654 1655 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL); 1656 if ((err = newprop(newnode, DTD_ATTR_ADDRESS, 1657 tabptr->zone_nwif_address)) != Z_OK) 1658 return (err); 1659 if ((err = newprop(newnode, DTD_ATTR_PHYSICAL, 1660 tabptr->zone_nwif_physical)) != Z_OK) 1661 return (err); 1662 return (Z_OK); 1663 } 1664 1665 int 1666 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 1667 { 1668 int err; 1669 1670 if (tabptr == NULL) 1671 return (Z_INVAL); 1672 1673 if ((err = operation_prep(handle)) != Z_OK) 1674 return (err); 1675 1676 if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK) 1677 return (err); 1678 1679 return (Z_OK); 1680 } 1681 1682 static int 1683 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 1684 { 1685 xmlNodePtr cur = handle->zone_dh_cur; 1686 boolean_t addr_match, phys_match; 1687 1688 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1689 if (xmlStrcmp(cur->name, DTD_ELEM_NET)) 1690 continue; 1691 1692 addr_match = match_prop(cur, DTD_ATTR_ADDRESS, 1693 tabptr->zone_nwif_address); 1694 phys_match = match_prop(cur, DTD_ATTR_PHYSICAL, 1695 tabptr->zone_nwif_physical); 1696 1697 if (addr_match && phys_match) { 1698 xmlUnlinkNode(cur); 1699 xmlFreeNode(cur); 1700 return (Z_OK); 1701 } 1702 } 1703 return (Z_NO_RESOURCE_ID); 1704 } 1705 1706 int 1707 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 1708 { 1709 int err; 1710 1711 if (tabptr == NULL) 1712 return (Z_INVAL); 1713 1714 if ((err = operation_prep(handle)) != Z_OK) 1715 return (err); 1716 1717 if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK) 1718 return (err); 1719 1720 return (Z_OK); 1721 } 1722 1723 int 1724 zonecfg_modify_nwif( 1725 zone_dochandle_t handle, 1726 struct zone_nwiftab *oldtabptr, 1727 struct zone_nwiftab *newtabptr) 1728 { 1729 int err; 1730 1731 if (oldtabptr == NULL || newtabptr == NULL) 1732 return (Z_INVAL); 1733 1734 if ((err = operation_prep(handle)) != Z_OK) 1735 return (err); 1736 1737 if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK) 1738 return (err); 1739 1740 if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK) 1741 return (err); 1742 1743 return (Z_OK); 1744 } 1745 1746 int 1747 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 1748 { 1749 xmlNodePtr cur, firstmatch; 1750 int err; 1751 char match[MAXPATHLEN]; 1752 1753 if (tabptr == NULL) 1754 return (Z_INVAL); 1755 1756 if ((err = operation_prep(handle)) != Z_OK) 1757 return (err); 1758 1759 cur = handle->zone_dh_cur; 1760 firstmatch = NULL; 1761 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1762 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 1763 continue; 1764 if (strlen(tabptr->zone_dev_match) == 0) 1765 continue; 1766 1767 if ((fetchprop(cur, DTD_ATTR_MATCH, match, 1768 sizeof (match)) == Z_OK)) { 1769 if (strcmp(tabptr->zone_dev_match, 1770 match) == 0) { 1771 if (firstmatch == NULL) 1772 firstmatch = cur; 1773 else if (firstmatch != cur) 1774 return (Z_INSUFFICIENT_SPEC); 1775 } else { 1776 /* 1777 * If another property matched but this 1778 * one doesn't then reset firstmatch. 1779 */ 1780 if (firstmatch == cur) 1781 firstmatch = NULL; 1782 } 1783 } 1784 } 1785 if (firstmatch == NULL) 1786 return (Z_NO_RESOURCE_ID); 1787 1788 cur = firstmatch; 1789 1790 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match, 1791 sizeof (tabptr->zone_dev_match))) != Z_OK) 1792 return (err); 1793 1794 return (Z_OK); 1795 } 1796 1797 static int 1798 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr) 1799 { 1800 xmlNodePtr newnode, cur = handle->zone_dh_cur; 1801 int err; 1802 1803 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL); 1804 1805 if ((err = newprop(newnode, DTD_ATTR_MATCH, 1806 tabptr->zone_dev_match)) != Z_OK) 1807 return (err); 1808 1809 return (Z_OK); 1810 } 1811 1812 int 1813 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 1814 { 1815 int err; 1816 1817 if (tabptr == NULL) 1818 return (Z_INVAL); 1819 1820 if ((err = operation_prep(handle)) != Z_OK) 1821 return (err); 1822 1823 if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK) 1824 return (err); 1825 1826 return (Z_OK); 1827 } 1828 1829 static int 1830 zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr) 1831 { 1832 xmlNodePtr cur = handle->zone_dh_cur; 1833 int match_match; 1834 1835 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1836 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 1837 continue; 1838 1839 match_match = match_prop(cur, DTD_ATTR_MATCH, 1840 tabptr->zone_dev_match); 1841 1842 if (match_match) { 1843 xmlUnlinkNode(cur); 1844 xmlFreeNode(cur); 1845 return (Z_OK); 1846 } 1847 } 1848 return (Z_NO_RESOURCE_ID); 1849 } 1850 1851 int 1852 zonecfg_delete_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 1853 { 1854 int err; 1855 1856 if (tabptr == NULL) 1857 return (Z_INVAL); 1858 1859 if ((err = operation_prep(handle)) != Z_OK) 1860 return (err); 1861 1862 if ((err = zonecfg_delete_dev_core(handle, tabptr)) != Z_OK) 1863 return (err); 1864 1865 return (Z_OK); 1866 } 1867 1868 int 1869 zonecfg_modify_dev( 1870 zone_dochandle_t handle, 1871 struct zone_devtab *oldtabptr, 1872 struct zone_devtab *newtabptr) 1873 { 1874 int err; 1875 1876 if (oldtabptr == NULL || newtabptr == NULL) 1877 return (Z_INVAL); 1878 1879 if ((err = operation_prep(handle)) != Z_OK) 1880 return (err); 1881 1882 if ((err = zonecfg_delete_dev_core(handle, oldtabptr)) != Z_OK) 1883 return (err); 1884 1885 if ((err = zonecfg_add_dev_core(handle, newtabptr)) != Z_OK) 1886 return (err); 1887 1888 return (Z_OK); 1889 } 1890 1891 /* 1892 * This is the set of devices which must be present in every zone. Users 1893 * can augment this list with additional device rules in their zone 1894 * configuration, but at present cannot remove any of the this set of 1895 * standard devices. All matching is done by /dev pathname (the "/dev" 1896 * part is implicit. Try to keep rules which match a large number of 1897 * devices (like the pts rule) first. 1898 */ 1899 static const char *standard_devs[] = { 1900 "pts/*", 1901 "ptmx", 1902 "random", 1903 "urandom", 1904 "poll", 1905 "pool", 1906 "kstat", 1907 "zero", 1908 "null", 1909 "crypto", 1910 "cryptoadm", 1911 "ticots", 1912 "ticotsord", 1913 "ticlts", 1914 "lo0", 1915 "lo1", 1916 "lo2", 1917 "lo3", 1918 "sad/user", 1919 "tty", 1920 "logindmux", 1921 "log", 1922 "conslog", 1923 "arp", 1924 "tcp", 1925 "tcp6", 1926 "udp", 1927 "udp6", 1928 "sysevent", 1929 #ifdef __sparc 1930 "openprom", 1931 #endif 1932 "cpu/self/cpuid", 1933 "dtrace/helper", 1934 "zfs", 1935 NULL 1936 }; 1937 1938 /* 1939 * This function finds everything mounted under a zone's rootpath. 1940 * This returns the number of mounts under rootpath, or -1 on error. 1941 * callback is called once per mount found with the first argument 1942 * pointing to the mount point. 1943 * 1944 * If the callback function returns non-zero zonecfg_find_mounts 1945 * aborts with an error. 1946 */ 1947 1948 int 1949 zonecfg_find_mounts(char *rootpath, int (*callback)(const char *, void *), 1950 void *priv) { 1951 FILE *mnttab; 1952 struct mnttab m; 1953 size_t l; 1954 int rv = 0; 1955 1956 assert(rootpath != NULL); 1957 1958 l = strlen(rootpath); 1959 1960 mnttab = fopen("/etc/mnttab", "r"); 1961 1962 if (mnttab == NULL) 1963 return (-1); 1964 1965 if (ioctl(fileno(mnttab), MNTIOC_SHOWHIDDEN, NULL) < 0) { 1966 rv = -1; 1967 goto out; 1968 } 1969 1970 while (!getmntent(mnttab, &m)) { 1971 if ((strncmp(rootpath, m.mnt_mountp, l) == 0) && 1972 (m.mnt_mountp[l] == '/')) { 1973 rv++; 1974 if (callback == NULL) 1975 continue; 1976 if (callback(m.mnt_mountp, priv)) { 1977 rv = -1; 1978 goto out; 1979 1980 } 1981 } 1982 } 1983 1984 out: 1985 (void) fclose(mnttab); 1986 return (rv); 1987 } 1988 1989 /* 1990 * This routine is used to determine if a given device should appear in the 1991 * zone represented by 'handle'. First it consults the list of "standard" 1992 * zone devices. Then it scans the user-supplied device entries. 1993 */ 1994 int 1995 zonecfg_match_dev(zone_dochandle_t handle, char *devpath, 1996 struct zone_devtab *out_match) 1997 { 1998 int err; 1999 boolean_t found = B_FALSE; 2000 char match[MAXPATHLEN]; 2001 const char **stdmatch; 2002 xmlNodePtr cur; 2003 2004 if (handle == NULL || devpath == NULL) 2005 return (Z_INVAL); 2006 2007 /* 2008 * Check the "standard" devices which we require to be present. 2009 */ 2010 for (stdmatch = &standard_devs[0]; *stdmatch != NULL; stdmatch++) { 2011 /* 2012 * fnmatch gives us simple but powerful shell-style matching. 2013 */ 2014 if (fnmatch(*stdmatch, devpath, FNM_PATHNAME) == 0) { 2015 if (!out_match) 2016 return (Z_OK); 2017 (void) snprintf(out_match->zone_dev_match, 2018 sizeof (out_match->zone_dev_match), 2019 "/dev/%s", *stdmatch); 2020 return (Z_OK); 2021 } 2022 } 2023 2024 /* 2025 * We got no hits in the set of standard devices. On to the user 2026 * supplied ones. 2027 */ 2028 if ((err = operation_prep(handle)) != Z_OK) { 2029 handle->zone_dh_cur = NULL; 2030 return (err); 2031 } 2032 2033 cur = handle->zone_dh_cur; 2034 cur = cur->xmlChildrenNode; 2035 if (cur == NULL) 2036 return (Z_NO_ENTRY); 2037 handle->zone_dh_cur = cur; 2038 2039 for (; cur != NULL; cur = cur->next) { 2040 char *m; 2041 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE) != 0) 2042 continue; 2043 if ((err = fetchprop(cur, DTD_ATTR_MATCH, match, 2044 sizeof (match))) != Z_OK) { 2045 handle->zone_dh_cur = handle->zone_dh_top; 2046 return (err); 2047 } 2048 m = match; 2049 /* 2050 * fnmatch gives us simple but powerful shell-style matching; 2051 * but first, we need to strip out /dev/ from the matching rule. 2052 */ 2053 if (strncmp(m, "/dev/", 5) == 0) 2054 m += 5; 2055 2056 if (fnmatch(m, devpath, FNM_PATHNAME) == 0) { 2057 found = B_TRUE; 2058 break; 2059 } 2060 } 2061 2062 if (!found) 2063 return (Z_NO_ENTRY); 2064 2065 if (!out_match) 2066 return (Z_OK); 2067 2068 (void) strlcpy(out_match->zone_dev_match, match, 2069 sizeof (out_match->zone_dev_match)); 2070 return (Z_OK); 2071 } 2072 2073 int 2074 zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2075 { 2076 xmlNodePtr cur, firstmatch; 2077 int err; 2078 char name[MAXNAMELEN], type[MAXNAMELEN], value[MAXNAMELEN]; 2079 2080 if (tabptr == NULL) 2081 return (Z_INVAL); 2082 2083 if ((err = operation_prep(handle)) != Z_OK) 2084 return (err); 2085 2086 cur = handle->zone_dh_cur; 2087 firstmatch = NULL; 2088 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2089 if (xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 2090 continue; 2091 if (strlen(tabptr->zone_attr_name) > 0) { 2092 if ((fetchprop(cur, DTD_ATTR_NAME, name, 2093 sizeof (name)) == Z_OK) && 2094 (strcmp(tabptr->zone_attr_name, name) == 0)) { 2095 if (firstmatch == NULL) 2096 firstmatch = cur; 2097 else 2098 return (Z_INSUFFICIENT_SPEC); 2099 } 2100 } 2101 if (strlen(tabptr->zone_attr_type) > 0) { 2102 if ((fetchprop(cur, DTD_ATTR_TYPE, type, 2103 sizeof (type)) == Z_OK)) { 2104 if (strcmp(tabptr->zone_attr_type, type) == 0) { 2105 if (firstmatch == NULL) 2106 firstmatch = cur; 2107 else if (firstmatch != cur) 2108 return (Z_INSUFFICIENT_SPEC); 2109 } else { 2110 /* 2111 * If another property matched but this 2112 * one doesn't then reset firstmatch. 2113 */ 2114 if (firstmatch == cur) 2115 firstmatch = NULL; 2116 } 2117 } 2118 } 2119 if (strlen(tabptr->zone_attr_value) > 0) { 2120 if ((fetchprop(cur, DTD_ATTR_VALUE, value, 2121 sizeof (value)) == Z_OK)) { 2122 if (strcmp(tabptr->zone_attr_value, value) == 2123 0) { 2124 if (firstmatch == NULL) 2125 firstmatch = cur; 2126 else if (firstmatch != cur) 2127 return (Z_INSUFFICIENT_SPEC); 2128 } else { 2129 /* 2130 * If another property matched but this 2131 * one doesn't then reset firstmatch. 2132 */ 2133 if (firstmatch == cur) 2134 firstmatch = NULL; 2135 } 2136 } 2137 } 2138 } 2139 if (firstmatch == NULL) 2140 return (Z_NO_RESOURCE_ID); 2141 2142 cur = firstmatch; 2143 2144 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name, 2145 sizeof (tabptr->zone_attr_name))) != Z_OK) 2146 return (err); 2147 2148 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type, 2149 sizeof (tabptr->zone_attr_type))) != Z_OK) 2150 return (err); 2151 2152 if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value, 2153 sizeof (tabptr->zone_attr_value))) != Z_OK) 2154 return (err); 2155 2156 return (Z_OK); 2157 } 2158 2159 static int 2160 zonecfg_add_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2161 { 2162 xmlNodePtr newnode, cur = handle->zone_dh_cur; 2163 int err; 2164 2165 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ATTR, NULL); 2166 err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_attr_name); 2167 if (err != Z_OK) 2168 return (err); 2169 err = newprop(newnode, DTD_ATTR_TYPE, tabptr->zone_attr_type); 2170 if (err != Z_OK) 2171 return (err); 2172 err = newprop(newnode, DTD_ATTR_VALUE, tabptr->zone_attr_value); 2173 if (err != Z_OK) 2174 return (err); 2175 return (Z_OK); 2176 } 2177 2178 int 2179 zonecfg_add_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2180 { 2181 int err; 2182 2183 if (tabptr == NULL) 2184 return (Z_INVAL); 2185 2186 if ((err = operation_prep(handle)) != Z_OK) 2187 return (err); 2188 2189 if ((err = zonecfg_add_attr_core(handle, tabptr)) != Z_OK) 2190 return (err); 2191 2192 return (Z_OK); 2193 } 2194 2195 static int 2196 zonecfg_delete_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2197 { 2198 xmlNodePtr cur = handle->zone_dh_cur; 2199 int name_match, type_match, value_match; 2200 2201 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2202 if (xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 2203 continue; 2204 2205 name_match = match_prop(cur, DTD_ATTR_NAME, 2206 tabptr->zone_attr_name); 2207 type_match = match_prop(cur, DTD_ATTR_TYPE, 2208 tabptr->zone_attr_type); 2209 value_match = match_prop(cur, DTD_ATTR_VALUE, 2210 tabptr->zone_attr_value); 2211 2212 if (name_match && type_match && value_match) { 2213 xmlUnlinkNode(cur); 2214 xmlFreeNode(cur); 2215 return (Z_OK); 2216 } 2217 } 2218 return (Z_NO_RESOURCE_ID); 2219 } 2220 2221 int 2222 zonecfg_delete_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2223 { 2224 int err; 2225 2226 if (tabptr == NULL) 2227 return (Z_INVAL); 2228 2229 if ((err = operation_prep(handle)) != Z_OK) 2230 return (err); 2231 2232 if ((err = zonecfg_delete_attr_core(handle, tabptr)) != Z_OK) 2233 return (err); 2234 2235 return (Z_OK); 2236 } 2237 2238 int 2239 zonecfg_modify_attr( 2240 zone_dochandle_t handle, 2241 struct zone_attrtab *oldtabptr, 2242 struct zone_attrtab *newtabptr) 2243 { 2244 int err; 2245 2246 if (oldtabptr == NULL || newtabptr == NULL) 2247 return (Z_INVAL); 2248 2249 if ((err = operation_prep(handle)) != Z_OK) 2250 return (err); 2251 2252 if ((err = zonecfg_delete_attr_core(handle, oldtabptr)) != Z_OK) 2253 return (err); 2254 2255 if ((err = zonecfg_add_attr_core(handle, newtabptr)) != Z_OK) 2256 return (err); 2257 2258 return (Z_OK); 2259 } 2260 2261 int 2262 zonecfg_get_attr_boolean(const struct zone_attrtab *attr, boolean_t *value) 2263 { 2264 if (attr == NULL) 2265 return (Z_INVAL); 2266 2267 if (strcmp(attr->zone_attr_type, DTD_ENTITY_BOOLEAN) != 0) 2268 return (Z_INVAL); 2269 2270 if (strcmp(attr->zone_attr_value, DTD_ENTITY_TRUE) == 0) { 2271 *value = B_TRUE; 2272 return (Z_OK); 2273 } 2274 if (strcmp(attr->zone_attr_value, DTD_ENTITY_FALSE) == 0) { 2275 *value = B_FALSE; 2276 return (Z_OK); 2277 } 2278 return (Z_INVAL); 2279 } 2280 2281 int 2282 zonecfg_get_attr_int(const struct zone_attrtab *attr, int64_t *value) 2283 { 2284 long long result; 2285 char *endptr; 2286 2287 if (attr == NULL) 2288 return (Z_INVAL); 2289 2290 if (strcmp(attr->zone_attr_type, DTD_ENTITY_INT) != 0) 2291 return (Z_INVAL); 2292 2293 errno = 0; 2294 result = strtoll(attr->zone_attr_value, &endptr, 10); 2295 if (errno != 0 || *endptr != '\0') 2296 return (Z_INVAL); 2297 *value = result; 2298 return (Z_OK); 2299 } 2300 2301 int 2302 zonecfg_get_attr_string(const struct zone_attrtab *attr, char *value, 2303 size_t val_sz) 2304 { 2305 if (attr == NULL) 2306 return (Z_INVAL); 2307 2308 if (strcmp(attr->zone_attr_type, DTD_ENTITY_STRING) != 0) 2309 return (Z_INVAL); 2310 2311 if (strlcpy(value, attr->zone_attr_value, val_sz) >= val_sz) 2312 return (Z_TOO_BIG); 2313 return (Z_OK); 2314 } 2315 2316 int 2317 zonecfg_get_attr_uint(const struct zone_attrtab *attr, uint64_t *value) 2318 { 2319 unsigned long long result; 2320 long long neg_result; 2321 char *endptr; 2322 2323 if (attr == NULL) 2324 return (Z_INVAL); 2325 2326 if (strcmp(attr->zone_attr_type, DTD_ENTITY_UINT) != 0) 2327 return (Z_INVAL); 2328 2329 errno = 0; 2330 result = strtoull(attr->zone_attr_value, &endptr, 10); 2331 if (errno != 0 || *endptr != '\0') 2332 return (Z_INVAL); 2333 errno = 0; 2334 neg_result = strtoll(attr->zone_attr_value, &endptr, 10); 2335 /* 2336 * Incredibly, strtoull("<negative number>", ...) will not fail but 2337 * return whatever (negative) number cast as a u_longlong_t, so we 2338 * need to look for this here. 2339 */ 2340 if (errno == 0 && neg_result < 0) 2341 return (Z_INVAL); 2342 *value = result; 2343 return (Z_OK); 2344 } 2345 2346 int 2347 zonecfg_lookup_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2348 { 2349 xmlNodePtr cur, val; 2350 char savedname[MAXNAMELEN]; 2351 struct zone_rctlvaltab *valptr; 2352 int err; 2353 2354 if (tabptr->zone_rctl_name == NULL || 2355 strlen(tabptr->zone_rctl_name) == 0) 2356 return (Z_INVAL); 2357 2358 if ((err = operation_prep(handle)) != Z_OK) 2359 return (err); 2360 2361 cur = handle->zone_dh_cur; 2362 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2363 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 2364 continue; 2365 if ((fetchprop(cur, DTD_ATTR_NAME, savedname, 2366 sizeof (savedname)) == Z_OK) && 2367 (strcmp(savedname, tabptr->zone_rctl_name) == 0)) { 2368 tabptr->zone_rctl_valptr = NULL; 2369 for (val = cur->xmlChildrenNode; val != NULL; 2370 val = val->next) { 2371 valptr = (struct zone_rctlvaltab *)malloc( 2372 sizeof (struct zone_rctlvaltab)); 2373 if (valptr == NULL) 2374 return (Z_NOMEM); 2375 if ((fetchprop(val, DTD_ATTR_PRIV, 2376 valptr->zone_rctlval_priv, 2377 sizeof (valptr->zone_rctlval_priv)) != 2378 Z_OK)) 2379 break; 2380 if ((fetchprop(val, DTD_ATTR_LIMIT, 2381 valptr->zone_rctlval_limit, 2382 sizeof (valptr->zone_rctlval_limit)) != 2383 Z_OK)) 2384 break; 2385 if ((fetchprop(val, DTD_ATTR_ACTION, 2386 valptr->zone_rctlval_action, 2387 sizeof (valptr->zone_rctlval_action)) != 2388 Z_OK)) 2389 break; 2390 if (zonecfg_add_rctl_value(tabptr, valptr) != 2391 Z_OK) 2392 break; 2393 } 2394 return (Z_OK); 2395 } 2396 } 2397 return (Z_NO_RESOURCE_ID); 2398 } 2399 2400 static int 2401 zonecfg_add_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2402 { 2403 xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode; 2404 struct zone_rctlvaltab *valptr; 2405 int err; 2406 2407 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_RCTL, NULL); 2408 err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_rctl_name); 2409 if (err != Z_OK) 2410 return (err); 2411 for (valptr = tabptr->zone_rctl_valptr; valptr != NULL; 2412 valptr = valptr->zone_rctlval_next) { 2413 valnode = xmlNewTextChild(newnode, NULL, 2414 DTD_ELEM_RCTLVALUE, NULL); 2415 err = newprop(valnode, DTD_ATTR_PRIV, 2416 valptr->zone_rctlval_priv); 2417 if (err != Z_OK) 2418 return (err); 2419 err = newprop(valnode, DTD_ATTR_LIMIT, 2420 valptr->zone_rctlval_limit); 2421 if (err != Z_OK) 2422 return (err); 2423 err = newprop(valnode, DTD_ATTR_ACTION, 2424 valptr->zone_rctlval_action); 2425 if (err != Z_OK) 2426 return (err); 2427 } 2428 return (Z_OK); 2429 } 2430 2431 int 2432 zonecfg_add_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2433 { 2434 int err; 2435 2436 if (tabptr == NULL || tabptr->zone_rctl_name == NULL) 2437 return (Z_INVAL); 2438 2439 if ((err = operation_prep(handle)) != Z_OK) 2440 return (err); 2441 2442 if ((err = zonecfg_add_rctl_core(handle, tabptr)) != Z_OK) 2443 return (err); 2444 2445 return (Z_OK); 2446 } 2447 2448 static int 2449 zonecfg_delete_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2450 { 2451 xmlNodePtr cur = handle->zone_dh_cur; 2452 xmlChar *savedname; 2453 int name_result; 2454 2455 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2456 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 2457 continue; 2458 2459 savedname = xmlGetProp(cur, DTD_ATTR_NAME); 2460 if (savedname == NULL) /* shouldn't happen */ 2461 continue; 2462 name_result = xmlStrcmp(savedname, 2463 (const xmlChar *) tabptr->zone_rctl_name); 2464 xmlFree(savedname); 2465 2466 if (name_result == 0) { 2467 xmlUnlinkNode(cur); 2468 xmlFreeNode(cur); 2469 return (Z_OK); 2470 } 2471 } 2472 return (Z_NO_RESOURCE_ID); 2473 } 2474 2475 int 2476 zonecfg_delete_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2477 { 2478 int err; 2479 2480 if (tabptr == NULL || tabptr->zone_rctl_name == NULL) 2481 return (Z_INVAL); 2482 2483 if ((err = operation_prep(handle)) != Z_OK) 2484 return (err); 2485 2486 if ((err = zonecfg_delete_rctl_core(handle, tabptr)) != Z_OK) 2487 return (err); 2488 2489 return (Z_OK); 2490 } 2491 2492 int 2493 zonecfg_modify_rctl( 2494 zone_dochandle_t handle, 2495 struct zone_rctltab *oldtabptr, 2496 struct zone_rctltab *newtabptr) 2497 { 2498 int err; 2499 2500 if (oldtabptr == NULL || oldtabptr->zone_rctl_name == NULL || 2501 newtabptr == NULL || newtabptr->zone_rctl_name == NULL) 2502 return (Z_INVAL); 2503 2504 if ((err = operation_prep(handle)) != Z_OK) 2505 return (err); 2506 2507 if ((err = zonecfg_delete_rctl_core(handle, oldtabptr)) != Z_OK) 2508 return (err); 2509 2510 if ((err = zonecfg_add_rctl_core(handle, newtabptr)) != Z_OK) 2511 return (err); 2512 2513 return (Z_OK); 2514 } 2515 2516 int 2517 zonecfg_add_rctl_value( 2518 struct zone_rctltab *tabptr, 2519 struct zone_rctlvaltab *valtabptr) 2520 { 2521 struct zone_rctlvaltab *last, *old, *new; 2522 rctlblk_t *rctlblk = alloca(rctlblk_size()); 2523 2524 last = tabptr->zone_rctl_valptr; 2525 for (old = last; old != NULL; old = old->zone_rctlval_next) 2526 last = old; /* walk to the end of the list */ 2527 new = valtabptr; /* alloc'd by caller */ 2528 new->zone_rctlval_next = NULL; 2529 if (zonecfg_construct_rctlblk(valtabptr, rctlblk) != Z_OK) 2530 return (Z_INVAL); 2531 if (!zonecfg_valid_rctlblk(rctlblk)) 2532 return (Z_INVAL); 2533 if (last == NULL) 2534 tabptr->zone_rctl_valptr = new; 2535 else 2536 last->zone_rctlval_next = new; 2537 return (Z_OK); 2538 } 2539 2540 int 2541 zonecfg_remove_rctl_value( 2542 struct zone_rctltab *tabptr, 2543 struct zone_rctlvaltab *valtabptr) 2544 { 2545 struct zone_rctlvaltab *last, *this, *next; 2546 2547 last = tabptr->zone_rctl_valptr; 2548 for (this = last; this != NULL; this = this->zone_rctlval_next) { 2549 if (strcmp(this->zone_rctlval_priv, 2550 valtabptr->zone_rctlval_priv) == 0 && 2551 strcmp(this->zone_rctlval_limit, 2552 valtabptr->zone_rctlval_limit) == 0 && 2553 strcmp(this->zone_rctlval_action, 2554 valtabptr->zone_rctlval_action) == 0) { 2555 next = this->zone_rctlval_next; 2556 if (this == tabptr->zone_rctl_valptr) 2557 tabptr->zone_rctl_valptr = next; 2558 else 2559 last->zone_rctlval_next = next; 2560 free(this); 2561 return (Z_OK); 2562 } else 2563 last = this; 2564 } 2565 return (Z_NO_PROPERTY_ID); 2566 } 2567 2568 char * 2569 zonecfg_strerror(int errnum) 2570 { 2571 switch (errnum) { 2572 case Z_OK: 2573 return (dgettext(TEXT_DOMAIN, "OK")); 2574 case Z_EMPTY_DOCUMENT: 2575 return (dgettext(TEXT_DOMAIN, "Empty document")); 2576 case Z_WRONG_DOC_TYPE: 2577 return (dgettext(TEXT_DOMAIN, "Wrong document type")); 2578 case Z_BAD_PROPERTY: 2579 return (dgettext(TEXT_DOMAIN, "Bad document property")); 2580 case Z_TEMP_FILE: 2581 return (dgettext(TEXT_DOMAIN, 2582 "Problem creating temporary file")); 2583 case Z_SAVING_FILE: 2584 return (dgettext(TEXT_DOMAIN, "Problem saving file")); 2585 case Z_NO_ENTRY: 2586 return (dgettext(TEXT_DOMAIN, "No such entry")); 2587 case Z_BOGUS_ZONE_NAME: 2588 return (dgettext(TEXT_DOMAIN, "Bogus zone name")); 2589 case Z_REQD_RESOURCE_MISSING: 2590 return (dgettext(TEXT_DOMAIN, "Required resource missing")); 2591 case Z_REQD_PROPERTY_MISSING: 2592 return (dgettext(TEXT_DOMAIN, "Required property missing")); 2593 case Z_BAD_HANDLE: 2594 return (dgettext(TEXT_DOMAIN, "Bad handle")); 2595 case Z_NOMEM: 2596 return (dgettext(TEXT_DOMAIN, "Out of memory")); 2597 case Z_INVAL: 2598 return (dgettext(TEXT_DOMAIN, "Invalid argument")); 2599 case Z_ACCES: 2600 return (dgettext(TEXT_DOMAIN, "Permission denied")); 2601 case Z_TOO_BIG: 2602 return (dgettext(TEXT_DOMAIN, "Argument list too long")); 2603 case Z_MISC_FS: 2604 return (dgettext(TEXT_DOMAIN, 2605 "Miscellaneous file system error")); 2606 case Z_NO_ZONE: 2607 return (dgettext(TEXT_DOMAIN, "No such zone configured")); 2608 case Z_NO_RESOURCE_TYPE: 2609 return (dgettext(TEXT_DOMAIN, "No such resource type")); 2610 case Z_NO_RESOURCE_ID: 2611 return (dgettext(TEXT_DOMAIN, "No such resource with that id")); 2612 case Z_NO_PROPERTY_TYPE: 2613 return (dgettext(TEXT_DOMAIN, "No such property type")); 2614 case Z_NO_PROPERTY_ID: 2615 return (dgettext(TEXT_DOMAIN, "No such property with that id")); 2616 case Z_BAD_ZONE_STATE: 2617 return (dgettext(TEXT_DOMAIN, 2618 "Zone state is invalid for the requested operation")); 2619 case Z_INVALID_DOCUMENT: 2620 return (dgettext(TEXT_DOMAIN, "Invalid document")); 2621 case Z_NAME_IN_USE: 2622 return (dgettext(TEXT_DOMAIN, "Zone name already in use")); 2623 case Z_NO_SUCH_ID: 2624 return (dgettext(TEXT_DOMAIN, "No such zone ID")); 2625 case Z_UPDATING_INDEX: 2626 return (dgettext(TEXT_DOMAIN, "Problem updating index file")); 2627 case Z_LOCKING_FILE: 2628 return (dgettext(TEXT_DOMAIN, "Locking index file")); 2629 case Z_UNLOCKING_FILE: 2630 return (dgettext(TEXT_DOMAIN, "Unlocking index file")); 2631 case Z_INSUFFICIENT_SPEC: 2632 return (dgettext(TEXT_DOMAIN, "Insufficient specification")); 2633 case Z_RESOLVED_PATH: 2634 return (dgettext(TEXT_DOMAIN, "Resolved path mismatch")); 2635 case Z_IPV6_ADDR_PREFIX_LEN: 2636 return (dgettext(TEXT_DOMAIN, 2637 "IPv6 address missing required prefix length")); 2638 case Z_BOGUS_ADDRESS: 2639 return (dgettext(TEXT_DOMAIN, 2640 "Neither an IPv4 nor an IPv6 address nor a host name")); 2641 default: 2642 return (dgettext(TEXT_DOMAIN, "Unknown error")); 2643 } 2644 } 2645 2646 /* 2647 * Note that the zonecfg_setXent() and zonecfg_endXent() calls are all the 2648 * same, as they just turn around and call zonecfg_setent() / zonecfg_endent(). 2649 */ 2650 2651 static int 2652 zonecfg_setent(zone_dochandle_t handle) 2653 { 2654 xmlNodePtr cur; 2655 int err; 2656 2657 if (handle == NULL) 2658 return (Z_INVAL); 2659 2660 if ((err = operation_prep(handle)) != Z_OK) { 2661 handle->zone_dh_cur = NULL; 2662 return (err); 2663 } 2664 cur = handle->zone_dh_cur; 2665 cur = cur->xmlChildrenNode; 2666 handle->zone_dh_cur = cur; 2667 return (Z_OK); 2668 } 2669 2670 static int 2671 zonecfg_endent(zone_dochandle_t handle) 2672 { 2673 if (handle == NULL) 2674 return (Z_INVAL); 2675 2676 handle->zone_dh_cur = handle->zone_dh_top; 2677 return (Z_OK); 2678 } 2679 2680 int 2681 zonecfg_setfsent(zone_dochandle_t handle) 2682 { 2683 return (zonecfg_setent(handle)); 2684 } 2685 2686 int 2687 zonecfg_getfsent(zone_dochandle_t handle, struct zone_fstab *tabptr) 2688 { 2689 xmlNodePtr cur, options; 2690 char options_str[MAX_MNTOPT_STR]; 2691 int err; 2692 2693 if (handle == NULL) 2694 return (Z_INVAL); 2695 2696 if ((cur = handle->zone_dh_cur) == NULL) 2697 return (Z_NO_ENTRY); 2698 2699 for (; cur != NULL; cur = cur->next) 2700 if (!xmlStrcmp(cur->name, DTD_ELEM_FS)) 2701 break; 2702 if (cur == NULL) { 2703 handle->zone_dh_cur = handle->zone_dh_top; 2704 return (Z_NO_ENTRY); 2705 } 2706 2707 if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special, 2708 sizeof (tabptr->zone_fs_special))) != Z_OK) { 2709 handle->zone_dh_cur = handle->zone_dh_top; 2710 return (err); 2711 } 2712 2713 if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw, 2714 sizeof (tabptr->zone_fs_raw))) != Z_OK) { 2715 handle->zone_dh_cur = handle->zone_dh_top; 2716 return (err); 2717 } 2718 2719 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 2720 sizeof (tabptr->zone_fs_dir))) != Z_OK) { 2721 handle->zone_dh_cur = handle->zone_dh_top; 2722 return (err); 2723 } 2724 2725 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type, 2726 sizeof (tabptr->zone_fs_type))) != Z_OK) { 2727 handle->zone_dh_cur = handle->zone_dh_top; 2728 return (err); 2729 } 2730 2731 /* OK for options to be NULL */ 2732 tabptr->zone_fs_options = NULL; 2733 for (options = cur->xmlChildrenNode; options != NULL; 2734 options = options->next) { 2735 if (fetchprop(options, DTD_ATTR_NAME, options_str, 2736 sizeof (options_str)) != Z_OK) 2737 break; 2738 if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK) 2739 break; 2740 } 2741 2742 handle->zone_dh_cur = cur->next; 2743 return (Z_OK); 2744 } 2745 2746 int 2747 zonecfg_endfsent(zone_dochandle_t handle) 2748 { 2749 return (zonecfg_endent(handle)); 2750 } 2751 2752 int 2753 zonecfg_setipdent(zone_dochandle_t handle) 2754 { 2755 return (zonecfg_setent(handle)); 2756 } 2757 2758 int 2759 zonecfg_getipdent(zone_dochandle_t handle, struct zone_fstab *tabptr) 2760 { 2761 xmlNodePtr cur; 2762 int err; 2763 2764 if (handle == NULL) 2765 return (Z_INVAL); 2766 2767 if ((cur = handle->zone_dh_cur) == NULL) 2768 return (Z_NO_ENTRY); 2769 2770 for (; cur != NULL; cur = cur->next) 2771 if (!xmlStrcmp(cur->name, DTD_ELEM_IPD)) 2772 break; 2773 if (cur == NULL) { 2774 handle->zone_dh_cur = handle->zone_dh_top; 2775 return (Z_NO_ENTRY); 2776 } 2777 2778 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 2779 sizeof (tabptr->zone_fs_dir))) != Z_OK) { 2780 handle->zone_dh_cur = handle->zone_dh_top; 2781 return (err); 2782 } 2783 2784 handle->zone_dh_cur = cur->next; 2785 return (Z_OK); 2786 } 2787 2788 int 2789 zonecfg_endipdent(zone_dochandle_t handle) 2790 { 2791 return (zonecfg_endent(handle)); 2792 } 2793 2794 int 2795 zonecfg_setnwifent(zone_dochandle_t handle) 2796 { 2797 return (zonecfg_setent(handle)); 2798 } 2799 2800 int 2801 zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2802 { 2803 xmlNodePtr cur; 2804 int err; 2805 2806 if (handle == NULL) 2807 return (Z_INVAL); 2808 2809 if ((cur = handle->zone_dh_cur) == NULL) 2810 return (Z_NO_ENTRY); 2811 2812 for (; cur != NULL; cur = cur->next) 2813 if (!xmlStrcmp(cur->name, DTD_ELEM_NET)) 2814 break; 2815 if (cur == NULL) { 2816 handle->zone_dh_cur = handle->zone_dh_top; 2817 return (Z_NO_ENTRY); 2818 } 2819 2820 if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address, 2821 sizeof (tabptr->zone_nwif_address))) != Z_OK) { 2822 handle->zone_dh_cur = handle->zone_dh_top; 2823 return (err); 2824 } 2825 2826 if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical, 2827 sizeof (tabptr->zone_nwif_physical))) != Z_OK) { 2828 handle->zone_dh_cur = handle->zone_dh_top; 2829 return (err); 2830 } 2831 2832 handle->zone_dh_cur = cur->next; 2833 return (Z_OK); 2834 } 2835 2836 int 2837 zonecfg_endnwifent(zone_dochandle_t handle) 2838 { 2839 return (zonecfg_endent(handle)); 2840 } 2841 2842 int 2843 zonecfg_setdevent(zone_dochandle_t handle) 2844 { 2845 return (zonecfg_setent(handle)); 2846 } 2847 2848 int 2849 zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr) 2850 { 2851 xmlNodePtr cur; 2852 int err; 2853 2854 if (handle == NULL) 2855 return (Z_INVAL); 2856 2857 if ((cur = handle->zone_dh_cur) == NULL) 2858 return (Z_NO_ENTRY); 2859 2860 for (; cur != NULL; cur = cur->next) 2861 if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 2862 break; 2863 if (cur == NULL) { 2864 handle->zone_dh_cur = handle->zone_dh_top; 2865 return (Z_NO_ENTRY); 2866 } 2867 2868 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match, 2869 sizeof (tabptr->zone_dev_match))) != Z_OK) { 2870 handle->zone_dh_cur = handle->zone_dh_top; 2871 return (err); 2872 } 2873 2874 handle->zone_dh_cur = cur->next; 2875 return (Z_OK); 2876 } 2877 2878 int 2879 zonecfg_enddevent(zone_dochandle_t handle) 2880 { 2881 return (zonecfg_endent(handle)); 2882 } 2883 2884 int 2885 zonecfg_setrctlent(zone_dochandle_t handle) 2886 { 2887 return (zonecfg_setent(handle)); 2888 } 2889 2890 int 2891 zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr) 2892 { 2893 xmlNodePtr cur, val; 2894 struct zone_rctlvaltab *valptr; 2895 int err; 2896 2897 if (handle == NULL) 2898 return (Z_INVAL); 2899 2900 if ((cur = handle->zone_dh_cur) == NULL) 2901 return (Z_NO_ENTRY); 2902 2903 for (; cur != NULL; cur = cur->next) 2904 if (!xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 2905 break; 2906 if (cur == NULL) { 2907 handle->zone_dh_cur = handle->zone_dh_top; 2908 return (Z_NO_ENTRY); 2909 } 2910 2911 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_rctl_name, 2912 sizeof (tabptr->zone_rctl_name))) != Z_OK) { 2913 handle->zone_dh_cur = handle->zone_dh_top; 2914 return (err); 2915 } 2916 2917 tabptr->zone_rctl_valptr = NULL; 2918 for (val = cur->xmlChildrenNode; val != NULL; val = val->next) { 2919 valptr = (struct zone_rctlvaltab *)malloc( 2920 sizeof (struct zone_rctlvaltab)); 2921 if (valptr == NULL) 2922 return (Z_NOMEM); 2923 if (fetchprop(val, DTD_ATTR_PRIV, valptr->zone_rctlval_priv, 2924 sizeof (valptr->zone_rctlval_priv)) != Z_OK) 2925 break; 2926 if (fetchprop(val, DTD_ATTR_LIMIT, valptr->zone_rctlval_limit, 2927 sizeof (valptr->zone_rctlval_limit)) != Z_OK) 2928 break; 2929 if (fetchprop(val, DTD_ATTR_ACTION, valptr->zone_rctlval_action, 2930 sizeof (valptr->zone_rctlval_action)) != Z_OK) 2931 break; 2932 if (zonecfg_add_rctl_value(tabptr, valptr) != Z_OK) 2933 break; 2934 } 2935 2936 handle->zone_dh_cur = cur->next; 2937 return (Z_OK); 2938 } 2939 2940 int 2941 zonecfg_endrctlent(zone_dochandle_t handle) 2942 { 2943 return (zonecfg_endent(handle)); 2944 } 2945 2946 int 2947 zonecfg_setattrent(zone_dochandle_t handle) 2948 { 2949 return (zonecfg_setent(handle)); 2950 } 2951 2952 int 2953 zonecfg_getattrent(zone_dochandle_t handle, struct zone_attrtab *tabptr) 2954 { 2955 xmlNodePtr cur; 2956 int err; 2957 2958 if (handle == NULL) 2959 return (Z_INVAL); 2960 2961 if ((cur = handle->zone_dh_cur) == NULL) 2962 return (Z_NO_ENTRY); 2963 2964 for (; cur != NULL; cur = cur->next) 2965 if (!xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 2966 break; 2967 if (cur == NULL) { 2968 handle->zone_dh_cur = handle->zone_dh_top; 2969 return (Z_NO_ENTRY); 2970 } 2971 2972 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name, 2973 sizeof (tabptr->zone_attr_name))) != Z_OK) { 2974 handle->zone_dh_cur = handle->zone_dh_top; 2975 return (err); 2976 } 2977 2978 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type, 2979 sizeof (tabptr->zone_attr_type))) != Z_OK) { 2980 handle->zone_dh_cur = handle->zone_dh_top; 2981 return (err); 2982 } 2983 2984 if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value, 2985 sizeof (tabptr->zone_attr_value))) != Z_OK) { 2986 handle->zone_dh_cur = handle->zone_dh_top; 2987 return (err); 2988 } 2989 2990 handle->zone_dh_cur = cur->next; 2991 return (Z_OK); 2992 } 2993 2994 int 2995 zonecfg_endattrent(zone_dochandle_t handle) 2996 { 2997 return (zonecfg_endent(handle)); 2998 } 2999 3000 /* This will ultimately be configurable. */ 3001 static const char *priv_list[] = { 3002 PRIV_FILE_CHOWN, 3003 PRIV_FILE_CHOWN_SELF, 3004 PRIV_FILE_DAC_EXECUTE, 3005 PRIV_FILE_DAC_READ, 3006 PRIV_FILE_DAC_SEARCH, 3007 PRIV_FILE_DAC_WRITE, 3008 PRIV_FILE_OWNER, 3009 PRIV_FILE_SETID, 3010 PRIV_IPC_DAC_READ, 3011 PRIV_IPC_DAC_WRITE, 3012 PRIV_IPC_OWNER, 3013 PRIV_NET_ICMPACCESS, 3014 PRIV_NET_PRIVADDR, 3015 PRIV_PROC_CHROOT, 3016 PRIV_SYS_AUDIT, 3017 PRIV_PROC_AUDIT, 3018 PRIV_PROC_OWNER, 3019 PRIV_PROC_SETID, 3020 PRIV_PROC_TASKID, 3021 PRIV_SYS_ACCT, 3022 PRIV_SYS_ADMIN, 3023 PRIV_SYS_MOUNT, 3024 PRIV_SYS_NFS, 3025 PRIV_SYS_RESOURCE, 3026 PRIV_CONTRACT_EVENT, 3027 PRIV_CONTRACT_OBSERVER, 3028 NULL 3029 }; 3030 3031 int 3032 zonecfg_get_privset(priv_set_t *privs) 3033 { 3034 const char **strp; 3035 priv_set_t *basic = priv_str_to_set("basic", ",", NULL); 3036 3037 if (basic == NULL) 3038 return (Z_INVAL); 3039 3040 priv_union(basic, privs); 3041 priv_freeset(basic); 3042 3043 for (strp = priv_list; *strp != NULL; strp++) { 3044 if (priv_addset(privs, *strp) != 0) { 3045 return (Z_INVAL); 3046 } 3047 } 3048 return (Z_OK); 3049 } 3050 3051 int 3052 zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz) 3053 { 3054 zone_dochandle_t handle; 3055 boolean_t found = B_FALSE; 3056 struct zoneent *ze; 3057 FILE *cookie; 3058 int err; 3059 char *cp; 3060 3061 if (zone_name == NULL) 3062 return (Z_INVAL); 3063 3064 (void) strlcpy(zonepath, zonecfg_root, rp_sz); 3065 cp = zonepath + strlen(zonepath); 3066 while (cp > zonepath && cp[-1] == '/') 3067 *--cp = '\0'; 3068 3069 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) { 3070 if (zonepath[0] == '\0') 3071 (void) strlcpy(zonepath, "/", rp_sz); 3072 return (Z_OK); 3073 } 3074 3075 /* 3076 * First check the index file. Because older versions did not have 3077 * a copy of the zone path, allow for it to be zero length, in which 3078 * case we ignore this result and fall back to the XML files. 3079 */ 3080 cookie = setzoneent(); 3081 while ((ze = getzoneent_private(cookie)) != NULL) { 3082 if (strcmp(ze->zone_name, zone_name) == 0) { 3083 found = B_TRUE; 3084 if (ze->zone_path[0] != '\0') 3085 (void) strlcpy(cp, ze->zone_path, 3086 rp_sz - (cp - zonepath)); 3087 } 3088 free(ze); 3089 if (found) 3090 break; 3091 } 3092 endzoneent(cookie); 3093 if (found && *cp != '\0') 3094 return (Z_OK); 3095 3096 /* Fall back to the XML files. */ 3097 if ((handle = zonecfg_init_handle()) == NULL) 3098 return (Z_NOMEM); 3099 3100 /* 3101 * Check the snapshot first: if a zone is running, its zonepath 3102 * may have changed. 3103 */ 3104 if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) { 3105 if ((err = zonecfg_get_handle(zone_name, handle)) != Z_OK) 3106 return (err); 3107 } 3108 err = zonecfg_get_zonepath(handle, zonepath, rp_sz); 3109 zonecfg_fini_handle(handle); 3110 return (err); 3111 } 3112 3113 int 3114 zone_get_rootpath(char *zone_name, char *rootpath, size_t rp_sz) 3115 { 3116 int err; 3117 3118 /* This function makes sense for non-global zones only. */ 3119 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) 3120 return (Z_BOGUS_ZONE_NAME); 3121 if ((err = zone_get_zonepath(zone_name, rootpath, rp_sz)) != Z_OK) 3122 return (err); 3123 if (strlcat(rootpath, "/root", rp_sz) >= rp_sz) 3124 return (Z_TOO_BIG); 3125 return (Z_OK); 3126 } 3127 3128 static zone_state_t 3129 kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state) 3130 { 3131 char zoneroot[MAXPATHLEN]; 3132 size_t zlen; 3133 3134 assert(kernel_state <= ZONE_MAX_STATE); 3135 switch (kernel_state) { 3136 case ZONE_IS_UNINITIALIZED: 3137 return (ZONE_STATE_READY); 3138 case ZONE_IS_READY: 3139 /* 3140 * If the zone's root is mounted on $ZONEPATH/lu, then 3141 * it's a mounted scratch zone. 3142 */ 3143 if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot, 3144 sizeof (zoneroot)) >= 0) { 3145 zlen = strlen(zoneroot); 3146 if (zlen > 3 && 3147 strcmp(zoneroot + zlen - 3, "/lu") == 0) 3148 return (ZONE_STATE_MOUNTED); 3149 } 3150 return (ZONE_STATE_READY); 3151 case ZONE_IS_BOOTING: 3152 case ZONE_IS_RUNNING: 3153 return (ZONE_STATE_RUNNING); 3154 case ZONE_IS_SHUTTING_DOWN: 3155 case ZONE_IS_EMPTY: 3156 return (ZONE_STATE_SHUTTING_DOWN); 3157 case ZONE_IS_DOWN: 3158 case ZONE_IS_DYING: 3159 case ZONE_IS_DEAD: 3160 default: 3161 return (ZONE_STATE_DOWN); 3162 } 3163 /* NOTREACHED */ 3164 } 3165 3166 int 3167 zone_get_state(char *zone_name, zone_state_t *state_num) 3168 { 3169 zone_status_t status; 3170 zoneid_t zone_id; 3171 struct zoneent *ze; 3172 boolean_t found = B_FALSE; 3173 FILE *cookie; 3174 char kernzone[ZONENAME_MAX]; 3175 FILE *fp; 3176 3177 if (zone_name == NULL) 3178 return (Z_INVAL); 3179 3180 /* 3181 * If we're looking at an alternate root, then we need to query the 3182 * kernel using the scratch zone name. 3183 */ 3184 zone_id = -1; 3185 if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) { 3186 if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) { 3187 if (zonecfg_find_scratch(fp, zone_name, zonecfg_root, 3188 kernzone, sizeof (kernzone)) == 0) 3189 zone_id = getzoneidbyname(kernzone); 3190 zonecfg_close_scratch(fp); 3191 } 3192 } else { 3193 zone_id = getzoneidbyname(zone_name); 3194 } 3195 3196 /* check to see if zone is running */ 3197 if (zone_id != -1 && 3198 zone_getattr(zone_id, ZONE_ATTR_STATUS, &status, 3199 sizeof (status)) >= 0) { 3200 *state_num = kernel_state_to_user_state(zone_id, status); 3201 return (Z_OK); 3202 } 3203 3204 cookie = setzoneent(); 3205 while ((ze = getzoneent_private(cookie)) != NULL) { 3206 if (strcmp(ze->zone_name, zone_name) == 0) { 3207 found = B_TRUE; 3208 *state_num = ze->zone_state; 3209 } 3210 free(ze); 3211 if (found) 3212 break; 3213 } 3214 endzoneent(cookie); 3215 return ((found) ? Z_OK : Z_NO_ZONE); 3216 } 3217 3218 int 3219 zone_set_state(char *zone, zone_state_t state) 3220 { 3221 struct zoneent ze; 3222 3223 if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED && 3224 state != ZONE_STATE_INCOMPLETE) 3225 return (Z_INVAL); 3226 3227 bzero(&ze, sizeof (ze)); 3228 (void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name)); 3229 ze.zone_state = state; 3230 (void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path)); 3231 return (putzoneent(&ze, PZE_MODIFY)); 3232 } 3233 3234 /* 3235 * Get id (if any) for specified zone. There are four possible outcomes: 3236 * - If the string corresponds to the numeric id of an active (booted) 3237 * zone, sets *zip to the zone id and returns 0. 3238 * - If the string corresponds to the name of an active (booted) zone, 3239 * sets *zip to the zone id and returns 0. 3240 * - If the string is a name in the configuration but is not booted, 3241 * sets *zip to ZONE_ID_UNDEFINED and returns 0. 3242 * - Otherwise, leaves *zip unchanged and returns -1. 3243 * 3244 * This function acts as an auxiliary filter on the function of the same 3245 * name in libc; the linker binds to this version if libzonecfg exists, 3246 * and the libc version if it doesn't. Any changes to this version of 3247 * the function should probably be reflected in the libc version as well. 3248 */ 3249 int 3250 zone_get_id(const char *str, zoneid_t *zip) 3251 { 3252 zone_dochandle_t hdl; 3253 zoneid_t zoneid; 3254 char *cp; 3255 int err; 3256 3257 /* first try looking for active zone by id */ 3258 errno = 0; 3259 zoneid = (zoneid_t)strtol(str, &cp, 0); 3260 if (errno == 0 && cp != str && *cp == '\0' && 3261 getzonenamebyid(zoneid, NULL, 0) != -1) { 3262 *zip = zoneid; 3263 return (0); 3264 } 3265 3266 /* then look for active zone by name */ 3267 if ((zoneid = getzoneidbyname(str)) != -1) { 3268 *zip = zoneid; 3269 return (0); 3270 } 3271 3272 /* if in global zone, try looking up name in configuration database */ 3273 if (getzoneid() != GLOBAL_ZONEID || 3274 (hdl = zonecfg_init_handle()) == NULL) 3275 return (-1); 3276 3277 if (zonecfg_get_handle(str, hdl) == Z_OK) { 3278 /* zone exists but isn't active */ 3279 *zip = ZONE_ID_UNDEFINED; 3280 err = 0; 3281 } else { 3282 err = -1; 3283 } 3284 3285 zonecfg_fini_handle(hdl); 3286 return (err); 3287 } 3288 3289 char * 3290 zone_state_str(zone_state_t state_num) 3291 { 3292 switch (state_num) { 3293 case ZONE_STATE_CONFIGURED: 3294 return (ZONE_STATE_STR_CONFIGURED); 3295 case ZONE_STATE_INCOMPLETE: 3296 return (ZONE_STATE_STR_INCOMPLETE); 3297 case ZONE_STATE_INSTALLED: 3298 return (ZONE_STATE_STR_INSTALLED); 3299 case ZONE_STATE_READY: 3300 return (ZONE_STATE_STR_READY); 3301 case ZONE_STATE_MOUNTED: 3302 return (ZONE_STATE_STR_MOUNTED); 3303 case ZONE_STATE_RUNNING: 3304 return (ZONE_STATE_STR_RUNNING); 3305 case ZONE_STATE_SHUTTING_DOWN: 3306 return (ZONE_STATE_STR_SHUTTING_DOWN); 3307 case ZONE_STATE_DOWN: 3308 return (ZONE_STATE_STR_DOWN); 3309 default: 3310 return ("unknown"); 3311 } 3312 } 3313 3314 /* 3315 * Given a UUID value, find an associated zone name. This is intended to be 3316 * used by callers who set up some 'default' name (corresponding to the 3317 * expected name for the zone) in the zonename buffer, and thus the function 3318 * doesn't touch this buffer on failure. 3319 */ 3320 int 3321 zonecfg_get_name_by_uuid(const uuid_t uuid, char *zonename, size_t namelen) 3322 { 3323 FILE *fp; 3324 struct zoneent *ze; 3325 3326 /* 3327 * A small amount of subterfuge via casts is necessary here because 3328 * libuuid doesn't use const correctly, but we don't want to export 3329 * this brokenness to our clients. 3330 */ 3331 if (uuid_is_null(*(uuid_t *)&uuid)) 3332 return (Z_NO_ZONE); 3333 if ((fp = setzoneent()) == NULL) 3334 return (Z_NO_ZONE); 3335 while ((ze = getzoneent_private(fp)) != NULL) { 3336 if (uuid_compare(*(uuid_t *)&uuid, ze->zone_uuid) == 0) 3337 break; 3338 free(ze); 3339 } 3340 endzoneent(fp); 3341 if (ze != NULL) { 3342 (void) strlcpy(zonename, ze->zone_name, namelen); 3343 free(ze); 3344 return (Z_OK); 3345 } else { 3346 return (Z_NO_ZONE); 3347 } 3348 } 3349 3350 /* 3351 * Given a zone name, get its UUID. Returns a "NULL" UUID value if the zone 3352 * exists but the file doesn't have a value set yet. Returns an error if the 3353 * zone cannot be located. 3354 */ 3355 int 3356 zonecfg_get_uuid(const char *zonename, uuid_t uuid) 3357 { 3358 FILE *fp; 3359 struct zoneent *ze; 3360 3361 if ((fp = setzoneent()) == NULL) 3362 return (Z_NO_ZONE); 3363 while ((ze = getzoneent_private(fp)) != NULL) { 3364 if (strcmp(ze->zone_name, zonename) == 0) 3365 break; 3366 free(ze); 3367 } 3368 endzoneent(fp); 3369 if (ze != NULL) { 3370 uuid_copy(uuid, ze->zone_uuid); 3371 free(ze); 3372 return (Z_OK); 3373 } else { 3374 return (Z_NO_ZONE); 3375 } 3376 } 3377 3378 /* 3379 * File-system convenience functions. 3380 */ 3381 boolean_t 3382 zonecfg_valid_fs_type(const char *type) 3383 { 3384 /* 3385 * We already know which FS types don't work. 3386 */ 3387 if (strcmp(type, "proc") == 0 || 3388 strcmp(type, "mntfs") == 0 || 3389 strcmp(type, "autofs") == 0 || 3390 strncmp(type, "nfs", sizeof ("nfs") - 1) == 0 || 3391 strcmp(type, "cachefs") == 0) 3392 return (B_FALSE); 3393 /* 3394 * The caller may do more detailed verification to make sure other 3395 * aspects of this filesystem type make sense. 3396 */ 3397 return (B_TRUE); 3398 } 3399 3400 /* 3401 * Generally uninteresting rctl convenience functions. 3402 */ 3403 3404 int 3405 zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval, 3406 rctlblk_t *rctlblk) 3407 { 3408 unsigned long long ull; 3409 char *endp; 3410 rctl_priv_t priv; 3411 rctl_qty_t limit; 3412 uint_t action; 3413 3414 /* Get the privilege */ 3415 if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) { 3416 priv = RCPRIV_BASIC; 3417 } else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) { 3418 priv = RCPRIV_PRIVILEGED; 3419 } else { 3420 /* Invalid privilege */ 3421 return (Z_INVAL); 3422 } 3423 3424 /* deal with negative input; strtoull(3c) doesn't do what we want */ 3425 if (rctlval->zone_rctlval_limit[0] == '-') 3426 return (Z_INVAL); 3427 /* Get the limit */ 3428 errno = 0; 3429 ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0); 3430 if (errno != 0 || *endp != '\0') { 3431 /* parse failed */ 3432 return (Z_INVAL); 3433 } 3434 limit = (rctl_qty_t)ull; 3435 3436 /* Get the action */ 3437 if (strcmp(rctlval->zone_rctlval_action, "none") == 0) { 3438 action = RCTL_LOCAL_NOACTION; 3439 } else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) { 3440 action = RCTL_LOCAL_SIGNAL; 3441 } else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) { 3442 action = RCTL_LOCAL_DENY; 3443 } else { 3444 /* Invalid Action */ 3445 return (Z_INVAL); 3446 } 3447 rctlblk_set_local_action(rctlblk, action, 0); 3448 rctlblk_set_privilege(rctlblk, priv); 3449 rctlblk_set_value(rctlblk, limit); 3450 return (Z_OK); 3451 } 3452 3453 static int 3454 rctl_check(const char *rctlname, void *arg) 3455 { 3456 const char *attrname = arg; 3457 3458 /* 3459 * Returning 1 here is our signal to zonecfg_is_rctl() that it is 3460 * indeed an rctl name recognized by the system. 3461 */ 3462 return (strcmp(rctlname, attrname) == 0 ? 1 : 0); 3463 } 3464 3465 boolean_t 3466 zonecfg_is_rctl(const char *name) 3467 { 3468 return (rctl_walk(rctl_check, (void *)name) == 1); 3469 } 3470 3471 boolean_t 3472 zonecfg_valid_rctlname(const char *name) 3473 { 3474 const char *c; 3475 3476 if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0) 3477 return (B_FALSE); 3478 if (strlen(name) == sizeof ("zone.") - 1) 3479 return (B_FALSE); 3480 for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) { 3481 if (!isalpha(*c) && *c != '-') 3482 return (B_FALSE); 3483 } 3484 return (B_TRUE); 3485 } 3486 3487 boolean_t 3488 zonecfg_valid_rctlblk(const rctlblk_t *rctlblk) 3489 { 3490 rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk); 3491 uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL); 3492 3493 if (priv != RCPRIV_PRIVILEGED) 3494 return (B_FALSE); 3495 if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY) 3496 return (B_FALSE); 3497 return (B_TRUE); 3498 } 3499 3500 boolean_t 3501 zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk) 3502 { 3503 rctlblk_t *current, *next; 3504 rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk); 3505 uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL); 3506 uint_t global_flags; 3507 3508 if (!zonecfg_valid_rctlblk(rctlblk)) 3509 return (B_FALSE); 3510 if (!zonecfg_valid_rctlname(name)) 3511 return (B_FALSE); 3512 3513 current = alloca(rctlblk_size()); 3514 if (getrctl(name, NULL, current, RCTL_FIRST) != 0) 3515 return (B_TRUE); /* not an rctl on this system */ 3516 /* 3517 * Make sure the proposed value isn't greater than the current system 3518 * value. 3519 */ 3520 next = alloca(rctlblk_size()); 3521 while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) { 3522 rctlblk_t *tmp; 3523 3524 if (getrctl(name, current, next, RCTL_NEXT) != 0) 3525 return (B_FALSE); /* shouldn't happen */ 3526 tmp = current; 3527 current = next; 3528 next = tmp; 3529 } 3530 if (limit > rctlblk_get_value(current)) 3531 return (B_FALSE); 3532 3533 /* 3534 * Make sure the proposed action is allowed. 3535 */ 3536 global_flags = rctlblk_get_global_flags(current); 3537 if ((global_flags & RCTL_GLOBAL_DENY_NEVER) && 3538 action == RCTL_LOCAL_DENY) 3539 return (B_FALSE); 3540 if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) && 3541 action == RCTL_LOCAL_NOACTION) 3542 return (B_FALSE); 3543 3544 return (B_TRUE); 3545 } 3546 3547 /* 3548 * There is always a race condition between reading the initial copy of 3549 * a zones state and its state changing. We address this by providing 3550 * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions. 3551 * When zonecfg_critical_enter is called, sets the state field to LOCKED 3552 * and aquires biglock. Biglock protects against other threads executing 3553 * critical_enter and the state field protects against state changes during 3554 * the critical period. 3555 * 3556 * If any state changes occur, zn_cb will set the failed field of the znotify 3557 * structure. This will cause the critical_exit function to re-lock the 3558 * channel and return an error. Since evsnts may be delayed, the critical_exit 3559 * function "flushes" the queue by putting an event on the queue and waiting for 3560 * zn_cb to notify critical_exit that it received the ping event. 3561 */ 3562 static const char * 3563 string_get_tok(const char *in, char delim, int num) 3564 { 3565 int i = 0; 3566 3567 for (; i < num; in++) { 3568 if (*in == delim) 3569 i++; 3570 if (*in == 0) 3571 return (NULL); 3572 } 3573 return (in); 3574 } 3575 3576 static boolean_t 3577 is_ping(sysevent_t *ev) 3578 { 3579 if (strcmp(sysevent_get_subclass_name(ev), 3580 ZONE_EVENT_PING_SUBCLASS) == 0) { 3581 return (B_TRUE); 3582 } else { 3583 return (B_FALSE); 3584 } 3585 } 3586 3587 static boolean_t 3588 is_my_ping(sysevent_t *ev) 3589 { 3590 const char *sender; 3591 char mypid[sizeof (pid_t) * 3 + 1]; 3592 3593 (void) snprintf(mypid, sizeof (mypid), "%i", getpid()); 3594 sender = string_get_tok(sysevent_get_pub(ev), ':', 3); 3595 if (sender == NULL) 3596 return (B_FALSE); 3597 if (strcmp(sender, mypid) != 0) 3598 return (B_FALSE); 3599 return (B_TRUE); 3600 } 3601 3602 static int 3603 do_callback(struct znotify *zevtchan, sysevent_t *ev) 3604 { 3605 nvlist_t *l; 3606 int zid; 3607 char *zonename; 3608 char *newstate; 3609 char *oldstate; 3610 int ret; 3611 hrtime_t when; 3612 3613 if (strcmp(sysevent_get_subclass_name(ev), 3614 ZONE_EVENT_STATUS_SUBCLASS) == 0) { 3615 3616 if (sysevent_get_attr_list(ev, &l) != 0) { 3617 if (errno == ENOMEM) { 3618 zevtchan->zn_failure_count++; 3619 return (EAGAIN); 3620 } 3621 return (0); 3622 } 3623 ret = 0; 3624 3625 if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) && 3626 (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate) 3627 == 0) && 3628 (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate) 3629 == 0) && 3630 (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP, 3631 (uint64_t *)&when) == 0) && 3632 (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) { 3633 ret = zevtchan->zn_callback(zonename, zid, newstate, 3634 oldstate, when, zevtchan->zn_private); 3635 } 3636 3637 zevtchan->zn_failure_count = 0; 3638 nvlist_free(l); 3639 return (ret); 3640 } else { 3641 /* 3642 * We have received an event in an unknown subclass. Ignore. 3643 */ 3644 zevtchan->zn_failure_count = 0; 3645 return (0); 3646 } 3647 } 3648 3649 static int 3650 zn_cb(sysevent_t *ev, void *p) 3651 { 3652 struct znotify *zevtchan = p; 3653 int error; 3654 3655 (void) pthread_mutex_lock(&(zevtchan->zn_mutex)); 3656 3657 if (is_ping(ev) && !is_my_ping(ev)) { 3658 (void) pthread_mutex_unlock((&zevtchan->zn_mutex)); 3659 return (0); 3660 } 3661 3662 if (zevtchan->zn_state == ZN_LOCKED) { 3663 assert(!is_ping(ev)); 3664 zevtchan->zn_failed = B_TRUE; 3665 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 3666 return (0); 3667 } 3668 3669 if (zevtchan->zn_state == ZN_PING_INFLIGHT) { 3670 if (is_ping(ev)) { 3671 zevtchan->zn_state = ZN_PING_RECEIVED; 3672 (void) pthread_cond_signal(&(zevtchan->zn_cond)); 3673 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 3674 return (0); 3675 } else { 3676 zevtchan->zn_failed = B_TRUE; 3677 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 3678 return (0); 3679 } 3680 } 3681 3682 if (zevtchan->zn_state == ZN_UNLOCKED) { 3683 3684 error = do_callback(zevtchan, ev); 3685 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 3686 /* 3687 * Every ENOMEM failure causes do_callback to increment 3688 * zn_failure_count and every success causes it to 3689 * set zn_failure_count to zero. If we got EAGAIN, 3690 * we will sleep for zn_failure_count seconds and return 3691 * EAGAIN to gpec to try again. 3692 * 3693 * After 55 seconds, or 10 try's we give up and drop the 3694 * event. 3695 */ 3696 if (error == EAGAIN) { 3697 if (zevtchan->zn_failure_count > ZONE_CB_RETRY_COUNT) { 3698 return (0); 3699 } 3700 (void) sleep(zevtchan->zn_failure_count); 3701 } 3702 return (error); 3703 } 3704 3705 if (zevtchan->zn_state == ZN_PING_RECEIVED) { 3706 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 3707 return (0); 3708 } 3709 3710 abort(); 3711 return (0); 3712 } 3713 3714 void 3715 zonecfg_notify_critical_enter(void *h) 3716 { 3717 struct znotify *zevtchan = h; 3718 3719 (void) pthread_mutex_lock(&(zevtchan->zn_bigmutex)); 3720 zevtchan->zn_state = ZN_LOCKED; 3721 } 3722 3723 int 3724 zonecfg_notify_critical_exit(void * h) 3725 { 3726 3727 struct znotify *zevtchan = h; 3728 3729 if (zevtchan->zn_state == ZN_UNLOCKED) 3730 return (0); 3731 3732 (void) pthread_mutex_lock(&(zevtchan->zn_mutex)); 3733 zevtchan->zn_state = ZN_PING_INFLIGHT; 3734 3735 sysevent_evc_publish(zevtchan->zn_eventchan, ZONE_EVENT_STATUS_CLASS, 3736 ZONE_EVENT_PING_SUBCLASS, ZONE_EVENT_PING_PUBLISHER, 3737 zevtchan->zn_subscriber_id, NULL, EVCH_SLEEP); 3738 3739 while (zevtchan->zn_state != ZN_PING_RECEIVED) { 3740 (void) pthread_cond_wait(&(zevtchan->zn_cond), 3741 &(zevtchan->zn_mutex)); 3742 } 3743 3744 if (zevtchan->zn_failed == B_TRUE) { 3745 zevtchan->zn_state = ZN_LOCKED; 3746 zevtchan->zn_failed = B_FALSE; 3747 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 3748 return (1); 3749 } 3750 3751 zevtchan->zn_state = ZN_UNLOCKED; 3752 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 3753 (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex)); 3754 return (0); 3755 } 3756 3757 void 3758 zonecfg_notify_critical_abort(void *h) 3759 { 3760 struct znotify *zevtchan = h; 3761 3762 zevtchan->zn_state = ZN_UNLOCKED; 3763 zevtchan->zn_failed = B_FALSE; 3764 /* 3765 * Don't do anything about zn_lock. If it is held, it could only be 3766 * held by zn_cb and it will be unlocked soon. 3767 */ 3768 (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex)); 3769 } 3770 3771 void * 3772 zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid, 3773 const char *newstate, const char *oldstate, hrtime_t when, void *p), 3774 void *p) 3775 { 3776 struct znotify *zevtchan; 3777 int i = 1; 3778 int r; 3779 3780 zevtchan = malloc(sizeof (struct znotify)); 3781 3782 if (zevtchan == NULL) 3783 return (NULL); 3784 3785 zevtchan->zn_private = p; 3786 zevtchan->zn_callback = func; 3787 zevtchan->zn_state = ZN_UNLOCKED; 3788 zevtchan->zn_failed = B_FALSE; 3789 3790 if (pthread_mutex_init(&(zevtchan->zn_mutex), NULL)) 3791 goto out3; 3792 if (pthread_cond_init(&(zevtchan->zn_cond), NULL)) { 3793 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex)); 3794 goto out3; 3795 } 3796 if (pthread_mutex_init(&(zevtchan->zn_bigmutex), NULL)) { 3797 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex)); 3798 (void) pthread_cond_destroy(&(zevtchan->zn_cond)); 3799 goto out3; 3800 } 3801 3802 if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &(zevtchan->zn_eventchan), 3803 0) != 0) 3804 goto out2; 3805 3806 do { 3807 /* 3808 * At 4 digits the subscriber ID gets too long and we have 3809 * no chance of successfully registering. 3810 */ 3811 if (i > 999) 3812 goto out1; 3813 3814 (void) sprintf(zevtchan->zn_subscriber_id, "zone_%li_%i", 3815 getpid() % 999999l, i); 3816 3817 r = sysevent_evc_subscribe(zevtchan->zn_eventchan, 3818 zevtchan->zn_subscriber_id, ZONE_EVENT_STATUS_CLASS, zn_cb, 3819 zevtchan, 0); 3820 3821 i++; 3822 3823 } while (r); 3824 3825 return (zevtchan); 3826 out1: 3827 sysevent_evc_unbind(zevtchan->zn_eventchan); 3828 out2: 3829 (void) pthread_mutex_destroy(&zevtchan->zn_mutex); 3830 (void) pthread_cond_destroy(&zevtchan->zn_cond); 3831 (void) pthread_mutex_destroy(&(zevtchan->zn_bigmutex)); 3832 out3: 3833 free(zevtchan); 3834 3835 return (NULL); 3836 } 3837 3838 void 3839 zonecfg_notify_unbind(void *handle) 3840 { 3841 3842 int ret; 3843 3844 sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan); 3845 /* 3846 * Check that all evc threads have gone away. This should be 3847 * enforced by sysevent_evc_unbind. 3848 */ 3849 ret = pthread_mutex_trylock(&((struct znotify *)handle)->zn_mutex); 3850 3851 if (ret) 3852 abort(); 3853 3854 (void) pthread_mutex_unlock(&((struct znotify *)handle)->zn_mutex); 3855 (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_mutex); 3856 (void) pthread_cond_destroy(&((struct znotify *)handle)->zn_cond); 3857 (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_bigmutex); 3858 3859 free(handle); 3860 } 3861 3862 static int 3863 zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr) 3864 { 3865 xmlNodePtr newnode, cur = handle->zone_dh_cur; 3866 int err; 3867 3868 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DATASET, NULL); 3869 if ((err = newprop(newnode, DTD_ATTR_NAME, 3870 tabptr->zone_dataset_name)) != Z_OK) 3871 return (err); 3872 return (Z_OK); 3873 } 3874 3875 int 3876 zonecfg_add_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 3877 { 3878 int err; 3879 3880 if (tabptr == NULL) 3881 return (Z_INVAL); 3882 3883 if ((err = operation_prep(handle)) != Z_OK) 3884 return (err); 3885 3886 if ((err = zonecfg_add_ds_core(handle, tabptr)) != Z_OK) 3887 return (err); 3888 3889 return (Z_OK); 3890 } 3891 3892 static int 3893 zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr) 3894 { 3895 xmlNodePtr cur = handle->zone_dh_cur; 3896 3897 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 3898 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 3899 continue; 3900 3901 if (match_prop(cur, DTD_ATTR_NAME, 3902 tabptr->zone_dataset_name)) { 3903 xmlUnlinkNode(cur); 3904 xmlFreeNode(cur); 3905 return (Z_OK); 3906 } 3907 } 3908 return (Z_NO_RESOURCE_ID); 3909 } 3910 3911 int 3912 zonecfg_delete_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 3913 { 3914 int err; 3915 3916 if (tabptr == NULL) 3917 return (Z_INVAL); 3918 3919 if ((err = operation_prep(handle)) != Z_OK) 3920 return (err); 3921 3922 if ((err = zonecfg_delete_ds_core(handle, tabptr)) != Z_OK) 3923 return (err); 3924 3925 return (Z_OK); 3926 } 3927 3928 int 3929 zonecfg_modify_ds( 3930 zone_dochandle_t handle, 3931 struct zone_dstab *oldtabptr, 3932 struct zone_dstab *newtabptr) 3933 { 3934 int err; 3935 3936 if (oldtabptr == NULL || newtabptr == NULL) 3937 return (Z_INVAL); 3938 3939 if ((err = operation_prep(handle)) != Z_OK) 3940 return (err); 3941 3942 if ((err = zonecfg_delete_ds_core(handle, oldtabptr)) != Z_OK) 3943 return (err); 3944 3945 if ((err = zonecfg_add_ds_core(handle, newtabptr)) != Z_OK) 3946 return (err); 3947 3948 return (Z_OK); 3949 } 3950 3951 int 3952 zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 3953 { 3954 xmlNodePtr cur, firstmatch; 3955 int err; 3956 char dataset[MAXNAMELEN]; 3957 3958 if (tabptr == NULL) 3959 return (Z_INVAL); 3960 3961 if ((err = operation_prep(handle)) != Z_OK) 3962 return (err); 3963 3964 cur = handle->zone_dh_cur; 3965 firstmatch = NULL; 3966 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 3967 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 3968 continue; 3969 if (strlen(tabptr->zone_dataset_name) > 0) { 3970 if ((fetchprop(cur, DTD_ATTR_NAME, dataset, 3971 sizeof (dataset)) == Z_OK) && 3972 (strcmp(tabptr->zone_dataset_name, 3973 dataset) == 0)) { 3974 if (firstmatch == NULL) 3975 firstmatch = cur; 3976 else 3977 return (Z_INSUFFICIENT_SPEC); 3978 } 3979 } 3980 } 3981 if (firstmatch == NULL) 3982 return (Z_NO_RESOURCE_ID); 3983 3984 cur = firstmatch; 3985 3986 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name, 3987 sizeof (tabptr->zone_dataset_name))) != Z_OK) 3988 return (err); 3989 3990 return (Z_OK); 3991 } 3992 3993 int 3994 zonecfg_setdsent(zone_dochandle_t handle) 3995 { 3996 return (zonecfg_setent(handle)); 3997 } 3998 3999 int 4000 zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr) 4001 { 4002 xmlNodePtr cur; 4003 int err; 4004 4005 if (handle == NULL) 4006 return (Z_INVAL); 4007 4008 if ((cur = handle->zone_dh_cur) == NULL) 4009 return (Z_NO_ENTRY); 4010 4011 for (; cur != NULL; cur = cur->next) 4012 if (!xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 4013 break; 4014 if (cur == NULL) { 4015 handle->zone_dh_cur = handle->zone_dh_top; 4016 return (Z_NO_ENTRY); 4017 } 4018 4019 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name, 4020 sizeof (tabptr->zone_dataset_name))) != Z_OK) { 4021 handle->zone_dh_cur = handle->zone_dh_top; 4022 return (err); 4023 } 4024 4025 handle->zone_dh_cur = cur->next; 4026 return (Z_OK); 4027 } 4028 4029 int 4030 zonecfg_enddsent(zone_dochandle_t handle) 4031 { 4032 return (zonecfg_endent(handle)); 4033 } 4034