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