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