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