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