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