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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <libsysevent.h> 27 #include <pthread.h> 28 #include <stdlib.h> 29 #include <errno.h> 30 #include <fnmatch.h> 31 #include <strings.h> 32 #include <unistd.h> 33 #include <assert.h> 34 #include <libgen.h> 35 #include <libintl.h> 36 #include <alloca.h> 37 #include <ctype.h> 38 #include <sys/acl.h> 39 #include <sys/stat.h> 40 #include <sys/brand.h> 41 #include <sys/mntio.h> 42 #include <sys/mnttab.h> 43 #include <sys/nvpair.h> 44 #include <sys/types.h> 45 #include <sys/sockio.h> 46 #include <sys/systeminfo.h> 47 #include <ftw.h> 48 #include <pool.h> 49 #include <libscf.h> 50 #include <libproc.h> 51 #include <sys/priocntl.h> 52 #include <libuutil.h> 53 #include <wait.h> 54 #include <bsm/adt.h> 55 #include <auth_attr.h> 56 #include <auth_list.h> 57 #include <secdb.h> 58 #include <user_attr.h> 59 #include <prof_attr.h> 60 61 #include <arpa/inet.h> 62 #include <netdb.h> 63 64 #include <libxml/xmlmemory.h> 65 #include <libxml/parser.h> 66 67 #include <libdevinfo.h> 68 #include <uuid/uuid.h> 69 #include <dirent.h> 70 #include <libbrand.h> 71 72 #include <libzonecfg.h> 73 #include "zonecfg_impl.h" 74 75 #define _PATH_TMPFILE "/zonecfg.XXXXXX" 76 #define ZONE_CB_RETRY_COUNT 10 77 #define ZONE_EVENT_PING_SUBCLASS "ping" 78 #define ZONE_EVENT_PING_PUBLISHER "solaris" 79 80 /* Hard-code the DTD element/attribute/entity names just once, here. */ 81 #define DTD_ELEM_ATTR (const xmlChar *) "attr" 82 #define DTD_ELEM_COMMENT (const xmlChar *) "comment" 83 #define DTD_ELEM_DEVICE (const xmlChar *) "device" 84 #define DTD_ELEM_FS (const xmlChar *) "filesystem" 85 #define DTD_ELEM_FSOPTION (const xmlChar *) "fsoption" 86 #define DTD_ELEM_IPD (const xmlChar *) "inherited-pkg-dir" 87 #define DTD_ELEM_NET (const xmlChar *) "network" 88 #define DTD_ELEM_RCTL (const xmlChar *) "rctl" 89 #define DTD_ELEM_RCTLVALUE (const xmlChar *) "rctl-value" 90 #define DTD_ELEM_ZONE (const xmlChar *) "zone" 91 #define DTD_ELEM_DATASET (const xmlChar *) "dataset" 92 #define DTD_ELEM_TMPPOOL (const xmlChar *) "tmp_pool" 93 #define DTD_ELEM_PSET (const xmlChar *) "pset" 94 #define DTD_ELEM_MCAP (const xmlChar *) "mcap" 95 #define DTD_ELEM_PACKAGE (const xmlChar *) "package" 96 #define DTD_ELEM_PATCH (const xmlChar *) "patch" 97 #define DTD_ELEM_OBSOLETES (const xmlChar *) "obsoletes" 98 #define DTD_ELEM_DEV_PERM (const xmlChar *) "dev-perm" 99 #define DTD_ELEM_ADMIN (const xmlChar *) "admin" 100 101 #define DTD_ATTR_ACTION (const xmlChar *) "action" 102 #define DTD_ATTR_ADDRESS (const xmlChar *) "address" 103 #define DTD_ATTR_AUTOBOOT (const xmlChar *) "autoboot" 104 #define DTD_ATTR_IPTYPE (const xmlChar *) "ip-type" 105 #define DTD_ATTR_DEFROUTER (const xmlChar *) "defrouter" 106 #define DTD_ATTR_DIR (const xmlChar *) "directory" 107 #define DTD_ATTR_LIMIT (const xmlChar *) "limit" 108 #define DTD_ATTR_LIMITPRIV (const xmlChar *) "limitpriv" 109 #define DTD_ATTR_BOOTARGS (const xmlChar *) "bootargs" 110 #define DTD_ATTR_SCHED (const xmlChar *) "scheduling-class" 111 #define DTD_ATTR_MATCH (const xmlChar *) "match" 112 #define DTD_ATTR_NAME (const xmlChar *) "name" 113 #define DTD_ATTR_PHYSICAL (const xmlChar *) "physical" 114 #define DTD_ATTR_POOL (const xmlChar *) "pool" 115 #define DTD_ATTR_PRIV (const xmlChar *) "priv" 116 #define DTD_ATTR_RAW (const xmlChar *) "raw" 117 #define DTD_ATTR_SPECIAL (const xmlChar *) "special" 118 #define DTD_ATTR_TYPE (const xmlChar *) "type" 119 #define DTD_ATTR_VALUE (const xmlChar *) "value" 120 #define DTD_ATTR_ZONEPATH (const xmlChar *) "zonepath" 121 #define DTD_ATTR_NCPU_MIN (const xmlChar *) "ncpu_min" 122 #define DTD_ATTR_NCPU_MAX (const xmlChar *) "ncpu_max" 123 #define DTD_ATTR_IMPORTANCE (const xmlChar *) "importance" 124 #define DTD_ATTR_PHYSCAP (const xmlChar *) "physcap" 125 #define DTD_ATTR_VERSION (const xmlChar *) "version" 126 #define DTD_ATTR_ID (const xmlChar *) "id" 127 #define DTD_ATTR_UID (const xmlChar *) "uid" 128 #define DTD_ATTR_GID (const xmlChar *) "gid" 129 #define DTD_ATTR_MODE (const xmlChar *) "mode" 130 #define DTD_ATTR_ACL (const xmlChar *) "acl" 131 #define DTD_ATTR_BRAND (const xmlChar *) "brand" 132 #define DTD_ATTR_HOSTID (const xmlChar *) "hostid" 133 #define DTD_ATTR_USER (const xmlChar *) "user" 134 #define DTD_ATTR_AUTHS (const xmlChar *) "auths" 135 #define DTD_ATTR_FS_ALLOWED (const xmlChar *) "fs-allowed" 136 137 #define DTD_ENTITY_BOOLEAN "boolean" 138 #define DTD_ENTITY_DEVPATH "devpath" 139 #define DTD_ENTITY_DRIVER "driver" 140 #define DTD_ENTITY_DRVMIN "drv_min" 141 #define DTD_ENTITY_FALSE "false" 142 #define DTD_ENTITY_INT "int" 143 #define DTD_ENTITY_STRING "string" 144 #define DTD_ENTITY_TRUE "true" 145 #define DTD_ENTITY_UINT "uint" 146 147 #define DTD_ENTITY_BOOL_LEN 6 /* "false" */ 148 149 #define ATTACH_FORCED "SUNWattached.xml" 150 151 #define TMP_POOL_NAME "SUNWtmp_%s" 152 #define MAX_TMP_POOL_NAME (ZONENAME_MAX + 9) 153 #define RCAP_SERVICE "system/rcap:default" 154 #define POOLD_SERVICE "system/pools/dynamic:default" 155 156 /* 157 * rctl alias definitions 158 * 159 * This holds the alias, the full rctl name, the default priv value, action 160 * and lower limit. The functions that handle rctl aliases step through 161 * this table, matching on the alias, and using the full values for setting 162 * the rctl entry as well the limit for validation. 163 */ 164 static struct alias { 165 char *shortname; 166 char *realname; 167 char *priv; 168 char *action; 169 uint64_t low_limit; 170 } aliases[] = { 171 {ALIAS_MAXLWPS, "zone.max-lwps", "privileged", "deny", 100}, 172 {ALIAS_MAXSHMMEM, "zone.max-shm-memory", "privileged", "deny", 0}, 173 {ALIAS_MAXSHMIDS, "zone.max-shm-ids", "privileged", "deny", 0}, 174 {ALIAS_MAXMSGIDS, "zone.max-msg-ids", "privileged", "deny", 0}, 175 {ALIAS_MAXSEMIDS, "zone.max-sem-ids", "privileged", "deny", 0}, 176 {ALIAS_MAXLOCKEDMEM, "zone.max-locked-memory", "privileged", "deny", 0}, 177 {ALIAS_MAXSWAP, "zone.max-swap", "privileged", "deny", 0}, 178 {ALIAS_SHARES, "zone.cpu-shares", "privileged", "none", 0}, 179 {ALIAS_CPUCAP, "zone.cpu-cap", "privileged", "deny", 0}, 180 {ALIAS_MAXPROCS, "zone.max-processes", "privileged", "deny", 100}, 181 {NULL, NULL, NULL, NULL, 0} 182 }; 183 184 /* 185 * Structure for applying rctls to a running zone. It allows important 186 * process values to be passed together easily. 187 */ 188 typedef struct pr_info_handle { 189 struct ps_prochandle *pr; 190 pid_t pid; 191 } pr_info_handle_t; 192 193 struct zone_dochandle { 194 char *zone_dh_rootdir; 195 xmlDocPtr zone_dh_doc; 196 xmlNodePtr zone_dh_cur; 197 xmlNodePtr zone_dh_top; 198 boolean_t zone_dh_newzone; 199 boolean_t zone_dh_snapshot; 200 boolean_t zone_dh_sw_inv; 201 zone_userauths_t *zone_dh_userauths; 202 char zone_dh_delete_name[ZONENAME_MAX]; 203 }; 204 205 struct znotify { 206 void * zn_private; 207 evchan_t *zn_eventchan; 208 int (*zn_callback)(const char *zonename, zoneid_t zid, 209 const char *newstate, const char *oldstate, hrtime_t when, void *p); 210 pthread_mutex_t zn_mutex; 211 pthread_cond_t zn_cond; 212 pthread_mutex_t zn_bigmutex; 213 volatile enum {ZN_UNLOCKED, ZN_LOCKED, ZN_PING_INFLIGHT, 214 ZN_PING_RECEIVED} zn_state; 215 char zn_subscriber_id[MAX_SUBID_LEN]; 216 volatile boolean_t zn_failed; 217 int zn_failure_count; 218 }; 219 220 /* used to track nested zone-lock operations */ 221 static int zone_lock_cnt = 0; 222 223 /* used to communicate lock status to children */ 224 #define LOCK_ENV_VAR "_ZONEADM_LOCK_HELD" 225 static char zoneadm_lock_held[] = LOCK_ENV_VAR"=1"; 226 static char zoneadm_lock_not_held[] = LOCK_ENV_VAR"=0"; 227 228 char *zonecfg_root = ""; 229 230 /* 231 * For functions which return int, which is most of the functions herein, 232 * the return values should be from the Z_foo set defined in <libzonecfg.h>. 233 * In some instances, we take pains mapping some libc errno values to Z_foo 234 * values from this set. 235 */ 236 237 /* 238 * Set the root (/) path for all zonecfg configuration files. This is a 239 * private interface used by Live Upgrade extensions to access zone 240 * configuration inside mounted alternate boot environments. 241 */ 242 void 243 zonecfg_set_root(const char *rootpath) 244 { 245 if (*zonecfg_root != '\0') 246 free(zonecfg_root); 247 if (rootpath == NULL || rootpath[0] == '\0' || rootpath[1] == '\0' || 248 (zonecfg_root = strdup(rootpath)) == NULL) 249 zonecfg_root = ""; 250 } 251 252 const char * 253 zonecfg_get_root(void) 254 { 255 return (zonecfg_root); 256 } 257 258 boolean_t 259 zonecfg_in_alt_root(void) 260 { 261 return (*zonecfg_root != '\0'); 262 } 263 264 /* 265 * Callers of the _file_path() functions are expected to have the second 266 * parameter be a (char foo[MAXPATHLEN]). 267 */ 268 269 static boolean_t 270 config_file_path(const char *zonename, char *answer) 271 { 272 return (snprintf(answer, MAXPATHLEN, "%s%s/%s.xml", zonecfg_root, 273 ZONE_CONFIG_ROOT, zonename) < MAXPATHLEN); 274 } 275 276 static boolean_t 277 snap_file_path(const char *zonename, char *answer) 278 { 279 return (snprintf(answer, MAXPATHLEN, "%s%s/%s.snapshot.xml", 280 zonecfg_root, ZONE_SNAPSHOT_ROOT, zonename) < MAXPATHLEN); 281 } 282 283 /*ARGSUSED*/ 284 static void 285 zonecfg_error_func(void *ctx, const char *msg, ...) 286 { 287 /* 288 * This function does nothing by design. Its purpose is to prevent 289 * libxml from dumping unwanted messages to stdout/stderr. 290 */ 291 } 292 293 zone_dochandle_t 294 zonecfg_init_handle(void) 295 { 296 zone_dochandle_t handle = calloc(1, sizeof (struct zone_dochandle)); 297 if (handle == NULL) { 298 errno = Z_NOMEM; 299 return (NULL); 300 } 301 302 /* generic libxml initialization */ 303 (void) xmlLineNumbersDefault(1); 304 xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS; 305 xmlDoValidityCheckingDefaultValue = 1; 306 (void) xmlKeepBlanksDefault(0); 307 xmlGetWarningsDefaultValue = 0; 308 xmlSetGenericErrorFunc(NULL, zonecfg_error_func); 309 310 return (handle); 311 } 312 313 int 314 zonecfg_check_handle(zone_dochandle_t handle) 315 { 316 if (handle == NULL || handle->zone_dh_doc == NULL) 317 return (Z_BAD_HANDLE); 318 return (Z_OK); 319 } 320 321 void 322 zonecfg_fini_handle(zone_dochandle_t handle) 323 { 324 if (zonecfg_check_handle(handle) == Z_OK) 325 xmlFreeDoc(handle->zone_dh_doc); 326 if (handle != NULL) 327 free(handle); 328 } 329 330 static int 331 zonecfg_destroy_impl(char *filename) 332 { 333 if (unlink(filename) == -1) { 334 if (errno == EACCES) 335 return (Z_ACCES); 336 if (errno == ENOENT) 337 return (Z_NO_ZONE); 338 return (Z_MISC_FS); 339 } 340 return (Z_OK); 341 } 342 343 int 344 zonecfg_destroy(const char *zonename, boolean_t force) 345 { 346 char path[MAXPATHLEN]; 347 struct zoneent ze; 348 int err, state_err; 349 zone_state_t state; 350 351 if (!config_file_path(zonename, path)) 352 return (Z_MISC_FS); 353 354 state_err = zone_get_state((char *)zonename, &state); 355 err = access(path, W_OK); 356 357 /* 358 * If there is no file, and no index entry, reliably indicate that no 359 * such zone exists. 360 */ 361 if ((state_err == Z_NO_ZONE) && (err == -1) && (errno == ENOENT)) 362 return (Z_NO_ZONE); 363 364 /* 365 * Handle any other filesystem related errors (except if the XML 366 * file is missing, which we treat silently), unless we're forcing, 367 * in which case we plow on. 368 */ 369 if (err == -1 && errno != ENOENT) { 370 if (errno == EACCES) 371 return (Z_ACCES); 372 else if (!force) 373 return (Z_MISC_FS); 374 } 375 376 if (state > ZONE_STATE_INSTALLED) 377 return (Z_BAD_ZONE_STATE); 378 379 if (!force && state > ZONE_STATE_CONFIGURED) 380 return (Z_BAD_ZONE_STATE); 381 382 /* 383 * Index deletion succeeds even if the entry doesn't exist. So this 384 * will fail only if we've had some more severe problem. 385 */ 386 bzero(&ze, sizeof (ze)); 387 (void) strlcpy(ze.zone_name, zonename, sizeof (ze.zone_name)); 388 if ((err = putzoneent(&ze, PZE_REMOVE)) != Z_OK) 389 if (!force) 390 return (err); 391 392 err = zonecfg_destroy_impl(path); 393 394 /* 395 * Treat failure to find the XML file silently, since, well, it's 396 * gone, and with the index file cleaned up, we're done. 397 */ 398 if (err == Z_OK || err == Z_NO_ZONE) 399 return (Z_OK); 400 return (err); 401 } 402 403 int 404 zonecfg_destroy_snapshot(const char *zonename) 405 { 406 char path[MAXPATHLEN]; 407 408 if (!snap_file_path(zonename, path)) 409 return (Z_MISC_FS); 410 return (zonecfg_destroy_impl(path)); 411 } 412 413 static int 414 getroot(zone_dochandle_t handle, xmlNodePtr *root) 415 { 416 if (zonecfg_check_handle(handle) == Z_BAD_HANDLE) 417 return (Z_BAD_HANDLE); 418 419 *root = xmlDocGetRootElement(handle->zone_dh_doc); 420 421 if (*root == NULL) 422 return (Z_EMPTY_DOCUMENT); 423 424 if (xmlStrcmp((*root)->name, DTD_ELEM_ZONE)) 425 return (Z_WRONG_DOC_TYPE); 426 427 return (Z_OK); 428 } 429 430 static int 431 operation_prep(zone_dochandle_t handle) 432 { 433 xmlNodePtr root; 434 int err; 435 436 if ((err = getroot(handle, &root)) != 0) 437 return (err); 438 439 handle->zone_dh_cur = root; 440 handle->zone_dh_top = root; 441 return (Z_OK); 442 } 443 444 static int 445 fetchprop(xmlNodePtr cur, const xmlChar *propname, char *dst, size_t dstsize) 446 { 447 xmlChar *property; 448 size_t srcsize; 449 450 if ((property = xmlGetProp(cur, propname)) == NULL) 451 return (Z_BAD_PROPERTY); 452 srcsize = strlcpy(dst, (char *)property, dstsize); 453 xmlFree(property); 454 if (srcsize >= dstsize) 455 return (Z_TOO_BIG); 456 return (Z_OK); 457 } 458 459 static int 460 fetch_alloc_prop(xmlNodePtr cur, const xmlChar *propname, char **dst) 461 { 462 xmlChar *property; 463 464 if ((property = xmlGetProp(cur, propname)) == NULL) 465 return (Z_BAD_PROPERTY); 466 if ((*dst = strdup((char *)property)) == NULL) { 467 xmlFree(property); 468 return (Z_NOMEM); 469 } 470 xmlFree(property); 471 return (Z_OK); 472 } 473 474 static int 475 getrootattr(zone_dochandle_t handle, const xmlChar *propname, 476 char *propval, size_t propsize) 477 { 478 xmlNodePtr root; 479 int err; 480 481 if ((err = getroot(handle, &root)) != 0) 482 return (err); 483 484 return (fetchprop(root, propname, propval, propsize)); 485 } 486 487 static int 488 get_alloc_rootattr(zone_dochandle_t handle, const xmlChar *propname, 489 char **propval) 490 { 491 xmlNodePtr root; 492 int err; 493 494 if ((err = getroot(handle, &root)) != 0) 495 return (err); 496 497 return (fetch_alloc_prop(root, propname, propval)); 498 } 499 500 static int 501 setrootattr(zone_dochandle_t handle, const xmlChar *propname, 502 const char *propval) 503 { 504 int err; 505 xmlNodePtr root; 506 507 if ((err = getroot(handle, &root)) != Z_OK) 508 return (err); 509 510 /* 511 * If we get a null propval remove the property (ignore return since it 512 * may not be set to begin with). 513 */ 514 if (propval == NULL) { 515 (void) xmlUnsetProp(root, propname); 516 } else { 517 if (xmlSetProp(root, propname, (const xmlChar *) propval) 518 == NULL) 519 return (Z_INVAL); 520 } 521 return (Z_OK); 522 } 523 524 static void 525 addcomment(zone_dochandle_t handle, const char *comment) 526 { 527 xmlNodePtr node; 528 node = xmlNewComment((xmlChar *) comment); 529 530 if (node != NULL) 531 (void) xmlAddPrevSibling(handle->zone_dh_top, node); 532 } 533 534 static void 535 stripcomments(zone_dochandle_t handle) 536 { 537 xmlDocPtr top; 538 xmlNodePtr child, next; 539 540 top = handle->zone_dh_doc; 541 for (child = top->xmlChildrenNode; child != NULL; child = next) { 542 next = child->next; 543 if (child->name == NULL) 544 continue; 545 if (xmlStrcmp(child->name, DTD_ELEM_COMMENT) == 0) { 546 next = child->next; 547 xmlUnlinkNode(child); 548 xmlFreeNode(child); 549 } 550 } 551 } 552 553 static void 554 strip_sw_inv(zone_dochandle_t handle) 555 { 556 xmlNodePtr root, child, next; 557 558 root = xmlDocGetRootElement(handle->zone_dh_doc); 559 for (child = root->xmlChildrenNode; child != NULL; child = next) { 560 next = child->next; 561 if (child->name == NULL) 562 continue; 563 if (xmlStrcmp(child->name, DTD_ELEM_PACKAGE) == 0 || 564 xmlStrcmp(child->name, DTD_ELEM_PATCH) == 0) { 565 next = child->next; 566 xmlUnlinkNode(child); 567 xmlFreeNode(child); 568 } 569 } 570 } 571 572 static int 573 zonecfg_get_handle_impl(const char *zonename, const char *filename, 574 zone_dochandle_t handle) 575 { 576 xmlValidCtxtPtr cvp; 577 struct stat statbuf; 578 int valid; 579 580 if (zonename == NULL) 581 return (Z_NO_ZONE); 582 583 if ((handle->zone_dh_doc = xmlParseFile(filename)) == NULL) { 584 /* distinguish file not found vs. found but not parsed */ 585 if (stat(filename, &statbuf) == 0) 586 return (Z_INVALID_DOCUMENT); 587 return (Z_NO_ZONE); 588 } 589 if ((cvp = xmlNewValidCtxt()) == NULL) 590 return (Z_NOMEM); 591 cvp->error = zonecfg_error_func; 592 cvp->warning = zonecfg_error_func; 593 valid = xmlValidateDocument(cvp, handle->zone_dh_doc); 594 xmlFreeValidCtxt(cvp); 595 if (valid == 0) 596 return (Z_INVALID_DOCUMENT); 597 598 /* delete any comments such as inherited Sun copyright / ident str */ 599 stripcomments(handle); 600 return (Z_OK); 601 } 602 603 int 604 zonecfg_get_handle(const char *zonename, zone_dochandle_t handle) 605 { 606 char path[MAXPATHLEN]; 607 608 if (!config_file_path(zonename, path)) 609 return (Z_MISC_FS); 610 handle->zone_dh_newzone = B_FALSE; 611 612 return (zonecfg_get_handle_impl(zonename, path, handle)); 613 } 614 615 int 616 zonecfg_get_attach_handle(const char *path, const char *fname, 617 const char *zonename, boolean_t preserve_sw, zone_dochandle_t handle) 618 { 619 char migpath[MAXPATHLEN]; 620 int err; 621 struct stat buf; 622 623 if (snprintf(migpath, sizeof (migpath), "%s/root", path) >= 624 sizeof (migpath)) 625 return (Z_NOMEM); 626 627 if (stat(migpath, &buf) == -1 || !S_ISDIR(buf.st_mode)) 628 return (Z_NO_ZONE); 629 630 if (snprintf(migpath, sizeof (migpath), "%s/%s", path, fname) >= 631 sizeof (migpath)) 632 return (Z_NOMEM); 633 634 if ((err = zonecfg_get_handle_impl(zonename, migpath, handle)) != Z_OK) 635 return (err); 636 637 if (!preserve_sw) 638 strip_sw_inv(handle); 639 640 handle->zone_dh_newzone = B_TRUE; 641 if ((err = setrootattr(handle, DTD_ATTR_ZONEPATH, path)) != Z_OK) 642 return (err); 643 644 return (setrootattr(handle, DTD_ATTR_NAME, zonename)); 645 } 646 647 int 648 zonecfg_get_snapshot_handle(const char *zonename, zone_dochandle_t handle) 649 { 650 char path[MAXPATHLEN]; 651 652 if (!snap_file_path(zonename, path)) 653 return (Z_MISC_FS); 654 handle->zone_dh_newzone = B_FALSE; 655 return (zonecfg_get_handle_impl(zonename, path, handle)); 656 } 657 658 int 659 zonecfg_get_template_handle(const char *template, const char *zonename, 660 zone_dochandle_t handle) 661 { 662 char path[MAXPATHLEN]; 663 int err; 664 665 if (!config_file_path(template, path)) 666 return (Z_MISC_FS); 667 668 if ((err = zonecfg_get_handle_impl(template, path, handle)) != Z_OK) 669 return (err); 670 handle->zone_dh_newzone = B_TRUE; 671 return (setrootattr(handle, DTD_ATTR_NAME, zonename)); 672 } 673 674 int 675 zonecfg_get_xml_handle(const char *path, zone_dochandle_t handle) 676 { 677 struct stat buf; 678 int err; 679 680 if (stat(path, &buf) == -1) 681 return (Z_MISC_FS); 682 683 if ((err = zonecfg_get_handle_impl("xml", path, handle)) != Z_OK) 684 return (err); 685 handle->zone_dh_newzone = B_TRUE; 686 return (Z_OK); 687 } 688 689 /* 690 * Initialize two handles from the manifest read on fd. The rem_handle 691 * is initialized from the input file, including the sw inventory. The 692 * local_handle is initialized with the same zone configuration but with 693 * no sw inventory. 694 */ 695 int 696 zonecfg_attach_manifest(int fd, zone_dochandle_t local_handle, 697 zone_dochandle_t rem_handle) 698 { 699 xmlValidCtxtPtr cvp; 700 int valid; 701 702 /* load the manifest into the handle for the remote system */ 703 if ((rem_handle->zone_dh_doc = xmlReadFd(fd, NULL, NULL, 0)) == NULL) { 704 return (Z_INVALID_DOCUMENT); 705 } 706 if ((cvp = xmlNewValidCtxt()) == NULL) 707 return (Z_NOMEM); 708 cvp->error = zonecfg_error_func; 709 cvp->warning = zonecfg_error_func; 710 valid = xmlValidateDocument(cvp, rem_handle->zone_dh_doc); 711 xmlFreeValidCtxt(cvp); 712 if (valid == 0) 713 return (Z_INVALID_DOCUMENT); 714 715 /* delete any comments such as inherited Sun copyright / ident str */ 716 stripcomments(rem_handle); 717 718 rem_handle->zone_dh_newzone = B_TRUE; 719 rem_handle->zone_dh_sw_inv = B_TRUE; 720 721 /* 722 * Now use the remote system handle to generate a local system handle 723 * with an identical zones configuration but no sw inventory. 724 */ 725 if ((local_handle->zone_dh_doc = xmlCopyDoc(rem_handle->zone_dh_doc, 726 1)) == NULL) { 727 return (Z_INVALID_DOCUMENT); 728 } 729 730 /* 731 * We need to re-run xmlValidateDocument on local_handle to properly 732 * update the in-core representation of the configuration. 733 */ 734 if ((cvp = xmlNewValidCtxt()) == NULL) 735 return (Z_NOMEM); 736 cvp->error = zonecfg_error_func; 737 cvp->warning = zonecfg_error_func; 738 valid = xmlValidateDocument(cvp, local_handle->zone_dh_doc); 739 xmlFreeValidCtxt(cvp); 740 if (valid == 0) 741 return (Z_INVALID_DOCUMENT); 742 743 strip_sw_inv(local_handle); 744 745 local_handle->zone_dh_newzone = B_TRUE; 746 local_handle->zone_dh_sw_inv = B_FALSE; 747 748 return (Z_OK); 749 } 750 751 static boolean_t 752 is_renaming(zone_dochandle_t handle) 753 { 754 if (handle->zone_dh_newzone) 755 return (B_FALSE); 756 if (strlen(handle->zone_dh_delete_name) > 0) 757 return (B_TRUE); 758 return (B_FALSE); 759 } 760 761 static boolean_t 762 is_new(zone_dochandle_t handle) 763 { 764 return (handle->zone_dh_newzone || handle->zone_dh_snapshot); 765 } 766 767 static boolean_t 768 is_snapshot(zone_dochandle_t handle) 769 { 770 return (handle->zone_dh_snapshot); 771 } 772 773 /* 774 * It would be great to be able to use libc's ctype(3c) macros, but we 775 * can't, as they are locale sensitive, and it would break our limited thread 776 * safety if this routine had to change the app locale on the fly. 777 */ 778 int 779 zonecfg_validate_zonename(const char *zone) 780 { 781 int i; 782 783 if (strcmp(zone, GLOBAL_ZONENAME) == 0) 784 return (Z_BOGUS_ZONE_NAME); 785 786 if (strlen(zone) >= ZONENAME_MAX) 787 return (Z_BOGUS_ZONE_NAME); 788 789 if (!((zone[0] >= 'a' && zone[0] <= 'z') || 790 (zone[0] >= 'A' && zone[0] <= 'Z') || 791 (zone[0] >= '0' && zone[0] <= '9'))) 792 return (Z_BOGUS_ZONE_NAME); 793 794 for (i = 1; zone[i] != '\0'; i++) { 795 if (!((zone[i] >= 'a' && zone[i] <= 'z') || 796 (zone[i] >= 'A' && zone[i] <= 'Z') || 797 (zone[i] >= '0' && zone[i] <= '9') || 798 (zone[i] == '-') || (zone[i] == '_') || (zone[i] == '.'))) 799 return (Z_BOGUS_ZONE_NAME); 800 } 801 802 return (Z_OK); 803 } 804 805 /* 806 * Changing the zone name requires us to track both the old and new 807 * name of the zone until commit time. 808 */ 809 int 810 zonecfg_get_name(zone_dochandle_t handle, char *name, size_t namesize) 811 { 812 return (getrootattr(handle, DTD_ATTR_NAME, name, namesize)); 813 } 814 815 static int 816 insert_admins(zone_dochandle_t handle, char *zonename) 817 { 818 int err; 819 struct zone_admintab admintab; 820 821 if ((err = zonecfg_setadminent(handle)) != Z_OK) { 822 return (err); 823 } 824 while (zonecfg_getadminent(handle, &admintab) == Z_OK) { 825 err = zonecfg_insert_userauths(handle, 826 admintab.zone_admin_user, zonename); 827 if (err != Z_OK) { 828 (void) zonecfg_endadminent(handle); 829 return (err); 830 } 831 } 832 (void) zonecfg_endadminent(handle); 833 return (Z_OK); 834 } 835 836 int 837 zonecfg_set_name(zone_dochandle_t handle, char *name) 838 { 839 zone_state_t state; 840 char curname[ZONENAME_MAX], old_delname[ZONENAME_MAX]; 841 int err; 842 843 if ((err = getrootattr(handle, DTD_ATTR_NAME, curname, 844 sizeof (curname))) != Z_OK) 845 return (err); 846 847 if (strcmp(name, curname) == 0) 848 return (Z_OK); 849 850 /* 851 * Switching zone names to one beginning with SUNW is not permitted. 852 */ 853 if (strncmp(name, "SUNW", 4) == 0) 854 return (Z_BOGUS_ZONE_NAME); 855 856 if ((err = zonecfg_validate_zonename(name)) != Z_OK) 857 return (err); 858 859 /* 860 * Setting the name back to the original name (effectively a revert of 861 * the name) is fine. But if we carry on, we'll falsely identify the 862 * name as "in use," so special case here. 863 */ 864 if (strcmp(name, handle->zone_dh_delete_name) == 0) { 865 err = setrootattr(handle, DTD_ATTR_NAME, name); 866 handle->zone_dh_delete_name[0] = '\0'; 867 return (err); 868 } 869 870 /* Check to see if new name chosen is already in use */ 871 if (zone_get_state(name, &state) != Z_NO_ZONE) 872 return (Z_NAME_IN_USE); 873 874 /* 875 * If this isn't already "new" or in a renaming transition, then 876 * we're initiating a rename here; so stash the "delete name" 877 * (i.e. the name of the zone we'll be removing) for the rename. 878 */ 879 (void) strlcpy(old_delname, handle->zone_dh_delete_name, 880 sizeof (old_delname)); 881 if (!is_new(handle) && !is_renaming(handle)) { 882 /* 883 * Name change is allowed only when the zone we're altering 884 * is not ready or running. 885 */ 886 err = zone_get_state(curname, &state); 887 if (err == Z_OK) { 888 if (state > ZONE_STATE_INSTALLED) 889 return (Z_BAD_ZONE_STATE); 890 } else if (err != Z_NO_ZONE) { 891 return (err); 892 } 893 894 (void) strlcpy(handle->zone_dh_delete_name, curname, 895 sizeof (handle->zone_dh_delete_name)); 896 assert(is_renaming(handle)); 897 } else if (is_renaming(handle)) { 898 err = zone_get_state(handle->zone_dh_delete_name, &state); 899 if (err == Z_OK) { 900 if (state > ZONE_STATE_INSTALLED) 901 return (Z_BAD_ZONE_STATE); 902 } else if (err != Z_NO_ZONE) { 903 return (err); 904 } 905 } 906 907 if ((err = setrootattr(handle, DTD_ATTR_NAME, name)) != Z_OK) { 908 /* 909 * Restore the deletename to whatever it was at the 910 * top of the routine, since we've had a failure. 911 */ 912 (void) strlcpy(handle->zone_dh_delete_name, old_delname, 913 sizeof (handle->zone_dh_delete_name)); 914 return (err); 915 } 916 917 /* 918 * Record the old admins from the old zonename 919 * so that they can be deleted when the operation is committed. 920 */ 921 if ((err = insert_admins(handle, curname)) != Z_OK) 922 return (err); 923 else 924 return (Z_OK); 925 } 926 927 int 928 zonecfg_get_zonepath(zone_dochandle_t handle, char *path, size_t pathsize) 929 { 930 size_t len; 931 932 if ((len = strlcpy(path, zonecfg_root, pathsize)) >= pathsize) 933 return (Z_TOO_BIG); 934 return (getrootattr(handle, DTD_ATTR_ZONEPATH, path + len, 935 pathsize - len)); 936 } 937 938 int 939 zonecfg_set_zonepath(zone_dochandle_t handle, char *zonepath) 940 { 941 size_t len; 942 char *modpath, *copy_mp, *curr_mp; /* modified path ptrs */ 943 char last_copied; 944 int ret; 945 946 /* 947 * Collapse multiple contiguous slashes and remove trailing slash. 948 */ 949 modpath = strdup(zonepath); 950 if (modpath == NULL) 951 return (Z_NOMEM); 952 last_copied = '\0'; 953 for (copy_mp = curr_mp = modpath; *curr_mp != '\0'; curr_mp++) { 954 if (*curr_mp != '/' || last_copied != '/') { 955 last_copied = *copy_mp = *curr_mp; 956 copy_mp++; 957 } 958 } 959 if (last_copied == '/') 960 copy_mp--; 961 *copy_mp = '\0'; 962 963 /* 964 * The user deals in absolute paths in the running global zone, but the 965 * internal configuration files deal with boot environment relative 966 * paths. Strip out the alternate root when specified. 967 */ 968 len = strlen(zonecfg_root); 969 if (strncmp(modpath, zonecfg_root, len) != 0 || modpath[len] != '/') { 970 free(modpath); 971 return (Z_BAD_PROPERTY); 972 } 973 curr_mp = modpath + len; 974 ret = setrootattr(handle, DTD_ATTR_ZONEPATH, curr_mp); 975 free(modpath); 976 return (ret); 977 } 978 979 static int 980 i_zonecfg_get_brand(zone_dochandle_t handle, char *brand, size_t brandsize, 981 boolean_t default_query) 982 { 983 int ret, sz; 984 985 ret = getrootattr(handle, DTD_ATTR_BRAND, brand, brandsize); 986 987 /* 988 * If the lookup failed, or succeeded in finding a non-null brand 989 * string then return. 990 */ 991 if (ret != Z_OK || brand[0] != '\0') 992 return (ret); 993 994 if (!default_query) { 995 /* If the zone has no brand, it is the default brand. */ 996 return (zonecfg_default_brand(brand, brandsize)); 997 } 998 999 /* if SUNWdefault didn't specify a brand, fallback to "native" */ 1000 sz = strlcpy(brand, NATIVE_BRAND_NAME, brandsize); 1001 if (sz >= brandsize) 1002 return (Z_TOO_BIG); 1003 return (Z_OK); 1004 } 1005 1006 int 1007 zonecfg_get_brand(zone_dochandle_t handle, char *brand, size_t brandsize) 1008 { 1009 return (i_zonecfg_get_brand(handle, brand, brandsize, B_FALSE)); 1010 } 1011 1012 int 1013 zonecfg_set_brand(zone_dochandle_t handle, char *brand) 1014 { 1015 return (setrootattr(handle, DTD_ATTR_BRAND, brand)); 1016 } 1017 1018 int 1019 zonecfg_get_autoboot(zone_dochandle_t handle, boolean_t *autoboot) 1020 { 1021 char autobootstr[DTD_ENTITY_BOOL_LEN]; 1022 int ret; 1023 1024 if ((ret = getrootattr(handle, DTD_ATTR_AUTOBOOT, autobootstr, 1025 sizeof (autobootstr))) != Z_OK) 1026 return (ret); 1027 1028 if (strcmp(autobootstr, DTD_ENTITY_TRUE) == 0) 1029 *autoboot = B_TRUE; 1030 else if (strcmp(autobootstr, DTD_ENTITY_FALSE) == 0) 1031 *autoboot = B_FALSE; 1032 else 1033 ret = Z_BAD_PROPERTY; 1034 return (ret); 1035 } 1036 1037 int 1038 zonecfg_set_autoboot(zone_dochandle_t handle, boolean_t autoboot) 1039 { 1040 return (setrootattr(handle, DTD_ATTR_AUTOBOOT, 1041 autoboot ? DTD_ENTITY_TRUE : DTD_ENTITY_FALSE)); 1042 } 1043 1044 int 1045 zonecfg_get_pool(zone_dochandle_t handle, char *pool, size_t poolsize) 1046 { 1047 return (getrootattr(handle, DTD_ATTR_POOL, pool, poolsize)); 1048 } 1049 1050 int 1051 zonecfg_set_pool(zone_dochandle_t handle, char *pool) 1052 { 1053 return (setrootattr(handle, DTD_ATTR_POOL, pool)); 1054 } 1055 1056 int 1057 zonecfg_get_limitpriv(zone_dochandle_t handle, char **limitpriv) 1058 { 1059 return (get_alloc_rootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv)); 1060 } 1061 1062 int 1063 zonecfg_set_limitpriv(zone_dochandle_t handle, char *limitpriv) 1064 { 1065 return (setrootattr(handle, DTD_ATTR_LIMITPRIV, limitpriv)); 1066 } 1067 1068 int 1069 zonecfg_get_bootargs(zone_dochandle_t handle, char *bargs, size_t bargssize) 1070 { 1071 return (getrootattr(handle, DTD_ATTR_BOOTARGS, bargs, bargssize)); 1072 } 1073 1074 int 1075 zonecfg_set_bootargs(zone_dochandle_t handle, char *bargs) 1076 { 1077 return (setrootattr(handle, DTD_ATTR_BOOTARGS, bargs)); 1078 } 1079 1080 int 1081 zonecfg_get_sched_class(zone_dochandle_t handle, char *sched, size_t schedsize) 1082 { 1083 return (getrootattr(handle, DTD_ATTR_SCHED, sched, schedsize)); 1084 } 1085 1086 int 1087 zonecfg_set_sched(zone_dochandle_t handle, char *sched) 1088 { 1089 return (setrootattr(handle, DTD_ATTR_SCHED, sched)); 1090 } 1091 1092 /* 1093 * /etc/zones/index caches a vital piece of information which is also 1094 * in the <zonename>.xml file: the path to the zone. This is for performance, 1095 * since we need to walk all zonepath's in order to be able to detect conflicts 1096 * (see crosscheck_zonepaths() in the zoneadm command). 1097 * 1098 * An additional complexity is that when doing a rename, we'd like the entire 1099 * index update operation (rename, and potential state changes) to be atomic. 1100 * In general, the operation of this function should succeed or fail as 1101 * a unit. 1102 */ 1103 int 1104 zonecfg_refresh_index_file(zone_dochandle_t handle) 1105 { 1106 char name[ZONENAME_MAX], zonepath[MAXPATHLEN]; 1107 struct zoneent ze; 1108 int err; 1109 int opcode; 1110 char *zn; 1111 1112 bzero(&ze, sizeof (ze)); 1113 ze.zone_state = -1; /* Preserve existing state in index */ 1114 1115 if ((err = zonecfg_get_name(handle, name, sizeof (name))) != Z_OK) 1116 return (err); 1117 (void) strlcpy(ze.zone_name, name, sizeof (ze.zone_name)); 1118 1119 if ((err = zonecfg_get_zonepath(handle, zonepath, 1120 sizeof (zonepath))) != Z_OK) 1121 return (err); 1122 (void) strlcpy(ze.zone_path, zonepath + strlen(zonecfg_root), 1123 sizeof (ze.zone_path)); 1124 1125 if (is_renaming(handle)) { 1126 opcode = PZE_MODIFY; 1127 (void) strlcpy(ze.zone_name, handle->zone_dh_delete_name, 1128 sizeof (ze.zone_name)); 1129 (void) strlcpy(ze.zone_newname, name, sizeof (ze.zone_newname)); 1130 } else if (is_new(handle)) { 1131 FILE *cookie; 1132 /* 1133 * Be tolerant of the zone already existing in the index file, 1134 * since we might be forcibly overwriting an existing 1135 * configuration with a new one (for example 'create -F' 1136 * in zonecfg). 1137 */ 1138 opcode = PZE_ADD; 1139 cookie = setzoneent(); 1140 while ((zn = getzoneent(cookie)) != NULL) { 1141 if (strcmp(zn, name) == 0) { 1142 opcode = PZE_MODIFY; 1143 free(zn); 1144 break; 1145 } 1146 free(zn); 1147 } 1148 endzoneent(cookie); 1149 ze.zone_state = ZONE_STATE_CONFIGURED; 1150 } else { 1151 opcode = PZE_MODIFY; 1152 } 1153 1154 if ((err = putzoneent(&ze, opcode)) != Z_OK) 1155 return (err); 1156 1157 return (Z_OK); 1158 } 1159 1160 /* 1161 * The goal of this routine is to cause the index file update and the 1162 * document save to happen as an atomic operation. We do the document 1163 * first, saving a backup copy using a hard link; if that succeeds, we go 1164 * on to the index. If that fails, we roll the document back into place. 1165 * 1166 * Strategy: 1167 * 1168 * New zone 'foo' configuration: 1169 * Create tmpfile (zonecfg.xxxxxx) 1170 * Write XML to tmpfile 1171 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml) 1172 * Add entry to index file 1173 * If it fails, delete foo.xml, leaving nothing behind. 1174 * 1175 * Save existing zone 'foo': 1176 * Make backup of foo.xml -> .backup 1177 * Create tmpfile (zonecfg.xxxxxx) 1178 * Write XML to tmpfile 1179 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> foo.xml) 1180 * Modify index file as needed 1181 * If it fails, recover from .backup -> foo.xml 1182 * 1183 * Rename 'foo' to 'bar': 1184 * Create tmpfile (zonecfg.xxxxxx) 1185 * Write XML to tmpfile 1186 * Rename tmpfile to xmlfile (zonecfg.xxxxxx -> bar.xml) 1187 * Add entry for 'bar' to index file, Remove entry for 'foo' (refresh) 1188 * If it fails, delete bar.xml; foo.xml is left behind. 1189 */ 1190 static int 1191 zonecfg_save_impl(zone_dochandle_t handle, char *filename) 1192 { 1193 char tmpfile[MAXPATHLEN]; 1194 char bakdir[MAXPATHLEN], bakbase[MAXPATHLEN], bakfile[MAXPATHLEN]; 1195 int tmpfd, err, valid; 1196 xmlValidCtxt cvp = { NULL }; 1197 boolean_t backup; 1198 1199 (void) strlcpy(tmpfile, filename, sizeof (tmpfile)); 1200 (void) dirname(tmpfile); 1201 (void) strlcat(tmpfile, _PATH_TMPFILE, sizeof (tmpfile)); 1202 1203 tmpfd = mkstemp(tmpfile); 1204 if (tmpfd == -1) { 1205 (void) unlink(tmpfile); 1206 return (Z_TEMP_FILE); 1207 } 1208 (void) close(tmpfd); 1209 1210 cvp.error = zonecfg_error_func; 1211 cvp.warning = zonecfg_error_func; 1212 1213 /* 1214 * We do a final validation of the document. Since the library has 1215 * malfunctioned if it fails to validate, we follow-up with an 1216 * assert() that the doc is valid. 1217 */ 1218 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc); 1219 assert(valid != 0); 1220 1221 if (xmlSaveFormatFile(tmpfile, handle->zone_dh_doc, 1) <= 0) 1222 goto err; 1223 1224 (void) chmod(tmpfile, 0644); 1225 1226 /* 1227 * In the event we are doing a standard save, hard link a copy of the 1228 * original file in .backup.<pid>.filename so we can restore it if 1229 * something goes wrong. 1230 */ 1231 if (!is_new(handle) && !is_renaming(handle)) { 1232 backup = B_TRUE; 1233 1234 (void) strlcpy(bakdir, filename, sizeof (bakdir)); 1235 (void) strlcpy(bakbase, filename, sizeof (bakbase)); 1236 (void) snprintf(bakfile, sizeof (bakfile), "%s/.backup.%d.%s", 1237 dirname(bakdir), getpid(), basename(bakbase)); 1238 1239 if (link(filename, bakfile) == -1) { 1240 err = errno; 1241 (void) unlink(tmpfile); 1242 if (errno == EACCES) 1243 return (Z_ACCES); 1244 return (Z_MISC_FS); 1245 } 1246 } 1247 1248 /* 1249 * Move the new document over top of the old. 1250 * i.e.: zonecfg.XXXXXX -> myzone.xml 1251 */ 1252 if (rename(tmpfile, filename) == -1) { 1253 err = errno; 1254 (void) unlink(tmpfile); 1255 if (backup) 1256 (void) unlink(bakfile); 1257 if (err == EACCES) 1258 return (Z_ACCES); 1259 return (Z_MISC_FS); 1260 } 1261 1262 /* 1263 * If this is a snapshot, we're done-- don't add an index entry. 1264 */ 1265 if (is_snapshot(handle)) 1266 return (Z_OK); 1267 1268 /* now update the index file to reflect whatever we just did */ 1269 if ((err = zonecfg_refresh_index_file(handle)) != Z_OK) { 1270 if (backup) { 1271 /* 1272 * Try to restore from our backup. 1273 */ 1274 (void) unlink(filename); 1275 (void) rename(bakfile, filename); 1276 } else { 1277 /* 1278 * Either the zone is new, in which case we can delete 1279 * new.xml, or we're doing a rename, so ditto. 1280 */ 1281 assert(is_new(handle) || is_renaming(handle)); 1282 (void) unlink(filename); 1283 } 1284 return (Z_UPDATING_INDEX); 1285 } 1286 1287 if (backup) 1288 (void) unlink(bakfile); 1289 1290 return (Z_OK); 1291 1292 err: 1293 (void) unlink(tmpfile); 1294 return (Z_SAVING_FILE); 1295 } 1296 1297 int 1298 zonecfg_save(zone_dochandle_t handle) 1299 { 1300 char zname[ZONENAME_MAX], path[MAXPATHLEN]; 1301 char delpath[MAXPATHLEN]; 1302 int err = Z_SAVING_FILE; 1303 1304 if (zonecfg_check_handle(handle) != Z_OK) 1305 return (Z_BAD_HANDLE); 1306 1307 /* 1308 * We don't support saving snapshots or a tree containing a sw 1309 * inventory at this time. 1310 */ 1311 if (handle->zone_dh_snapshot || handle->zone_dh_sw_inv) 1312 return (Z_INVAL); 1313 1314 if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) != Z_OK) 1315 return (err); 1316 1317 if (!config_file_path(zname, path)) 1318 return (Z_MISC_FS); 1319 1320 addcomment(handle, "\n DO NOT EDIT THIS " 1321 "FILE. Use zonecfg(1M) instead.\n"); 1322 1323 /* 1324 * Update user_attr first so that it will be older 1325 * than the config file. 1326 */ 1327 (void) zonecfg_authorize_users(handle, zname); 1328 err = zonecfg_save_impl(handle, path); 1329 1330 stripcomments(handle); 1331 1332 if (err != Z_OK) 1333 return (err); 1334 1335 handle->zone_dh_newzone = B_FALSE; 1336 1337 if (is_renaming(handle)) { 1338 if (config_file_path(handle->zone_dh_delete_name, delpath)) 1339 (void) unlink(delpath); 1340 handle->zone_dh_delete_name[0] = '\0'; 1341 } 1342 1343 return (Z_OK); 1344 } 1345 1346 int 1347 zonecfg_verify_save(zone_dochandle_t handle, char *filename) 1348 { 1349 int valid; 1350 1351 xmlValidCtxt cvp = { NULL }; 1352 1353 if (zonecfg_check_handle(handle) != Z_OK) 1354 return (Z_BAD_HANDLE); 1355 1356 cvp.error = zonecfg_error_func; 1357 cvp.warning = zonecfg_error_func; 1358 1359 /* 1360 * We do a final validation of the document. Since the library has 1361 * malfunctioned if it fails to validate, we follow-up with an 1362 * assert() that the doc is valid. 1363 */ 1364 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc); 1365 assert(valid != 0); 1366 1367 if (xmlSaveFormatFile(filename, handle->zone_dh_doc, 1) <= 0) 1368 return (Z_SAVING_FILE); 1369 1370 return (Z_OK); 1371 } 1372 1373 int 1374 zonecfg_detach_save(zone_dochandle_t handle, uint_t flags) 1375 { 1376 char zname[ZONENAME_MAX]; 1377 char path[MAXPATHLEN]; 1378 char migpath[MAXPATHLEN]; 1379 xmlValidCtxt cvp = { NULL }; 1380 int err = Z_SAVING_FILE; 1381 int valid; 1382 1383 if (zonecfg_check_handle(handle) != Z_OK) 1384 return (Z_BAD_HANDLE); 1385 1386 if (flags & ZONE_DRY_RUN) { 1387 (void) strlcpy(migpath, "-", sizeof (migpath)); 1388 } else { 1389 if ((err = zonecfg_get_name(handle, zname, sizeof (zname))) 1390 != Z_OK) 1391 return (err); 1392 1393 if ((err = zone_get_zonepath(zname, path, sizeof (path))) 1394 != Z_OK) 1395 return (err); 1396 1397 if (snprintf(migpath, sizeof (migpath), "%s/%s", path, 1398 ZONE_DETACHED) >= sizeof (migpath)) 1399 return (Z_NOMEM); 1400 } 1401 1402 if ((err = operation_prep(handle)) != Z_OK) 1403 return (err); 1404 1405 addcomment(handle, "\n DO NOT EDIT THIS FILE. " 1406 "Use zonecfg(1M) and zoneadm(1M) attach.\n"); 1407 1408 cvp.error = zonecfg_error_func; 1409 cvp.warning = zonecfg_error_func; 1410 1411 /* 1412 * We do a final validation of the document. Since the library has 1413 * malfunctioned if it fails to validate, we follow-up with an 1414 * assert() that the doc is valid. 1415 */ 1416 valid = xmlValidateDocument(&cvp, handle->zone_dh_doc); 1417 assert(valid != 0); 1418 1419 if (xmlSaveFormatFile(migpath, handle->zone_dh_doc, 1) <= 0) 1420 return (Z_SAVING_FILE); 1421 1422 if (!(flags & ZONE_DRY_RUN)) 1423 (void) chmod(migpath, 0644); 1424 1425 stripcomments(handle); 1426 1427 handle->zone_dh_newzone = B_FALSE; 1428 1429 return (Z_OK); 1430 } 1431 1432 boolean_t 1433 zonecfg_detached(const char *path) 1434 { 1435 char migpath[MAXPATHLEN]; 1436 struct stat buf; 1437 1438 if (snprintf(migpath, sizeof (migpath), "%s/%s", path, ZONE_DETACHED) >= 1439 sizeof (migpath)) 1440 return (B_FALSE); 1441 1442 if (stat(migpath, &buf) != -1) 1443 return (B_TRUE); 1444 1445 return (B_FALSE); 1446 } 1447 1448 void 1449 zonecfg_rm_detached(zone_dochandle_t handle, boolean_t forced) 1450 { 1451 char zname[ZONENAME_MAX]; 1452 char path[MAXPATHLEN]; 1453 char detached[MAXPATHLEN]; 1454 char attached[MAXPATHLEN]; 1455 1456 if (zonecfg_check_handle(handle) != Z_OK) 1457 return; 1458 1459 if (zonecfg_get_name(handle, zname, sizeof (zname)) != Z_OK) 1460 return; 1461 1462 if (zone_get_zonepath(zname, path, sizeof (path)) != Z_OK) 1463 return; 1464 1465 (void) snprintf(detached, sizeof (detached), "%s/%s", path, 1466 ZONE_DETACHED); 1467 (void) snprintf(attached, sizeof (attached), "%s/%s", path, 1468 ATTACH_FORCED); 1469 1470 if (forced) { 1471 (void) rename(detached, attached); 1472 } else { 1473 (void) unlink(attached); 1474 (void) unlink(detached); 1475 } 1476 } 1477 1478 /* 1479 * Special case: if access(2) fails with ENOENT, then try again using 1480 * ZONE_CONFIG_ROOT instead of config_file_path(zonename). This is how we 1481 * work around the case of a config file which has not been created yet: 1482 * the user will need access to the directory so use that as a heuristic. 1483 */ 1484 1485 int 1486 zonecfg_access(const char *zonename, int amode) 1487 { 1488 char path[MAXPATHLEN]; 1489 1490 if (!config_file_path(zonename, path)) 1491 return (Z_INVAL); 1492 if (access(path, amode) == 0) 1493 return (Z_OK); 1494 if (errno == ENOENT) { 1495 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root, 1496 ZONE_CONFIG_ROOT) >= sizeof (path)) 1497 return (Z_INVAL); 1498 if (access(path, amode) == 0) 1499 return (Z_OK); 1500 } 1501 if (errno == EACCES) 1502 return (Z_ACCES); 1503 if (errno == EINVAL) 1504 return (Z_INVAL); 1505 return (Z_MISC_FS); 1506 } 1507 1508 int 1509 zonecfg_create_snapshot(const char *zonename) 1510 { 1511 zone_dochandle_t handle; 1512 char path[MAXPATHLEN], zonepath[MAXPATHLEN], rpath[MAXPATHLEN]; 1513 int error = Z_OK, res; 1514 1515 if ((handle = zonecfg_init_handle()) == NULL) { 1516 return (Z_NOMEM); 1517 } 1518 1519 handle->zone_dh_newzone = B_TRUE; 1520 handle->zone_dh_snapshot = B_TRUE; 1521 1522 if ((error = zonecfg_get_handle(zonename, handle)) != Z_OK) 1523 goto out; 1524 if ((error = operation_prep(handle)) != Z_OK) 1525 goto out; 1526 error = zonecfg_get_zonepath(handle, zonepath, sizeof (zonepath)); 1527 if (error != Z_OK) 1528 goto out; 1529 if ((res = resolvepath(zonepath, rpath, sizeof (rpath))) == -1) { 1530 error = Z_RESOLVED_PATH; 1531 goto out; 1532 } 1533 /* 1534 * If the resolved path is not the same as the original path, then 1535 * save the resolved path in the snapshot, thus preventing any 1536 * potential problems down the line when zoneadmd goes to unmount 1537 * file systems and depends on initial string matches with resolved 1538 * paths. 1539 */ 1540 rpath[res] = '\0'; 1541 if (strcmp(zonepath, rpath) != 0) { 1542 if ((error = zonecfg_set_zonepath(handle, rpath)) != Z_OK) 1543 goto out; 1544 } 1545 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root, 1546 ZONE_SNAPSHOT_ROOT) >= sizeof (path)) { 1547 error = Z_MISC_FS; 1548 goto out; 1549 } 1550 if ((mkdir(path, S_IRWXU) == -1) && (errno != EEXIST)) { 1551 error = Z_MISC_FS; 1552 goto out; 1553 } 1554 1555 if (!snap_file_path(zonename, path)) { 1556 error = Z_MISC_FS; 1557 goto out; 1558 } 1559 1560 addcomment(handle, "\n DO NOT EDIT THIS FILE. " 1561 "It is a snapshot of running zone state.\n"); 1562 1563 error = zonecfg_save_impl(handle, path); 1564 1565 stripcomments(handle); 1566 1567 out: 1568 zonecfg_fini_handle(handle); 1569 return (error); 1570 } 1571 1572 int 1573 zonecfg_get_iptype(zone_dochandle_t handle, zone_iptype_t *iptypep) 1574 { 1575 char property[10]; /* 10 is big enough for "shared"/"exclusive" */ 1576 int err; 1577 1578 err = getrootattr(handle, DTD_ATTR_IPTYPE, property, sizeof (property)); 1579 if (err == Z_BAD_PROPERTY) { 1580 /* Return default value */ 1581 *iptypep = ZS_SHARED; 1582 return (Z_OK); 1583 } else if (err != Z_OK) { 1584 return (err); 1585 } 1586 1587 if (strlen(property) == 0 || 1588 strcmp(property, "shared") == 0) 1589 *iptypep = ZS_SHARED; 1590 else if (strcmp(property, "exclusive") == 0) 1591 *iptypep = ZS_EXCLUSIVE; 1592 else 1593 return (Z_INVAL); 1594 1595 return (Z_OK); 1596 } 1597 1598 int 1599 zonecfg_set_iptype(zone_dochandle_t handle, zone_iptype_t iptype) 1600 { 1601 xmlNodePtr cur; 1602 1603 if (handle == NULL) 1604 return (Z_INVAL); 1605 1606 cur = xmlDocGetRootElement(handle->zone_dh_doc); 1607 if (cur == NULL) { 1608 return (Z_EMPTY_DOCUMENT); 1609 } 1610 1611 if (xmlStrcmp(cur->name, DTD_ELEM_ZONE) != 0) { 1612 return (Z_WRONG_DOC_TYPE); 1613 } 1614 switch (iptype) { 1615 case ZS_SHARED: 1616 /* 1617 * Since "shared" is the default, we don't write it to the 1618 * configuration file, so that it's easier to migrate those 1619 * zones elsewhere, eg., to systems which are not IP-Instances 1620 * aware. 1621 * xmlUnsetProp only fails when the attribute doesn't exist, 1622 * which we don't care. 1623 */ 1624 (void) xmlUnsetProp(cur, DTD_ATTR_IPTYPE); 1625 break; 1626 case ZS_EXCLUSIVE: 1627 if (xmlSetProp(cur, DTD_ATTR_IPTYPE, 1628 (const xmlChar *) "exclusive") == NULL) 1629 return (Z_INVAL); 1630 break; 1631 } 1632 return (Z_OK); 1633 } 1634 1635 static int 1636 newprop(xmlNodePtr node, const xmlChar *attrname, char *src) 1637 { 1638 xmlAttrPtr newattr; 1639 1640 newattr = xmlNewProp(node, attrname, (xmlChar *)src); 1641 if (newattr == NULL) { 1642 xmlUnlinkNode(node); 1643 xmlFreeNode(node); 1644 return (Z_BAD_PROPERTY); 1645 } 1646 return (Z_OK); 1647 } 1648 1649 static int 1650 zonecfg_add_filesystem_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1651 { 1652 xmlNodePtr newnode, cur = handle->zone_dh_cur, options_node; 1653 zone_fsopt_t *ptr; 1654 int err; 1655 1656 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_FS, NULL); 1657 if ((err = newprop(newnode, DTD_ATTR_SPECIAL, 1658 tabptr->zone_fs_special)) != Z_OK) 1659 return (err); 1660 if (tabptr->zone_fs_raw[0] != '\0' && 1661 (err = newprop(newnode, DTD_ATTR_RAW, tabptr->zone_fs_raw)) != Z_OK) 1662 return (err); 1663 if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK) 1664 return (err); 1665 if ((err = newprop(newnode, DTD_ATTR_TYPE, 1666 tabptr->zone_fs_type)) != Z_OK) 1667 return (err); 1668 if (tabptr->zone_fs_options != NULL) { 1669 for (ptr = tabptr->zone_fs_options; ptr != NULL; 1670 ptr = ptr->zone_fsopt_next) { 1671 options_node = xmlNewTextChild(newnode, NULL, 1672 DTD_ELEM_FSOPTION, NULL); 1673 if ((err = newprop(options_node, DTD_ATTR_NAME, 1674 ptr->zone_fsopt_opt)) != Z_OK) 1675 return (err); 1676 } 1677 } 1678 return (Z_OK); 1679 } 1680 1681 int 1682 zonecfg_add_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr) 1683 { 1684 int err; 1685 1686 if (tabptr == NULL) 1687 return (Z_INVAL); 1688 1689 if ((err = operation_prep(handle)) != Z_OK) 1690 return (err); 1691 1692 if ((err = zonecfg_add_filesystem_core(handle, tabptr)) != Z_OK) 1693 return (err); 1694 1695 return (Z_OK); 1696 } 1697 1698 static int 1699 zonecfg_add_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1700 { 1701 xmlNodePtr newnode, cur = handle->zone_dh_cur; 1702 int err; 1703 1704 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_IPD, NULL); 1705 if ((err = newprop(newnode, DTD_ATTR_DIR, tabptr->zone_fs_dir)) != Z_OK) 1706 return (err); 1707 return (Z_OK); 1708 } 1709 1710 int 1711 zonecfg_add_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 1712 { 1713 int err; 1714 1715 if (tabptr == NULL) 1716 return (Z_INVAL); 1717 1718 if ((err = operation_prep(handle)) != Z_OK) 1719 return (err); 1720 1721 if ((err = zonecfg_add_ipd_core(handle, tabptr)) != Z_OK) 1722 return (err); 1723 1724 return (Z_OK); 1725 } 1726 1727 int 1728 zonecfg_add_fs_option(struct zone_fstab *tabptr, char *option) 1729 { 1730 zone_fsopt_t *last, *old, *new; 1731 1732 last = tabptr->zone_fs_options; 1733 for (old = last; old != NULL; old = old->zone_fsopt_next) 1734 last = old; /* walk to the end of the list */ 1735 new = (zone_fsopt_t *)malloc(sizeof (zone_fsopt_t)); 1736 if (new == NULL) 1737 return (Z_NOMEM); 1738 (void) strlcpy(new->zone_fsopt_opt, option, 1739 sizeof (new->zone_fsopt_opt)); 1740 new->zone_fsopt_next = NULL; 1741 if (last == NULL) 1742 tabptr->zone_fs_options = new; 1743 else 1744 last->zone_fsopt_next = new; 1745 return (Z_OK); 1746 } 1747 1748 int 1749 zonecfg_remove_fs_option(struct zone_fstab *tabptr, char *option) 1750 { 1751 zone_fsopt_t *last, *this, *next; 1752 1753 last = tabptr->zone_fs_options; 1754 for (this = last; this != NULL; this = this->zone_fsopt_next) { 1755 if (strcmp(this->zone_fsopt_opt, option) == 0) { 1756 next = this->zone_fsopt_next; 1757 if (this == tabptr->zone_fs_options) 1758 tabptr->zone_fs_options = next; 1759 else 1760 last->zone_fsopt_next = next; 1761 free(this); 1762 return (Z_OK); 1763 } else 1764 last = this; 1765 } 1766 return (Z_NO_PROPERTY_ID); 1767 } 1768 1769 void 1770 zonecfg_free_fs_option_list(zone_fsopt_t *list) 1771 { 1772 zone_fsopt_t *this, *next; 1773 1774 for (this = list; this != NULL; this = next) { 1775 next = this->zone_fsopt_next; 1776 free(this); 1777 } 1778 } 1779 1780 void 1781 zonecfg_free_rctl_value_list(struct zone_rctlvaltab *valtab) 1782 { 1783 if (valtab == NULL) 1784 return; 1785 zonecfg_free_rctl_value_list(valtab->zone_rctlval_next); 1786 free(valtab); 1787 } 1788 1789 static boolean_t 1790 match_prop(xmlNodePtr cur, const xmlChar *attr, char *user_prop) 1791 { 1792 xmlChar *gotten_prop; 1793 int prop_result; 1794 1795 gotten_prop = xmlGetProp(cur, attr); 1796 if (gotten_prop == NULL) /* shouldn't happen */ 1797 return (B_FALSE); 1798 prop_result = xmlStrcmp(gotten_prop, (const xmlChar *) user_prop); 1799 xmlFree(gotten_prop); 1800 return ((prop_result == 0)); 1801 } 1802 1803 static int 1804 zonecfg_delete_filesystem_core(zone_dochandle_t handle, 1805 struct zone_fstab *tabptr) 1806 { 1807 xmlNodePtr cur = handle->zone_dh_cur; 1808 boolean_t dir_match, spec_match, raw_match, type_match; 1809 1810 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1811 if (xmlStrcmp(cur->name, DTD_ELEM_FS)) 1812 continue; 1813 dir_match = match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir); 1814 spec_match = match_prop(cur, DTD_ATTR_SPECIAL, 1815 tabptr->zone_fs_special); 1816 raw_match = match_prop(cur, DTD_ATTR_RAW, 1817 tabptr->zone_fs_raw); 1818 type_match = match_prop(cur, DTD_ATTR_TYPE, 1819 tabptr->zone_fs_type); 1820 if (dir_match && spec_match && raw_match && type_match) { 1821 xmlUnlinkNode(cur); 1822 xmlFreeNode(cur); 1823 return (Z_OK); 1824 } 1825 } 1826 return (Z_NO_RESOURCE_ID); 1827 } 1828 1829 int 1830 zonecfg_delete_filesystem(zone_dochandle_t handle, struct zone_fstab *tabptr) 1831 { 1832 int err; 1833 1834 if (tabptr == NULL) 1835 return (Z_INVAL); 1836 1837 if ((err = operation_prep(handle)) != Z_OK) 1838 return (err); 1839 1840 if ((err = zonecfg_delete_filesystem_core(handle, tabptr)) != Z_OK) 1841 return (err); 1842 1843 return (Z_OK); 1844 } 1845 1846 int 1847 zonecfg_modify_filesystem( 1848 zone_dochandle_t handle, 1849 struct zone_fstab *oldtabptr, 1850 struct zone_fstab *newtabptr) 1851 { 1852 int err; 1853 1854 if (oldtabptr == NULL || newtabptr == NULL) 1855 return (Z_INVAL); 1856 1857 if ((err = operation_prep(handle)) != Z_OK) 1858 return (err); 1859 1860 if ((err = zonecfg_delete_filesystem_core(handle, oldtabptr)) != Z_OK) 1861 return (err); 1862 1863 if ((err = zonecfg_add_filesystem_core(handle, newtabptr)) != Z_OK) 1864 return (err); 1865 1866 return (Z_OK); 1867 } 1868 1869 static int 1870 zonecfg_delete_ipd_core(zone_dochandle_t handle, struct zone_fstab *tabptr) 1871 { 1872 xmlNodePtr cur = handle->zone_dh_cur; 1873 1874 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1875 if (xmlStrcmp(cur->name, DTD_ELEM_IPD)) 1876 continue; 1877 if (match_prop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir)) { 1878 xmlUnlinkNode(cur); 1879 xmlFreeNode(cur); 1880 return (Z_OK); 1881 } 1882 } 1883 return (Z_NO_RESOURCE_ID); 1884 } 1885 1886 int 1887 zonecfg_delete_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 1888 { 1889 int err; 1890 1891 if (tabptr == NULL) 1892 return (Z_INVAL); 1893 1894 if ((err = operation_prep(handle)) != Z_OK) 1895 return (err); 1896 1897 if ((err = zonecfg_delete_ipd_core(handle, tabptr)) != Z_OK) 1898 return (err); 1899 1900 return (Z_OK); 1901 } 1902 1903 int 1904 zonecfg_modify_ipd(zone_dochandle_t handle, struct zone_fstab *oldtabptr, 1905 struct zone_fstab *newtabptr) 1906 { 1907 int err; 1908 1909 if (oldtabptr == NULL || newtabptr == NULL) 1910 return (Z_INVAL); 1911 1912 if ((err = operation_prep(handle)) != Z_OK) 1913 return (err); 1914 1915 if ((err = zonecfg_delete_ipd_core(handle, oldtabptr)) != Z_OK) 1916 return (err); 1917 1918 if ((err = zonecfg_add_ipd_core(handle, newtabptr)) != Z_OK) 1919 return (err); 1920 1921 return (Z_OK); 1922 } 1923 1924 int 1925 zonecfg_lookup_filesystem( 1926 zone_dochandle_t handle, 1927 struct zone_fstab *tabptr) 1928 { 1929 xmlNodePtr cur, options, firstmatch; 1930 int err; 1931 char dirname[MAXPATHLEN], special[MAXPATHLEN], raw[MAXPATHLEN]; 1932 char type[FSTYPSZ]; 1933 char options_str[MAX_MNTOPT_STR]; 1934 1935 if (tabptr == NULL) 1936 return (Z_INVAL); 1937 1938 if ((err = operation_prep(handle)) != Z_OK) 1939 return (err); 1940 1941 /* 1942 * Walk the list of children looking for matches on any properties 1943 * specified in the fstab parameter. If more than one resource 1944 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return 1945 * Z_NO_RESOURCE_ID. 1946 */ 1947 cur = handle->zone_dh_cur; 1948 firstmatch = NULL; 1949 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 1950 if (xmlStrcmp(cur->name, DTD_ELEM_FS)) 1951 continue; 1952 if (strlen(tabptr->zone_fs_dir) > 0) { 1953 if ((fetchprop(cur, DTD_ATTR_DIR, dirname, 1954 sizeof (dirname)) == Z_OK) && 1955 (strcmp(tabptr->zone_fs_dir, dirname) == 0)) { 1956 if (firstmatch == NULL) 1957 firstmatch = cur; 1958 else 1959 return (Z_INSUFFICIENT_SPEC); 1960 } 1961 } 1962 if (strlen(tabptr->zone_fs_special) > 0) { 1963 if ((fetchprop(cur, DTD_ATTR_SPECIAL, special, 1964 sizeof (special)) == Z_OK)) { 1965 if (strcmp(tabptr->zone_fs_special, 1966 special) == 0) { 1967 if (firstmatch == NULL) 1968 firstmatch = cur; 1969 else if (firstmatch != cur) 1970 return (Z_INSUFFICIENT_SPEC); 1971 } else { 1972 /* 1973 * If another property matched but this 1974 * one doesn't then reset firstmatch. 1975 */ 1976 if (firstmatch == cur) 1977 firstmatch = NULL; 1978 } 1979 } 1980 } 1981 if (strlen(tabptr->zone_fs_raw) > 0) { 1982 if ((fetchprop(cur, DTD_ATTR_RAW, raw, 1983 sizeof (raw)) == Z_OK)) { 1984 if (strcmp(tabptr->zone_fs_raw, raw) == 0) { 1985 if (firstmatch == NULL) 1986 firstmatch = cur; 1987 else if (firstmatch != cur) 1988 return (Z_INSUFFICIENT_SPEC); 1989 } else { 1990 /* 1991 * If another property matched but this 1992 * one doesn't then reset firstmatch. 1993 */ 1994 if (firstmatch == cur) 1995 firstmatch = NULL; 1996 } 1997 } 1998 } 1999 if (strlen(tabptr->zone_fs_type) > 0) { 2000 if ((fetchprop(cur, DTD_ATTR_TYPE, type, 2001 sizeof (type)) == Z_OK)) { 2002 if (strcmp(tabptr->zone_fs_type, type) == 0) { 2003 if (firstmatch == NULL) 2004 firstmatch = cur; 2005 else if (firstmatch != cur) 2006 return (Z_INSUFFICIENT_SPEC); 2007 } else { 2008 /* 2009 * If another property matched but this 2010 * one doesn't then reset firstmatch. 2011 */ 2012 if (firstmatch == cur) 2013 firstmatch = NULL; 2014 } 2015 } 2016 } 2017 } 2018 2019 if (firstmatch == NULL) 2020 return (Z_NO_RESOURCE_ID); 2021 2022 cur = firstmatch; 2023 2024 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 2025 sizeof (tabptr->zone_fs_dir))) != Z_OK) 2026 return (err); 2027 2028 if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special, 2029 sizeof (tabptr->zone_fs_special))) != Z_OK) 2030 return (err); 2031 2032 if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw, 2033 sizeof (tabptr->zone_fs_raw))) != Z_OK) 2034 return (err); 2035 2036 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type, 2037 sizeof (tabptr->zone_fs_type))) != Z_OK) 2038 return (err); 2039 2040 /* options are optional */ 2041 tabptr->zone_fs_options = NULL; 2042 for (options = cur->xmlChildrenNode; options != NULL; 2043 options = options->next) { 2044 if ((fetchprop(options, DTD_ATTR_NAME, options_str, 2045 sizeof (options_str)) != Z_OK)) 2046 break; 2047 if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK) 2048 break; 2049 } 2050 return (Z_OK); 2051 } 2052 2053 int 2054 zonecfg_lookup_ipd(zone_dochandle_t handle, struct zone_fstab *tabptr) 2055 { 2056 xmlNodePtr cur, match; 2057 int err; 2058 char dirname[MAXPATHLEN]; 2059 2060 if (tabptr == NULL) 2061 return (Z_INVAL); 2062 2063 if ((err = operation_prep(handle)) != Z_OK) 2064 return (err); 2065 2066 /* 2067 * General algorithm: 2068 * Walk the list of children looking for matches on any properties 2069 * specified in the fstab parameter. If more than one resource 2070 * matches, we return Z_INSUFFICIENT_SPEC; if none match, we return 2071 * Z_NO_RESOURCE_ID. 2072 */ 2073 cur = handle->zone_dh_cur; 2074 match = NULL; 2075 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2076 if (xmlStrcmp(cur->name, DTD_ELEM_IPD)) 2077 continue; 2078 if (strlen(tabptr->zone_fs_dir) > 0) { 2079 if ((fetchprop(cur, DTD_ATTR_DIR, dirname, 2080 sizeof (dirname)) == Z_OK) && 2081 (strcmp(tabptr->zone_fs_dir, dirname) == 0)) { 2082 if (match == NULL) 2083 match = cur; 2084 else 2085 return (Z_INSUFFICIENT_SPEC); 2086 } 2087 } 2088 } 2089 2090 if (match == NULL) 2091 return (Z_NO_RESOURCE_ID); 2092 2093 cur = match; 2094 2095 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 2096 sizeof (tabptr->zone_fs_dir))) != Z_OK) 2097 return (err); 2098 2099 return (Z_OK); 2100 } 2101 2102 /* 2103 * Compare two IP addresses in string form. Allow for the possibility that 2104 * one might have "/<prefix-length>" at the end: allow a match on just the 2105 * IP address (or host name) part. 2106 */ 2107 2108 boolean_t 2109 zonecfg_same_net_address(char *a1, char *a2) 2110 { 2111 char *slashp, *slashp1, *slashp2; 2112 int result; 2113 2114 if (strcmp(a1, a2) == 0) 2115 return (B_TRUE); 2116 2117 /* 2118 * If neither has a slash or both do, they need to match to be 2119 * considered the same, but they did not match above, so fail. 2120 */ 2121 slashp1 = strchr(a1, '/'); 2122 slashp2 = strchr(a2, '/'); 2123 if ((slashp1 == NULL && slashp2 == NULL) || 2124 (slashp1 != NULL && slashp2 != NULL)) 2125 return (B_FALSE); 2126 2127 /* 2128 * Only one had a slash: pick that one, zero out the slash, compare 2129 * the "address only" strings, restore the slash, and return the 2130 * result of the comparison. 2131 */ 2132 slashp = (slashp1 == NULL) ? slashp2 : slashp1; 2133 *slashp = '\0'; 2134 result = strcmp(a1, a2); 2135 *slashp = '/'; 2136 return ((result == 0)); 2137 } 2138 2139 int 2140 zonecfg_valid_net_address(char *address, struct lifreq *lifr) 2141 { 2142 struct sockaddr_in *sin4; 2143 struct sockaddr_in6 *sin6; 2144 struct addrinfo hints, *result; 2145 char *slashp = strchr(address, '/'); 2146 2147 bzero(lifr, sizeof (struct lifreq)); 2148 sin4 = (struct sockaddr_in *)&lifr->lifr_addr; 2149 sin6 = (struct sockaddr_in6 *)&lifr->lifr_addr; 2150 if (slashp != NULL) 2151 *slashp = '\0'; 2152 if (inet_pton(AF_INET, address, &sin4->sin_addr) == 1) { 2153 sin4->sin_family = AF_INET; 2154 } else if (inet_pton(AF_INET6, address, &sin6->sin6_addr) == 1) { 2155 if (slashp == NULL) 2156 return (Z_IPV6_ADDR_PREFIX_LEN); 2157 sin6->sin6_family = AF_INET6; 2158 } else { 2159 /* "address" may be a host name */ 2160 (void) memset(&hints, 0, sizeof (hints)); 2161 hints.ai_family = PF_INET; 2162 if (getaddrinfo(address, NULL, &hints, &result) != 0) 2163 return (Z_BOGUS_ADDRESS); 2164 sin4->sin_family = result->ai_family; 2165 2166 (void) memcpy(&sin4->sin_addr, 2167 /* LINTED E_BAD_PTR_CAST_ALIGN */ 2168 &((struct sockaddr_in *)result->ai_addr)->sin_addr, 2169 sizeof (struct in_addr)); 2170 2171 freeaddrinfo(result); 2172 } 2173 return (Z_OK); 2174 } 2175 2176 boolean_t 2177 zonecfg_ifname_exists(sa_family_t af, char *ifname) 2178 { 2179 struct lifreq lifr; 2180 int so; 2181 int save_errno; 2182 2183 (void) memset(&lifr, 0, sizeof (lifr)); 2184 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 2185 lifr.lifr_addr.ss_family = af; 2186 if ((so = socket(af, SOCK_DGRAM, 0)) < 0) { 2187 /* Odd - can't tell if the ifname exists */ 2188 return (B_FALSE); 2189 } 2190 if (ioctl(so, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 2191 save_errno = errno; 2192 (void) close(so); 2193 errno = save_errno; 2194 return (B_FALSE); 2195 } 2196 (void) close(so); 2197 return (B_TRUE); 2198 } 2199 2200 /* 2201 * Determines whether there is a net resource with the physical interface, IP 2202 * address, and default router specified by 'tabptr' in the zone configuration 2203 * to which 'handle' refers. 'tabptr' must have an interface, an address, a 2204 * default router, or a combination of the three. This function returns Z_OK 2205 * iff there is exactly one net resource matching the query specified by 2206 * 'tabptr'. The function returns Z_INSUFFICIENT_SPEC if there are multiple 2207 * matches or 'tabptr' does not specify a physical interface, address, or 2208 * default router. The function returns Z_NO_RESOURCE_ID if are no matches. 2209 * 2210 * Errors might also be returned if the entry that exactly matches the 2211 * query lacks critical network resource information. 2212 * 2213 * If there is a single match, then the matching entry's physical interface, IP 2214 * address, and default router information are stored in 'tabptr'. 2215 */ 2216 int 2217 zonecfg_lookup_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2218 { 2219 xmlNodePtr cur; 2220 xmlNodePtr firstmatch; 2221 int err; 2222 char address[INET6_ADDRSTRLEN]; 2223 char physical[LIFNAMSIZ]; 2224 size_t addrspec; /* nonzero if tabptr has IP addr */ 2225 size_t physspec; /* nonzero if tabptr has interface */ 2226 size_t defrouterspec; /* nonzero if tabptr has def. router */ 2227 2228 if (tabptr == NULL) 2229 return (Z_INVAL); 2230 2231 /* 2232 * Determine the fields that will be searched. There must be at least 2233 * one. 2234 * 2235 * zone_nwif_address, zone_nwif_physical, and zone_nwif_defrouter are 2236 * arrays, so no NULL checks are necessary. 2237 */ 2238 addrspec = strlen(tabptr->zone_nwif_address); 2239 physspec = strlen(tabptr->zone_nwif_physical); 2240 defrouterspec = strlen(tabptr->zone_nwif_defrouter); 2241 if (addrspec == 0 && physspec == 0 && defrouterspec == 0) 2242 return (Z_INSUFFICIENT_SPEC); 2243 2244 if ((err = operation_prep(handle)) != Z_OK) 2245 return (err); 2246 2247 /* 2248 * Iterate over the configuration's elements and look for net elements 2249 * that match the query. 2250 */ 2251 firstmatch = NULL; 2252 cur = handle->zone_dh_cur; 2253 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2254 /* Skip non-net elements */ 2255 if (xmlStrcmp(cur->name, DTD_ELEM_NET)) 2256 continue; 2257 2258 /* 2259 * If any relevant fields don't match the query, then skip 2260 * the current net element. 2261 */ 2262 if (physspec != 0 && (fetchprop(cur, DTD_ATTR_PHYSICAL, 2263 physical, sizeof (physical)) != Z_OK || 2264 strcmp(tabptr->zone_nwif_physical, physical) != 0)) 2265 continue; 2266 if (addrspec != 0 && (fetchprop(cur, DTD_ATTR_ADDRESS, address, 2267 sizeof (address)) != Z_OK || 2268 !zonecfg_same_net_address(tabptr->zone_nwif_address, 2269 address))) 2270 continue; 2271 if (defrouterspec != 0 && (fetchprop(cur, DTD_ATTR_DEFROUTER, 2272 address, sizeof (address)) != Z_OK || 2273 !zonecfg_same_net_address(tabptr->zone_nwif_defrouter, 2274 address))) 2275 continue; 2276 2277 /* 2278 * The current net element matches the query. Select it if 2279 * it's the first match; otherwise, abort the search. 2280 */ 2281 if (firstmatch == NULL) 2282 firstmatch = cur; 2283 else 2284 return (Z_INSUFFICIENT_SPEC); 2285 } 2286 if (firstmatch == NULL) 2287 return (Z_NO_RESOURCE_ID); 2288 2289 cur = firstmatch; 2290 2291 if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical, 2292 sizeof (tabptr->zone_nwif_physical))) != Z_OK) 2293 return (err); 2294 2295 if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address, 2296 sizeof (tabptr->zone_nwif_address))) != Z_OK) 2297 return (err); 2298 2299 if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER, 2300 tabptr->zone_nwif_defrouter, 2301 sizeof (tabptr->zone_nwif_defrouter))) != Z_OK) 2302 return (err); 2303 2304 return (Z_OK); 2305 } 2306 2307 static int 2308 zonecfg_add_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2309 { 2310 xmlNodePtr newnode, cur = handle->zone_dh_cur; 2311 int err; 2312 2313 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_NET, NULL); 2314 if ((err = newprop(newnode, DTD_ATTR_ADDRESS, 2315 tabptr->zone_nwif_address)) != Z_OK) 2316 return (err); 2317 if ((err = newprop(newnode, DTD_ATTR_PHYSICAL, 2318 tabptr->zone_nwif_physical)) != Z_OK) 2319 return (err); 2320 /* 2321 * Do not add this property when it is not set, for backwards 2322 * compatibility and because it is optional. 2323 */ 2324 if ((strlen(tabptr->zone_nwif_defrouter) > 0) && 2325 ((err = newprop(newnode, DTD_ATTR_DEFROUTER, 2326 tabptr->zone_nwif_defrouter)) != Z_OK)) 2327 return (err); 2328 return (Z_OK); 2329 } 2330 2331 int 2332 zonecfg_add_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2333 { 2334 int err; 2335 2336 if (tabptr == NULL) 2337 return (Z_INVAL); 2338 2339 if ((err = operation_prep(handle)) != Z_OK) 2340 return (err); 2341 2342 if ((err = zonecfg_add_nwif_core(handle, tabptr)) != Z_OK) 2343 return (err); 2344 2345 return (Z_OK); 2346 } 2347 2348 static int 2349 zonecfg_delete_nwif_core(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2350 { 2351 xmlNodePtr cur = handle->zone_dh_cur; 2352 boolean_t addr_match, phys_match; 2353 2354 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2355 if (xmlStrcmp(cur->name, DTD_ELEM_NET)) 2356 continue; 2357 2358 addr_match = match_prop(cur, DTD_ATTR_ADDRESS, 2359 tabptr->zone_nwif_address); 2360 phys_match = match_prop(cur, DTD_ATTR_PHYSICAL, 2361 tabptr->zone_nwif_physical); 2362 2363 if (addr_match && phys_match) { 2364 xmlUnlinkNode(cur); 2365 xmlFreeNode(cur); 2366 return (Z_OK); 2367 } 2368 } 2369 return (Z_NO_RESOURCE_ID); 2370 } 2371 2372 int 2373 zonecfg_delete_nwif(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 2374 { 2375 int err; 2376 2377 if (tabptr == NULL) 2378 return (Z_INVAL); 2379 2380 if ((err = operation_prep(handle)) != Z_OK) 2381 return (err); 2382 2383 if ((err = zonecfg_delete_nwif_core(handle, tabptr)) != Z_OK) 2384 return (err); 2385 2386 return (Z_OK); 2387 } 2388 2389 int 2390 zonecfg_modify_nwif( 2391 zone_dochandle_t handle, 2392 struct zone_nwiftab *oldtabptr, 2393 struct zone_nwiftab *newtabptr) 2394 { 2395 int err; 2396 2397 if (oldtabptr == NULL || newtabptr == NULL) 2398 return (Z_INVAL); 2399 2400 if ((err = operation_prep(handle)) != Z_OK) 2401 return (err); 2402 2403 if ((err = zonecfg_delete_nwif_core(handle, oldtabptr)) != Z_OK) 2404 return (err); 2405 2406 if ((err = zonecfg_add_nwif_core(handle, newtabptr)) != Z_OK) 2407 return (err); 2408 2409 return (Z_OK); 2410 } 2411 2412 /* 2413 * Must be a comma-separated list of alpha-numeric file system names. 2414 */ 2415 static int 2416 zonecfg_valid_fs_allowed(const char *fsallowedp) 2417 { 2418 char tmp[ZONE_FS_ALLOWED_MAX]; 2419 char *cp = tmp; 2420 char *p; 2421 2422 if (strlen(fsallowedp) > ZONE_FS_ALLOWED_MAX) 2423 return (Z_TOO_BIG); 2424 2425 (void) strlcpy(tmp, fsallowedp, sizeof (tmp)); 2426 2427 while (*cp != '\0') { 2428 p = cp; 2429 while (*p != '\0' && *p != ',') { 2430 if (!isalnum(*p)) 2431 return (Z_INVALID_PROPERTY); 2432 p++; 2433 } 2434 2435 if (*p == ',') { 2436 if (p == cp) 2437 return (Z_INVALID_PROPERTY); 2438 2439 p++; 2440 2441 if (*p == '\0') 2442 return (Z_INVALID_PROPERTY); 2443 } 2444 2445 cp = p; 2446 } 2447 2448 return (Z_OK); 2449 } 2450 2451 int 2452 zonecfg_get_fs_allowed(zone_dochandle_t handle, char *bufp, size_t buflen) 2453 { 2454 int err; 2455 2456 if ((err = getrootattr(handle, DTD_ATTR_FS_ALLOWED, 2457 bufp, buflen)) != Z_OK) 2458 return (err); 2459 if (bufp[0] == '\0') 2460 return (Z_BAD_PROPERTY); 2461 return (zonecfg_valid_fs_allowed(bufp)); 2462 } 2463 2464 int 2465 zonecfg_set_fs_allowed(zone_dochandle_t handle, const char *bufp) 2466 { 2467 int err; 2468 2469 if (bufp == NULL || (err = zonecfg_valid_fs_allowed(bufp)) == Z_OK) 2470 return (setrootattr(handle, DTD_ATTR_FS_ALLOWED, bufp)); 2471 return (err); 2472 } 2473 2474 /* 2475 * Determines if the specified string is a valid hostid string. This function 2476 * returns Z_OK if the string is a valid hostid string. It returns Z_INVAL if 2477 * 'hostidp' is NULL, Z_TOO_BIG if 'hostidp' refers to a string buffer 2478 * containing a hex string with more than 8 digits, and Z_INVALID_PROPERTY if 2479 * the string has an invalid format. 2480 */ 2481 static int 2482 zonecfg_valid_hostid(const char *hostidp) 2483 { 2484 char *currentp; 2485 u_longlong_t hostidval; 2486 size_t len; 2487 2488 if (hostidp == NULL) 2489 return (Z_INVAL); 2490 2491 /* Empty strings and strings with whitespace are invalid. */ 2492 if (*hostidp == '\0') 2493 return (Z_INVALID_PROPERTY); 2494 for (currentp = (char *)hostidp; *currentp != '\0'; ++currentp) { 2495 if (isspace(*currentp)) 2496 return (Z_INVALID_PROPERTY); 2497 } 2498 len = (size_t)(currentp - hostidp); 2499 2500 /* 2501 * The caller might pass a hostid that is larger than the maximum 2502 * unsigned 32-bit integral value. Check for this! Also, make sure 2503 * that the whole string is converted (this helps us find illegal 2504 * characters) and that the whole string fits within a buffer of size 2505 * HW_HOSTID_LEN. 2506 */ 2507 currentp = (char *)hostidp; 2508 if (strncmp(hostidp, "0x", 2) == 0 || strncmp(hostidp, "0X", 2) == 0) 2509 currentp += 2; 2510 hostidval = strtoull(currentp, ¤tp, 16); 2511 if ((size_t)(currentp - hostidp) >= HW_HOSTID_LEN) 2512 return (Z_TOO_BIG); 2513 if (hostidval > UINT_MAX || hostidval == HW_INVALID_HOSTID || 2514 currentp != hostidp + len) 2515 return (Z_INVALID_PROPERTY); 2516 return (Z_OK); 2517 } 2518 2519 /* 2520 * Gets the zone hostid string stored in the specified zone configuration 2521 * document. This function returns Z_OK on success. Z_BAD_PROPERTY is returned 2522 * if the config file doesn't specify a hostid or if the hostid is blank. 2523 * 2524 * Note that buflen should be at least HW_HOSTID_LEN. 2525 */ 2526 int 2527 zonecfg_get_hostid(zone_dochandle_t handle, char *bufp, size_t buflen) 2528 { 2529 int err; 2530 2531 if ((err = getrootattr(handle, DTD_ATTR_HOSTID, bufp, buflen)) != Z_OK) 2532 return (err); 2533 if (bufp[0] == '\0') 2534 return (Z_BAD_PROPERTY); 2535 return (zonecfg_valid_hostid(bufp)); 2536 } 2537 2538 /* 2539 * Sets the hostid string in the specified zone config document to the given 2540 * string value. If 'hostidp' is NULL, then the config document's hostid 2541 * attribute is cleared. Non-NULL hostids are validated. This function returns 2542 * Z_OK on success. Any other return value indicates failure. 2543 */ 2544 int 2545 zonecfg_set_hostid(zone_dochandle_t handle, const char *hostidp) 2546 { 2547 int err; 2548 2549 /* 2550 * A NULL hostid string is interpreted as a request to clear the 2551 * hostid. 2552 */ 2553 if (hostidp == NULL || (err = zonecfg_valid_hostid(hostidp)) == Z_OK) 2554 return (setrootattr(handle, DTD_ATTR_HOSTID, hostidp)); 2555 return (err); 2556 } 2557 2558 int 2559 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 2560 { 2561 xmlNodePtr cur, firstmatch; 2562 int err; 2563 char match[MAXPATHLEN]; 2564 2565 if (tabptr == NULL) 2566 return (Z_INVAL); 2567 2568 if ((err = operation_prep(handle)) != Z_OK) 2569 return (err); 2570 2571 cur = handle->zone_dh_cur; 2572 firstmatch = NULL; 2573 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2574 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 2575 continue; 2576 if (strlen(tabptr->zone_dev_match) == 0) 2577 continue; 2578 2579 if ((fetchprop(cur, DTD_ATTR_MATCH, match, 2580 sizeof (match)) == Z_OK)) { 2581 if (strcmp(tabptr->zone_dev_match, 2582 match) == 0) { 2583 if (firstmatch == NULL) 2584 firstmatch = cur; 2585 else if (firstmatch != cur) 2586 return (Z_INSUFFICIENT_SPEC); 2587 } else { 2588 /* 2589 * If another property matched but this 2590 * one doesn't then reset firstmatch. 2591 */ 2592 if (firstmatch == cur) 2593 firstmatch = NULL; 2594 } 2595 } 2596 } 2597 if (firstmatch == NULL) 2598 return (Z_NO_RESOURCE_ID); 2599 2600 cur = firstmatch; 2601 2602 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match, 2603 sizeof (tabptr->zone_dev_match))) != Z_OK) 2604 return (err); 2605 2606 return (Z_OK); 2607 } 2608 2609 static int 2610 zonecfg_add_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr) 2611 { 2612 xmlNodePtr newnode, cur = handle->zone_dh_cur; 2613 int err; 2614 2615 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEVICE, NULL); 2616 2617 if ((err = newprop(newnode, DTD_ATTR_MATCH, 2618 tabptr->zone_dev_match)) != Z_OK) 2619 return (err); 2620 2621 return (Z_OK); 2622 } 2623 2624 int 2625 zonecfg_add_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 2626 { 2627 int err; 2628 2629 if (tabptr == NULL) 2630 return (Z_INVAL); 2631 2632 if ((err = operation_prep(handle)) != Z_OK) 2633 return (err); 2634 2635 if ((err = zonecfg_add_dev_core(handle, tabptr)) != Z_OK) 2636 return (err); 2637 2638 return (Z_OK); 2639 } 2640 2641 static int 2642 zonecfg_delete_dev_core(zone_dochandle_t handle, struct zone_devtab *tabptr) 2643 { 2644 xmlNodePtr cur = handle->zone_dh_cur; 2645 int match_match; 2646 2647 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2648 if (xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 2649 continue; 2650 2651 match_match = match_prop(cur, DTD_ATTR_MATCH, 2652 tabptr->zone_dev_match); 2653 2654 if (match_match) { 2655 xmlUnlinkNode(cur); 2656 xmlFreeNode(cur); 2657 return (Z_OK); 2658 } 2659 } 2660 return (Z_NO_RESOURCE_ID); 2661 } 2662 2663 int 2664 zonecfg_delete_dev(zone_dochandle_t handle, struct zone_devtab *tabptr) 2665 { 2666 int err; 2667 2668 if (tabptr == NULL) 2669 return (Z_INVAL); 2670 2671 if ((err = operation_prep(handle)) != Z_OK) 2672 return (err); 2673 2674 if ((err = zonecfg_delete_dev_core(handle, tabptr)) != Z_OK) 2675 return (err); 2676 2677 return (Z_OK); 2678 } 2679 2680 int 2681 zonecfg_modify_dev( 2682 zone_dochandle_t handle, 2683 struct zone_devtab *oldtabptr, 2684 struct zone_devtab *newtabptr) 2685 { 2686 int err; 2687 2688 if (oldtabptr == NULL || newtabptr == NULL) 2689 return (Z_INVAL); 2690 2691 if ((err = operation_prep(handle)) != Z_OK) 2692 return (err); 2693 2694 if ((err = zonecfg_delete_dev_core(handle, oldtabptr)) != Z_OK) 2695 return (err); 2696 2697 if ((err = zonecfg_add_dev_core(handle, newtabptr)) != Z_OK) 2698 return (err); 2699 2700 return (Z_OK); 2701 } 2702 2703 static int 2704 zonecfg_add_auth_core(zone_dochandle_t handle, struct zone_admintab *tabptr, 2705 char *zonename) 2706 { 2707 xmlNodePtr newnode, cur = handle->zone_dh_cur; 2708 int err; 2709 2710 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ADMIN, NULL); 2711 err = newprop(newnode, DTD_ATTR_USER, tabptr->zone_admin_user); 2712 if (err != Z_OK) 2713 return (err); 2714 err = newprop(newnode, DTD_ATTR_AUTHS, tabptr->zone_admin_auths); 2715 if (err != Z_OK) 2716 return (err); 2717 if ((err = zonecfg_remove_userauths( 2718 handle, tabptr->zone_admin_user, zonename, B_FALSE)) != Z_OK) 2719 return (err); 2720 return (Z_OK); 2721 } 2722 2723 int 2724 zonecfg_add_admin(zone_dochandle_t handle, struct zone_admintab *tabptr, 2725 char *zonename) 2726 { 2727 int err; 2728 2729 if (tabptr == NULL) 2730 return (Z_INVAL); 2731 2732 if ((err = operation_prep(handle)) != Z_OK) 2733 return (err); 2734 2735 if ((err = zonecfg_add_auth_core(handle, tabptr, 2736 zonename)) != Z_OK) 2737 return (err); 2738 2739 return (Z_OK); 2740 } 2741 static int 2742 zonecfg_delete_auth_core(zone_dochandle_t handle, struct zone_admintab *tabptr, 2743 char *zonename) 2744 { 2745 xmlNodePtr cur = handle->zone_dh_cur; 2746 boolean_t auth_match; 2747 int err; 2748 2749 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2750 if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN)) 2751 continue; 2752 auth_match = match_prop(cur, DTD_ATTR_USER, 2753 tabptr->zone_admin_user); 2754 if (auth_match) { 2755 if ((err = zonecfg_insert_userauths( 2756 handle, tabptr->zone_admin_user, 2757 zonename)) != Z_OK) 2758 return (err); 2759 xmlUnlinkNode(cur); 2760 xmlFreeNode(cur); 2761 return (Z_OK); 2762 } 2763 } 2764 return (Z_NO_RESOURCE_ID); 2765 } 2766 2767 int 2768 zonecfg_delete_admin(zone_dochandle_t handle, struct zone_admintab *tabptr, 2769 char *zonename) 2770 { 2771 int err; 2772 2773 if (tabptr == NULL) 2774 return (Z_INVAL); 2775 2776 if ((err = operation_prep(handle)) != Z_OK) 2777 return (err); 2778 2779 if ((err = zonecfg_delete_auth_core(handle, tabptr, zonename)) != Z_OK) 2780 return (err); 2781 2782 return (Z_OK); 2783 } 2784 2785 int 2786 zonecfg_modify_admin(zone_dochandle_t handle, struct zone_admintab *oldtabptr, 2787 struct zone_admintab *newtabptr, char *zonename) 2788 { 2789 int err; 2790 2791 if (oldtabptr == NULL || newtabptr == NULL) 2792 return (Z_INVAL); 2793 2794 if ((err = operation_prep(handle)) != Z_OK) 2795 return (err); 2796 2797 if ((err = zonecfg_delete_auth_core(handle, oldtabptr, zonename)) 2798 != Z_OK) 2799 return (err); 2800 2801 if ((err = zonecfg_add_auth_core(handle, newtabptr, 2802 zonename)) != Z_OK) 2803 return (err); 2804 2805 return (Z_OK); 2806 } 2807 2808 int 2809 zonecfg_lookup_admin(zone_dochandle_t handle, struct zone_admintab *tabptr) 2810 { 2811 xmlNodePtr cur, firstmatch; 2812 int err; 2813 char user[MAXUSERNAME]; 2814 2815 if (tabptr == NULL) 2816 return (Z_INVAL); 2817 2818 if ((err = operation_prep(handle)) != Z_OK) 2819 return (err); 2820 2821 cur = handle->zone_dh_cur; 2822 firstmatch = NULL; 2823 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 2824 if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN)) 2825 continue; 2826 if (strlen(tabptr->zone_admin_user) > 0) { 2827 if ((fetchprop(cur, DTD_ATTR_USER, user, 2828 sizeof (user)) == Z_OK) && 2829 (strcmp(tabptr->zone_admin_user, user) == 0)) { 2830 if (firstmatch == NULL) 2831 firstmatch = cur; 2832 else 2833 return (Z_INSUFFICIENT_SPEC); 2834 } 2835 } 2836 } 2837 if (firstmatch == NULL) 2838 return (Z_NO_RESOURCE_ID); 2839 2840 cur = firstmatch; 2841 2842 if ((err = fetchprop(cur, DTD_ATTR_USER, tabptr->zone_admin_user, 2843 sizeof (tabptr->zone_admin_user))) != Z_OK) 2844 return (err); 2845 2846 if ((err = fetchprop(cur, DTD_ATTR_AUTHS, tabptr->zone_admin_auths, 2847 sizeof (tabptr->zone_admin_auths))) != Z_OK) 2848 return (err); 2849 2850 return (Z_OK); 2851 } 2852 2853 2854 /* Lock to serialize all devwalks */ 2855 static pthread_mutex_t zonecfg_devwalk_lock = PTHREAD_MUTEX_INITIALIZER; 2856 /* 2857 * Global variables used to pass data from zonecfg_dev_manifest to the nftw 2858 * call-back (zonecfg_devwalk_cb). g_devwalk_data is really the void* 2859 * parameter and g_devwalk_cb is really the *cb parameter from 2860 * zonecfg_dev_manifest. 2861 */ 2862 typedef struct __g_devwalk_data *g_devwalk_data_t; 2863 static g_devwalk_data_t g_devwalk_data; 2864 static int (*g_devwalk_cb)(const char *, uid_t, gid_t, mode_t, const char *, 2865 void *); 2866 static size_t g_devwalk_skip_prefix; 2867 2868 /* 2869 * zonecfg_dev_manifest call-back function used during detach to generate the 2870 * dev info in the manifest. 2871 */ 2872 static int 2873 get_detach_dev_entry(const char *name, uid_t uid, gid_t gid, mode_t mode, 2874 const char *acl, void *hdl) 2875 { 2876 zone_dochandle_t handle = (zone_dochandle_t)hdl; 2877 xmlNodePtr newnode; 2878 xmlNodePtr cur; 2879 int err; 2880 char buf[128]; 2881 2882 if ((err = operation_prep(handle)) != Z_OK) 2883 return (err); 2884 2885 cur = handle->zone_dh_cur; 2886 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DEV_PERM, NULL); 2887 if ((err = newprop(newnode, DTD_ATTR_NAME, (char *)name)) != Z_OK) 2888 return (err); 2889 (void) snprintf(buf, sizeof (buf), "%lu", uid); 2890 if ((err = newprop(newnode, DTD_ATTR_UID, buf)) != Z_OK) 2891 return (err); 2892 (void) snprintf(buf, sizeof (buf), "%lu", gid); 2893 if ((err = newprop(newnode, DTD_ATTR_GID, buf)) != Z_OK) 2894 return (err); 2895 (void) snprintf(buf, sizeof (buf), "%o", mode); 2896 if ((err = newprop(newnode, DTD_ATTR_MODE, buf)) != Z_OK) 2897 return (err); 2898 if ((err = newprop(newnode, DTD_ATTR_ACL, (char *)acl)) != Z_OK) 2899 return (err); 2900 return (Z_OK); 2901 } 2902 2903 /* 2904 * This is the nftw call-back function used by zonecfg_dev_manifest. It is 2905 * responsible for calling the actual call-back. 2906 */ 2907 /* ARGSUSED2 */ 2908 static int 2909 zonecfg_devwalk_cb(const char *path, const struct stat *st, int f, 2910 struct FTW *ftw) 2911 { 2912 acl_t *acl; 2913 char *acl_txt = NULL; 2914 2915 /* skip all but character and block devices */ 2916 if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode)) 2917 return (0); 2918 2919 if ((acl_get(path, ACL_NO_TRIVIAL, &acl) == 0) && 2920 acl != NULL) { 2921 acl_txt = acl_totext(acl, ACL_NORESOLVE); 2922 acl_free(acl); 2923 } 2924 2925 if (strlen(path) <= g_devwalk_skip_prefix) 2926 return (0); 2927 2928 g_devwalk_cb(path + g_devwalk_skip_prefix, st->st_uid, st->st_gid, 2929 st->st_mode & S_IAMB, acl_txt != NULL ? acl_txt : "", 2930 g_devwalk_data); 2931 free(acl_txt); 2932 return (0); 2933 } 2934 2935 /* 2936 * Walk the dev tree for the zone specified by hdl and call the 2937 * get_detach_dev_entry call-back function for each entry in the tree. The 2938 * call-back will be passed the name, uid, gid, mode, acl string and the 2939 * handle input parameter for each dev entry. 2940 * 2941 * Data is passed to get_detach_dev_entry through the global variables 2942 * g_devwalk_data, *g_devwalk_cb, and g_devwalk_skip_prefix. The 2943 * zonecfg_devwalk_cb function will actually call get_detach_dev_entry. 2944 */ 2945 int 2946 zonecfg_dev_manifest(zone_dochandle_t hdl) 2947 { 2948 char path[MAXPATHLEN]; 2949 int ret; 2950 2951 if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK) 2952 return (ret); 2953 2954 if (strlcat(path, "/dev", sizeof (path)) >= sizeof (path)) 2955 return (Z_TOO_BIG); 2956 2957 /* 2958 * We have to serialize all devwalks in the same process 2959 * (which should be fine), since nftw() is so badly designed. 2960 */ 2961 (void) pthread_mutex_lock(&zonecfg_devwalk_lock); 2962 2963 g_devwalk_skip_prefix = strlen(path) + 1; 2964 g_devwalk_data = (g_devwalk_data_t)hdl; 2965 g_devwalk_cb = get_detach_dev_entry; 2966 (void) nftw(path, zonecfg_devwalk_cb, 0, FTW_PHYS); 2967 2968 (void) pthread_mutex_unlock(&zonecfg_devwalk_lock); 2969 return (Z_OK); 2970 } 2971 2972 /* 2973 * Update the owner, group, mode and acl on the specified dev (inpath) for 2974 * the zone (hdl). This function can be used to fix up the dev tree after 2975 * attaching a migrated zone. 2976 */ 2977 int 2978 zonecfg_devperms_apply(zone_dochandle_t hdl, const char *inpath, uid_t owner, 2979 gid_t group, mode_t mode, const char *acltxt) 2980 { 2981 int ret; 2982 char path[MAXPATHLEN]; 2983 struct stat st; 2984 acl_t *aclp; 2985 2986 if ((ret = zonecfg_get_zonepath(hdl, path, sizeof (path))) != Z_OK) 2987 return (ret); 2988 2989 if (strlcat(path, "/dev/", sizeof (path)) >= sizeof (path)) 2990 return (Z_TOO_BIG); 2991 if (strlcat(path, inpath, sizeof (path)) >= sizeof (path)) 2992 return (Z_TOO_BIG); 2993 2994 if (stat(path, &st) == -1) 2995 return (Z_INVAL); 2996 2997 /* make sure we're only touching device nodes */ 2998 if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) 2999 return (Z_INVAL); 3000 3001 if (chown(path, owner, group) == -1) 3002 return (Z_SYSTEM); 3003 3004 if (chmod(path, mode) == -1) 3005 return (Z_SYSTEM); 3006 3007 if ((acltxt == NULL) || (strcmp(acltxt, "") == 0)) 3008 return (Z_OK); 3009 3010 if (acl_fromtext(acltxt, &aclp) != 0) { 3011 errno = EINVAL; 3012 return (Z_SYSTEM); 3013 } 3014 3015 errno = 0; 3016 if (acl_set(path, aclp) == -1) { 3017 free(aclp); 3018 return (Z_SYSTEM); 3019 } 3020 3021 free(aclp); 3022 return (Z_OK); 3023 } 3024 3025 /* 3026 * This function finds everything mounted under a zone's rootpath. 3027 * This returns the number of mounts under rootpath, or -1 on error. 3028 * callback is called once per mount found with the first argument 3029 * pointing to a mnttab structure containing the mount's information. 3030 * 3031 * If the callback function returns non-zero zonecfg_find_mounts 3032 * aborts with an error. 3033 */ 3034 int 3035 zonecfg_find_mounts(char *rootpath, int (*callback)(const struct mnttab *, 3036 void *), void *priv) { 3037 FILE *mnttab; 3038 struct mnttab m; 3039 size_t l; 3040 int zfsl; 3041 int rv = 0; 3042 char zfs_path[MAXPATHLEN]; 3043 3044 assert(rootpath != NULL); 3045 3046 if ((zfsl = snprintf(zfs_path, sizeof (zfs_path), "%s/.zfs/", rootpath)) 3047 >= sizeof (zfs_path)) 3048 return (-1); 3049 3050 l = strlen(rootpath); 3051 3052 mnttab = fopen("/etc/mnttab", "r"); 3053 3054 if (mnttab == NULL) 3055 return (-1); 3056 3057 if (ioctl(fileno(mnttab), MNTIOC_SHOWHIDDEN, NULL) < 0) { 3058 rv = -1; 3059 goto out; 3060 } 3061 3062 while (!getmntent(mnttab, &m)) { 3063 if ((strncmp(rootpath, m.mnt_mountp, l) == 0) && 3064 (m.mnt_mountp[l] == '/') && 3065 (strncmp(zfs_path, m.mnt_mountp, zfsl) != 0)) { 3066 rv++; 3067 if (callback == NULL) 3068 continue; 3069 if (callback(&m, priv)) { 3070 rv = -1; 3071 goto out; 3072 3073 } 3074 } 3075 } 3076 3077 out: 3078 (void) fclose(mnttab); 3079 return (rv); 3080 } 3081 3082 int 3083 zonecfg_lookup_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 3084 { 3085 xmlNodePtr cur, firstmatch; 3086 int err; 3087 char name[MAXNAMELEN], type[MAXNAMELEN], value[MAXNAMELEN]; 3088 3089 if (tabptr == NULL) 3090 return (Z_INVAL); 3091 3092 if ((err = operation_prep(handle)) != Z_OK) 3093 return (err); 3094 3095 cur = handle->zone_dh_cur; 3096 firstmatch = NULL; 3097 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 3098 if (xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 3099 continue; 3100 if (strlen(tabptr->zone_attr_name) > 0) { 3101 if ((fetchprop(cur, DTD_ATTR_NAME, name, 3102 sizeof (name)) == Z_OK) && 3103 (strcmp(tabptr->zone_attr_name, name) == 0)) { 3104 if (firstmatch == NULL) 3105 firstmatch = cur; 3106 else 3107 return (Z_INSUFFICIENT_SPEC); 3108 } 3109 } 3110 if (strlen(tabptr->zone_attr_type) > 0) { 3111 if ((fetchprop(cur, DTD_ATTR_TYPE, type, 3112 sizeof (type)) == Z_OK)) { 3113 if (strcmp(tabptr->zone_attr_type, type) == 0) { 3114 if (firstmatch == NULL) 3115 firstmatch = cur; 3116 else if (firstmatch != cur) 3117 return (Z_INSUFFICIENT_SPEC); 3118 } else { 3119 /* 3120 * If another property matched but this 3121 * one doesn't then reset firstmatch. 3122 */ 3123 if (firstmatch == cur) 3124 firstmatch = NULL; 3125 } 3126 } 3127 } 3128 if (strlen(tabptr->zone_attr_value) > 0) { 3129 if ((fetchprop(cur, DTD_ATTR_VALUE, value, 3130 sizeof (value)) == Z_OK)) { 3131 if (strcmp(tabptr->zone_attr_value, value) == 3132 0) { 3133 if (firstmatch == NULL) 3134 firstmatch = cur; 3135 else if (firstmatch != cur) 3136 return (Z_INSUFFICIENT_SPEC); 3137 } else { 3138 /* 3139 * If another property matched but this 3140 * one doesn't then reset firstmatch. 3141 */ 3142 if (firstmatch == cur) 3143 firstmatch = NULL; 3144 } 3145 } 3146 } 3147 } 3148 if (firstmatch == NULL) 3149 return (Z_NO_RESOURCE_ID); 3150 3151 cur = firstmatch; 3152 3153 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name, 3154 sizeof (tabptr->zone_attr_name))) != Z_OK) 3155 return (err); 3156 3157 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type, 3158 sizeof (tabptr->zone_attr_type))) != Z_OK) 3159 return (err); 3160 3161 if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value, 3162 sizeof (tabptr->zone_attr_value))) != Z_OK) 3163 return (err); 3164 3165 return (Z_OK); 3166 } 3167 3168 static int 3169 zonecfg_add_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr) 3170 { 3171 xmlNodePtr newnode, cur = handle->zone_dh_cur; 3172 int err; 3173 3174 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_ATTR, NULL); 3175 err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_attr_name); 3176 if (err != Z_OK) 3177 return (err); 3178 err = newprop(newnode, DTD_ATTR_TYPE, tabptr->zone_attr_type); 3179 if (err != Z_OK) 3180 return (err); 3181 err = newprop(newnode, DTD_ATTR_VALUE, tabptr->zone_attr_value); 3182 if (err != Z_OK) 3183 return (err); 3184 return (Z_OK); 3185 } 3186 3187 int 3188 zonecfg_add_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 3189 { 3190 int err; 3191 3192 if (tabptr == NULL) 3193 return (Z_INVAL); 3194 3195 if ((err = operation_prep(handle)) != Z_OK) 3196 return (err); 3197 3198 if ((err = zonecfg_add_attr_core(handle, tabptr)) != Z_OK) 3199 return (err); 3200 3201 return (Z_OK); 3202 } 3203 3204 static int 3205 zonecfg_delete_attr_core(zone_dochandle_t handle, struct zone_attrtab *tabptr) 3206 { 3207 xmlNodePtr cur = handle->zone_dh_cur; 3208 int name_match, type_match, value_match; 3209 3210 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 3211 if (xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 3212 continue; 3213 3214 name_match = match_prop(cur, DTD_ATTR_NAME, 3215 tabptr->zone_attr_name); 3216 type_match = match_prop(cur, DTD_ATTR_TYPE, 3217 tabptr->zone_attr_type); 3218 value_match = match_prop(cur, DTD_ATTR_VALUE, 3219 tabptr->zone_attr_value); 3220 3221 if (name_match && type_match && value_match) { 3222 xmlUnlinkNode(cur); 3223 xmlFreeNode(cur); 3224 return (Z_OK); 3225 } 3226 } 3227 return (Z_NO_RESOURCE_ID); 3228 } 3229 3230 int 3231 zonecfg_delete_attr(zone_dochandle_t handle, struct zone_attrtab *tabptr) 3232 { 3233 int err; 3234 3235 if (tabptr == NULL) 3236 return (Z_INVAL); 3237 3238 if ((err = operation_prep(handle)) != Z_OK) 3239 return (err); 3240 3241 if ((err = zonecfg_delete_attr_core(handle, tabptr)) != Z_OK) 3242 return (err); 3243 3244 return (Z_OK); 3245 } 3246 3247 int 3248 zonecfg_modify_attr( 3249 zone_dochandle_t handle, 3250 struct zone_attrtab *oldtabptr, 3251 struct zone_attrtab *newtabptr) 3252 { 3253 int err; 3254 3255 if (oldtabptr == NULL || newtabptr == NULL) 3256 return (Z_INVAL); 3257 3258 if ((err = operation_prep(handle)) != Z_OK) 3259 return (err); 3260 3261 if ((err = zonecfg_delete_attr_core(handle, oldtabptr)) != Z_OK) 3262 return (err); 3263 3264 if ((err = zonecfg_add_attr_core(handle, newtabptr)) != Z_OK) 3265 return (err); 3266 3267 return (Z_OK); 3268 } 3269 3270 int 3271 zonecfg_get_attr_boolean(const struct zone_attrtab *attr, boolean_t *value) 3272 { 3273 if (attr == NULL) 3274 return (Z_INVAL); 3275 3276 if (strcmp(attr->zone_attr_type, DTD_ENTITY_BOOLEAN) != 0) 3277 return (Z_INVAL); 3278 3279 if (strcmp(attr->zone_attr_value, DTD_ENTITY_TRUE) == 0) { 3280 *value = B_TRUE; 3281 return (Z_OK); 3282 } 3283 if (strcmp(attr->zone_attr_value, DTD_ENTITY_FALSE) == 0) { 3284 *value = B_FALSE; 3285 return (Z_OK); 3286 } 3287 return (Z_INVAL); 3288 } 3289 3290 int 3291 zonecfg_get_attr_int(const struct zone_attrtab *attr, int64_t *value) 3292 { 3293 long long result; 3294 char *endptr; 3295 3296 if (attr == NULL) 3297 return (Z_INVAL); 3298 3299 if (strcmp(attr->zone_attr_type, DTD_ENTITY_INT) != 0) 3300 return (Z_INVAL); 3301 3302 errno = 0; 3303 result = strtoll(attr->zone_attr_value, &endptr, 10); 3304 if (errno != 0 || *endptr != '\0') 3305 return (Z_INVAL); 3306 *value = result; 3307 return (Z_OK); 3308 } 3309 3310 int 3311 zonecfg_get_attr_string(const struct zone_attrtab *attr, char *value, 3312 size_t val_sz) 3313 { 3314 if (attr == NULL) 3315 return (Z_INVAL); 3316 3317 if (strcmp(attr->zone_attr_type, DTD_ENTITY_STRING) != 0) 3318 return (Z_INVAL); 3319 3320 if (strlcpy(value, attr->zone_attr_value, val_sz) >= val_sz) 3321 return (Z_TOO_BIG); 3322 return (Z_OK); 3323 } 3324 3325 int 3326 zonecfg_get_attr_uint(const struct zone_attrtab *attr, uint64_t *value) 3327 { 3328 unsigned long long result; 3329 long long neg_result; 3330 char *endptr; 3331 3332 if (attr == NULL) 3333 return (Z_INVAL); 3334 3335 if (strcmp(attr->zone_attr_type, DTD_ENTITY_UINT) != 0) 3336 return (Z_INVAL); 3337 3338 errno = 0; 3339 result = strtoull(attr->zone_attr_value, &endptr, 10); 3340 if (errno != 0 || *endptr != '\0') 3341 return (Z_INVAL); 3342 errno = 0; 3343 neg_result = strtoll(attr->zone_attr_value, &endptr, 10); 3344 /* 3345 * Incredibly, strtoull("<negative number>", ...) will not fail but 3346 * return whatever (negative) number cast as a u_longlong_t, so we 3347 * need to look for this here. 3348 */ 3349 if (errno == 0 && neg_result < 0) 3350 return (Z_INVAL); 3351 *value = result; 3352 return (Z_OK); 3353 } 3354 3355 int 3356 zonecfg_lookup_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 3357 { 3358 xmlNodePtr cur, val; 3359 char savedname[MAXNAMELEN]; 3360 struct zone_rctlvaltab *valptr; 3361 int err; 3362 3363 if (strlen(tabptr->zone_rctl_name) == 0) 3364 return (Z_INVAL); 3365 3366 if ((err = operation_prep(handle)) != Z_OK) 3367 return (err); 3368 3369 cur = handle->zone_dh_cur; 3370 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 3371 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 3372 continue; 3373 if ((fetchprop(cur, DTD_ATTR_NAME, savedname, 3374 sizeof (savedname)) == Z_OK) && 3375 (strcmp(savedname, tabptr->zone_rctl_name) == 0)) { 3376 tabptr->zone_rctl_valptr = NULL; 3377 for (val = cur->xmlChildrenNode; val != NULL; 3378 val = val->next) { 3379 valptr = (struct zone_rctlvaltab *)malloc( 3380 sizeof (struct zone_rctlvaltab)); 3381 if (valptr == NULL) 3382 return (Z_NOMEM); 3383 if ((fetchprop(val, DTD_ATTR_PRIV, 3384 valptr->zone_rctlval_priv, 3385 sizeof (valptr->zone_rctlval_priv)) != 3386 Z_OK)) 3387 break; 3388 if ((fetchprop(val, DTD_ATTR_LIMIT, 3389 valptr->zone_rctlval_limit, 3390 sizeof (valptr->zone_rctlval_limit)) != 3391 Z_OK)) 3392 break; 3393 if ((fetchprop(val, DTD_ATTR_ACTION, 3394 valptr->zone_rctlval_action, 3395 sizeof (valptr->zone_rctlval_action)) != 3396 Z_OK)) 3397 break; 3398 if (zonecfg_add_rctl_value(tabptr, valptr) != 3399 Z_OK) 3400 break; 3401 } 3402 return (Z_OK); 3403 } 3404 } 3405 return (Z_NO_RESOURCE_ID); 3406 } 3407 3408 static int 3409 zonecfg_add_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr) 3410 { 3411 xmlNodePtr newnode, cur = handle->zone_dh_cur, valnode; 3412 struct zone_rctlvaltab *valptr; 3413 int err; 3414 3415 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_RCTL, NULL); 3416 err = newprop(newnode, DTD_ATTR_NAME, tabptr->zone_rctl_name); 3417 if (err != Z_OK) 3418 return (err); 3419 for (valptr = tabptr->zone_rctl_valptr; valptr != NULL; 3420 valptr = valptr->zone_rctlval_next) { 3421 valnode = xmlNewTextChild(newnode, NULL, 3422 DTD_ELEM_RCTLVALUE, NULL); 3423 err = newprop(valnode, DTD_ATTR_PRIV, 3424 valptr->zone_rctlval_priv); 3425 if (err != Z_OK) 3426 return (err); 3427 err = newprop(valnode, DTD_ATTR_LIMIT, 3428 valptr->zone_rctlval_limit); 3429 if (err != Z_OK) 3430 return (err); 3431 err = newprop(valnode, DTD_ATTR_ACTION, 3432 valptr->zone_rctlval_action); 3433 if (err != Z_OK) 3434 return (err); 3435 } 3436 return (Z_OK); 3437 } 3438 3439 int 3440 zonecfg_add_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 3441 { 3442 int err; 3443 3444 if (tabptr == NULL) 3445 return (Z_INVAL); 3446 3447 if ((err = operation_prep(handle)) != Z_OK) 3448 return (err); 3449 3450 if ((err = zonecfg_add_rctl_core(handle, tabptr)) != Z_OK) 3451 return (err); 3452 3453 return (Z_OK); 3454 } 3455 3456 static int 3457 zonecfg_delete_rctl_core(zone_dochandle_t handle, struct zone_rctltab *tabptr) 3458 { 3459 xmlNodePtr cur = handle->zone_dh_cur; 3460 xmlChar *savedname; 3461 int name_result; 3462 3463 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 3464 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 3465 continue; 3466 3467 savedname = xmlGetProp(cur, DTD_ATTR_NAME); 3468 if (savedname == NULL) /* shouldn't happen */ 3469 continue; 3470 name_result = xmlStrcmp(savedname, 3471 (const xmlChar *) tabptr->zone_rctl_name); 3472 xmlFree(savedname); 3473 3474 if (name_result == 0) { 3475 xmlUnlinkNode(cur); 3476 xmlFreeNode(cur); 3477 return (Z_OK); 3478 } 3479 } 3480 return (Z_NO_RESOURCE_ID); 3481 } 3482 3483 int 3484 zonecfg_delete_rctl(zone_dochandle_t handle, struct zone_rctltab *tabptr) 3485 { 3486 int err; 3487 3488 if (tabptr == NULL) 3489 return (Z_INVAL); 3490 3491 if ((err = operation_prep(handle)) != Z_OK) 3492 return (err); 3493 3494 if ((err = zonecfg_delete_rctl_core(handle, tabptr)) != Z_OK) 3495 return (err); 3496 3497 return (Z_OK); 3498 } 3499 3500 int 3501 zonecfg_modify_rctl( 3502 zone_dochandle_t handle, 3503 struct zone_rctltab *oldtabptr, 3504 struct zone_rctltab *newtabptr) 3505 { 3506 int err; 3507 3508 if (oldtabptr == NULL || newtabptr == NULL) 3509 return (Z_INVAL); 3510 3511 if ((err = operation_prep(handle)) != Z_OK) 3512 return (err); 3513 3514 if ((err = zonecfg_delete_rctl_core(handle, oldtabptr)) != Z_OK) 3515 return (err); 3516 3517 if ((err = zonecfg_add_rctl_core(handle, newtabptr)) != Z_OK) 3518 return (err); 3519 3520 return (Z_OK); 3521 } 3522 3523 int 3524 zonecfg_add_rctl_value( 3525 struct zone_rctltab *tabptr, 3526 struct zone_rctlvaltab *valtabptr) 3527 { 3528 struct zone_rctlvaltab *last, *old, *new; 3529 rctlblk_t *rctlblk = alloca(rctlblk_size()); 3530 3531 last = tabptr->zone_rctl_valptr; 3532 for (old = last; old != NULL; old = old->zone_rctlval_next) 3533 last = old; /* walk to the end of the list */ 3534 new = valtabptr; /* alloc'd by caller */ 3535 new->zone_rctlval_next = NULL; 3536 if (zonecfg_construct_rctlblk(valtabptr, rctlblk) != Z_OK) 3537 return (Z_INVAL); 3538 if (!zonecfg_valid_rctlblk(rctlblk)) 3539 return (Z_INVAL); 3540 if (last == NULL) 3541 tabptr->zone_rctl_valptr = new; 3542 else 3543 last->zone_rctlval_next = new; 3544 return (Z_OK); 3545 } 3546 3547 int 3548 zonecfg_remove_rctl_value( 3549 struct zone_rctltab *tabptr, 3550 struct zone_rctlvaltab *valtabptr) 3551 { 3552 struct zone_rctlvaltab *last, *this, *next; 3553 3554 last = tabptr->zone_rctl_valptr; 3555 for (this = last; this != NULL; this = this->zone_rctlval_next) { 3556 if (strcmp(this->zone_rctlval_priv, 3557 valtabptr->zone_rctlval_priv) == 0 && 3558 strcmp(this->zone_rctlval_limit, 3559 valtabptr->zone_rctlval_limit) == 0 && 3560 strcmp(this->zone_rctlval_action, 3561 valtabptr->zone_rctlval_action) == 0) { 3562 next = this->zone_rctlval_next; 3563 if (this == tabptr->zone_rctl_valptr) 3564 tabptr->zone_rctl_valptr = next; 3565 else 3566 last->zone_rctlval_next = next; 3567 free(this); 3568 return (Z_OK); 3569 } else 3570 last = this; 3571 } 3572 return (Z_NO_PROPERTY_ID); 3573 } 3574 3575 void 3576 zonecfg_set_swinv(zone_dochandle_t handle) 3577 { 3578 handle->zone_dh_sw_inv = B_TRUE; 3579 } 3580 3581 /* 3582 * Add the pkg to the sw inventory on the handle. 3583 */ 3584 int 3585 zonecfg_add_pkg(zone_dochandle_t handle, char *name, char *version) 3586 { 3587 xmlNodePtr newnode; 3588 xmlNodePtr cur; 3589 int err; 3590 3591 if ((err = operation_prep(handle)) != Z_OK) 3592 return (err); 3593 3594 cur = handle->zone_dh_cur; 3595 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PACKAGE, NULL); 3596 if ((err = newprop(newnode, DTD_ATTR_NAME, name)) != Z_OK) 3597 return (err); 3598 if ((err = newprop(newnode, DTD_ATTR_VERSION, version)) != Z_OK) 3599 return (err); 3600 return (Z_OK); 3601 } 3602 3603 int 3604 zonecfg_add_patch(zone_dochandle_t handle, char *id, void **pnode) 3605 { 3606 xmlNodePtr node = (xmlNodePtr)*pnode; 3607 xmlNodePtr cur; 3608 int err; 3609 3610 if ((err = operation_prep(handle)) != Z_OK) 3611 return (err); 3612 3613 cur = handle->zone_dh_cur; 3614 node = xmlNewTextChild(cur, NULL, DTD_ELEM_PATCH, NULL); 3615 if ((err = newprop(node, DTD_ATTR_ID, id)) != Z_OK) 3616 return (err); 3617 *pnode = (void *)node; 3618 return (Z_OK); 3619 } 3620 3621 int 3622 zonecfg_add_patch_obs(char *id, void *cur) 3623 { 3624 xmlNodePtr node; 3625 int err; 3626 3627 node = xmlNewTextChild((xmlNodePtr)cur, NULL, DTD_ELEM_OBSOLETES, NULL); 3628 if ((err = newprop(node, DTD_ATTR_ID, id)) != Z_OK) 3629 return (err); 3630 return (Z_OK); 3631 } 3632 3633 char * 3634 zonecfg_strerror(int errnum) 3635 { 3636 switch (errnum) { 3637 case Z_OK: 3638 return (dgettext(TEXT_DOMAIN, "OK")); 3639 case Z_EMPTY_DOCUMENT: 3640 return (dgettext(TEXT_DOMAIN, "Empty document")); 3641 case Z_WRONG_DOC_TYPE: 3642 return (dgettext(TEXT_DOMAIN, "Wrong document type")); 3643 case Z_BAD_PROPERTY: 3644 return (dgettext(TEXT_DOMAIN, "Bad document property")); 3645 case Z_TEMP_FILE: 3646 return (dgettext(TEXT_DOMAIN, 3647 "Problem creating temporary file")); 3648 case Z_SAVING_FILE: 3649 return (dgettext(TEXT_DOMAIN, "Problem saving file")); 3650 case Z_NO_ENTRY: 3651 return (dgettext(TEXT_DOMAIN, "No such entry")); 3652 case Z_BOGUS_ZONE_NAME: 3653 return (dgettext(TEXT_DOMAIN, "Bogus zone name")); 3654 case Z_REQD_RESOURCE_MISSING: 3655 return (dgettext(TEXT_DOMAIN, "Required resource missing")); 3656 case Z_REQD_PROPERTY_MISSING: 3657 return (dgettext(TEXT_DOMAIN, "Required property missing")); 3658 case Z_BAD_HANDLE: 3659 return (dgettext(TEXT_DOMAIN, "Bad handle")); 3660 case Z_NOMEM: 3661 return (dgettext(TEXT_DOMAIN, "Out of memory")); 3662 case Z_INVAL: 3663 return (dgettext(TEXT_DOMAIN, "Invalid argument")); 3664 case Z_ACCES: 3665 return (dgettext(TEXT_DOMAIN, "Permission denied")); 3666 case Z_TOO_BIG: 3667 return (dgettext(TEXT_DOMAIN, "Argument list too long")); 3668 case Z_MISC_FS: 3669 return (dgettext(TEXT_DOMAIN, 3670 "Miscellaneous file system error")); 3671 case Z_NO_ZONE: 3672 return (dgettext(TEXT_DOMAIN, "No such zone configured")); 3673 case Z_NO_RESOURCE_TYPE: 3674 return (dgettext(TEXT_DOMAIN, "No such resource type")); 3675 case Z_NO_RESOURCE_ID: 3676 return (dgettext(TEXT_DOMAIN, "No such resource with that id")); 3677 case Z_NO_PROPERTY_TYPE: 3678 return (dgettext(TEXT_DOMAIN, "No such property type")); 3679 case Z_NO_PROPERTY_ID: 3680 return (dgettext(TEXT_DOMAIN, "No such property with that id")); 3681 case Z_BAD_ZONE_STATE: 3682 return (dgettext(TEXT_DOMAIN, 3683 "Zone state is invalid for the requested operation")); 3684 case Z_INVALID_DOCUMENT: 3685 return (dgettext(TEXT_DOMAIN, "Invalid document")); 3686 case Z_NAME_IN_USE: 3687 return (dgettext(TEXT_DOMAIN, "Zone name already in use")); 3688 case Z_NO_SUCH_ID: 3689 return (dgettext(TEXT_DOMAIN, "No such zone ID")); 3690 case Z_UPDATING_INDEX: 3691 return (dgettext(TEXT_DOMAIN, "Problem updating index file")); 3692 case Z_LOCKING_FILE: 3693 return (dgettext(TEXT_DOMAIN, "Locking index file")); 3694 case Z_UNLOCKING_FILE: 3695 return (dgettext(TEXT_DOMAIN, "Unlocking index file")); 3696 case Z_INSUFFICIENT_SPEC: 3697 return (dgettext(TEXT_DOMAIN, "Insufficient specification")); 3698 case Z_RESOLVED_PATH: 3699 return (dgettext(TEXT_DOMAIN, "Resolved path mismatch")); 3700 case Z_IPV6_ADDR_PREFIX_LEN: 3701 return (dgettext(TEXT_DOMAIN, 3702 "IPv6 address missing required prefix length")); 3703 case Z_BOGUS_ADDRESS: 3704 return (dgettext(TEXT_DOMAIN, 3705 "Neither an IPv4 nor an IPv6 address nor a host name")); 3706 case Z_PRIV_PROHIBITED: 3707 return (dgettext(TEXT_DOMAIN, 3708 "Specified privilege is prohibited")); 3709 case Z_PRIV_REQUIRED: 3710 return (dgettext(TEXT_DOMAIN, 3711 "Required privilege is missing")); 3712 case Z_PRIV_UNKNOWN: 3713 return (dgettext(TEXT_DOMAIN, 3714 "Specified privilege is unknown")); 3715 case Z_BRAND_ERROR: 3716 return (dgettext(TEXT_DOMAIN, 3717 "Brand-specific error")); 3718 case Z_INCOMPATIBLE: 3719 return (dgettext(TEXT_DOMAIN, "Incompatible settings")); 3720 case Z_ALIAS_DISALLOW: 3721 return (dgettext(TEXT_DOMAIN, 3722 "An incompatible rctl already exists for this property")); 3723 case Z_CLEAR_DISALLOW: 3724 return (dgettext(TEXT_DOMAIN, 3725 "Clearing this property is not allowed")); 3726 case Z_POOL: 3727 return (dgettext(TEXT_DOMAIN, "libpool(3LIB) error")); 3728 case Z_POOLS_NOT_ACTIVE: 3729 return (dgettext(TEXT_DOMAIN, "Pools facility not active; " 3730 "zone will not be bound to pool")); 3731 case Z_POOL_ENABLE: 3732 return (dgettext(TEXT_DOMAIN, 3733 "Could not enable pools facility")); 3734 case Z_NO_POOL: 3735 return (dgettext(TEXT_DOMAIN, 3736 "Pool not found; using default pool")); 3737 case Z_POOL_CREATE: 3738 return (dgettext(TEXT_DOMAIN, 3739 "Could not create a temporary pool")); 3740 case Z_POOL_BIND: 3741 return (dgettext(TEXT_DOMAIN, "Could not bind zone to pool")); 3742 case Z_INVALID_PROPERTY: 3743 return (dgettext(TEXT_DOMAIN, "Specified property is invalid")); 3744 case Z_SYSTEM: 3745 return (strerror(errno)); 3746 default: 3747 return (dgettext(TEXT_DOMAIN, "Unknown error")); 3748 } 3749 } 3750 3751 /* 3752 * Note that the zonecfg_setXent() and zonecfg_endXent() calls are all the 3753 * same, as they just turn around and call zonecfg_setent() / zonecfg_endent(). 3754 */ 3755 3756 static int 3757 zonecfg_setent(zone_dochandle_t handle) 3758 { 3759 xmlNodePtr cur; 3760 int err; 3761 3762 if (handle == NULL) 3763 return (Z_INVAL); 3764 3765 if ((err = operation_prep(handle)) != Z_OK) { 3766 handle->zone_dh_cur = NULL; 3767 return (err); 3768 } 3769 cur = handle->zone_dh_cur; 3770 cur = cur->xmlChildrenNode; 3771 handle->zone_dh_cur = cur; 3772 return (Z_OK); 3773 } 3774 3775 static int 3776 zonecfg_endent(zone_dochandle_t handle) 3777 { 3778 if (handle == NULL) 3779 return (Z_INVAL); 3780 3781 handle->zone_dh_cur = handle->zone_dh_top; 3782 return (Z_OK); 3783 } 3784 3785 /* 3786 * Do the work required to manipulate a process through libproc. 3787 * If grab_process() returns no errors (0), then release_process() 3788 * must eventually be called. 3789 * 3790 * Return values: 3791 * 0 Successful creation of agent thread 3792 * 1 Error grabbing 3793 * 2 Error creating agent 3794 */ 3795 static int 3796 grab_process(pr_info_handle_t *p) 3797 { 3798 int ret; 3799 3800 if ((p->pr = Pgrab(p->pid, 0, &ret)) != NULL) { 3801 3802 if (Psetflags(p->pr, PR_RLC) != 0) { 3803 Prelease(p->pr, 0); 3804 return (1); 3805 } 3806 if (Pcreate_agent(p->pr) == 0) { 3807 return (0); 3808 3809 } else { 3810 Prelease(p->pr, 0); 3811 return (2); 3812 } 3813 } else { 3814 return (1); 3815 } 3816 } 3817 3818 /* 3819 * Release the specified process. This destroys the agent 3820 * and releases the process. If the process is NULL, nothing 3821 * is done. This function should only be called if grab_process() 3822 * has previously been called and returned success. 3823 * 3824 * This function is Pgrab-safe. 3825 */ 3826 static void 3827 release_process(struct ps_prochandle *Pr) 3828 { 3829 if (Pr == NULL) 3830 return; 3831 3832 Pdestroy_agent(Pr); 3833 Prelease(Pr, 0); 3834 } 3835 3836 static boolean_t 3837 grab_zone_proc(char *zonename, pr_info_handle_t *p) 3838 { 3839 DIR *dirp; 3840 struct dirent *dentp; 3841 zoneid_t zoneid; 3842 int pid_self; 3843 psinfo_t psinfo; 3844 3845 if (zone_get_id(zonename, &zoneid) != 0) 3846 return (B_FALSE); 3847 3848 pid_self = getpid(); 3849 3850 if ((dirp = opendir("/proc")) == NULL) 3851 return (B_FALSE); 3852 3853 while (dentp = readdir(dirp)) { 3854 p->pid = atoi(dentp->d_name); 3855 3856 /* Skip self */ 3857 if (p->pid == pid_self) 3858 continue; 3859 3860 if (proc_get_psinfo(p->pid, &psinfo) != 0) 3861 continue; 3862 3863 if (psinfo.pr_zoneid != zoneid) 3864 continue; 3865 3866 /* attempt to grab process */ 3867 if (grab_process(p) != 0) 3868 continue; 3869 3870 if (pr_getzoneid(p->pr) != zoneid) { 3871 release_process(p->pr); 3872 continue; 3873 } 3874 3875 (void) closedir(dirp); 3876 return (B_TRUE); 3877 } 3878 3879 (void) closedir(dirp); 3880 return (B_FALSE); 3881 } 3882 3883 static boolean_t 3884 get_priv_rctl(struct ps_prochandle *pr, char *name, rctlblk_t *rblk) 3885 { 3886 if (pr_getrctl(pr, name, NULL, rblk, RCTL_FIRST)) 3887 return (B_FALSE); 3888 3889 if (rctlblk_get_privilege(rblk) == RCPRIV_PRIVILEGED) 3890 return (B_TRUE); 3891 3892 while (pr_getrctl(pr, name, rblk, rblk, RCTL_NEXT) == 0) { 3893 if (rctlblk_get_privilege(rblk) == RCPRIV_PRIVILEGED) 3894 return (B_TRUE); 3895 } 3896 3897 return (B_FALSE); 3898 } 3899 3900 /* 3901 * Apply the current rctl settings to the specified, running zone. 3902 */ 3903 int 3904 zonecfg_apply_rctls(char *zone_name, zone_dochandle_t handle) 3905 { 3906 int err; 3907 int res = Z_OK; 3908 rctlblk_t *rblk; 3909 pr_info_handle_t p; 3910 struct zone_rctltab rctl; 3911 3912 if ((err = zonecfg_setrctlent(handle)) != Z_OK) 3913 return (err); 3914 3915 if ((rblk = (rctlblk_t *)malloc(rctlblk_size())) == NULL) { 3916 (void) zonecfg_endrctlent(handle); 3917 return (Z_NOMEM); 3918 } 3919 3920 if (!grab_zone_proc(zone_name, &p)) { 3921 (void) zonecfg_endrctlent(handle); 3922 free(rblk); 3923 return (Z_SYSTEM); 3924 } 3925 3926 while (zonecfg_getrctlent(handle, &rctl) == Z_OK) { 3927 char *rname; 3928 struct zone_rctlvaltab *valptr; 3929 3930 rname = rctl.zone_rctl_name; 3931 3932 /* first delete all current privileged settings for this rctl */ 3933 while (get_priv_rctl(p.pr, rname, rblk)) { 3934 if (pr_setrctl(p.pr, rname, NULL, rblk, RCTL_DELETE) != 3935 0) { 3936 res = Z_SYSTEM; 3937 goto done; 3938 } 3939 } 3940 3941 /* now set each new value for the rctl */ 3942 for (valptr = rctl.zone_rctl_valptr; valptr != NULL; 3943 valptr = valptr->zone_rctlval_next) { 3944 if ((err = zonecfg_construct_rctlblk(valptr, rblk)) 3945 != Z_OK) { 3946 res = errno = err; 3947 goto done; 3948 } 3949 3950 if (pr_setrctl(p.pr, rname, NULL, rblk, RCTL_INSERT)) { 3951 res = Z_SYSTEM; 3952 goto done; 3953 } 3954 } 3955 } 3956 3957 done: 3958 release_process(p.pr); 3959 free(rblk); 3960 (void) zonecfg_endrctlent(handle); 3961 3962 return (res); 3963 } 3964 3965 static const xmlChar * 3966 nm_to_dtd(char *nm) 3967 { 3968 if (strcmp(nm, "device") == 0) 3969 return (DTD_ELEM_DEVICE); 3970 if (strcmp(nm, "fs") == 0) 3971 return (DTD_ELEM_FS); 3972 if (strcmp(nm, "inherit-pkg-dir") == 0) 3973 return (DTD_ELEM_IPD); 3974 if (strcmp(nm, "net") == 0) 3975 return (DTD_ELEM_NET); 3976 if (strcmp(nm, "attr") == 0) 3977 return (DTD_ELEM_ATTR); 3978 if (strcmp(nm, "rctl") == 0) 3979 return (DTD_ELEM_RCTL); 3980 if (strcmp(nm, "dataset") == 0) 3981 return (DTD_ELEM_DATASET); 3982 if (strcmp(nm, "admin") == 0) 3983 return (DTD_ELEM_ADMIN); 3984 3985 return (NULL); 3986 } 3987 3988 int 3989 zonecfg_num_resources(zone_dochandle_t handle, char *rsrc) 3990 { 3991 int num = 0; 3992 const xmlChar *dtd; 3993 xmlNodePtr cur; 3994 3995 if ((dtd = nm_to_dtd(rsrc)) == NULL) 3996 return (num); 3997 3998 if (zonecfg_setent(handle) != Z_OK) 3999 return (num); 4000 4001 for (cur = handle->zone_dh_cur; cur != NULL; cur = cur->next) 4002 if (xmlStrcmp(cur->name, dtd) == 0) 4003 num++; 4004 4005 (void) zonecfg_endent(handle); 4006 4007 return (num); 4008 } 4009 4010 int 4011 zonecfg_del_all_resources(zone_dochandle_t handle, char *rsrc) 4012 { 4013 int err; 4014 const xmlChar *dtd; 4015 xmlNodePtr cur; 4016 4017 if ((dtd = nm_to_dtd(rsrc)) == NULL) 4018 return (Z_NO_RESOURCE_TYPE); 4019 4020 if ((err = zonecfg_setent(handle)) != Z_OK) 4021 return (err); 4022 4023 cur = handle->zone_dh_cur; 4024 while (cur != NULL) { 4025 xmlNodePtr tmp; 4026 4027 if (xmlStrcmp(cur->name, dtd)) { 4028 cur = cur->next; 4029 continue; 4030 } 4031 4032 tmp = cur->next; 4033 xmlUnlinkNode(cur); 4034 xmlFreeNode(cur); 4035 cur = tmp; 4036 } 4037 4038 (void) zonecfg_endent(handle); 4039 return (Z_OK); 4040 } 4041 4042 static boolean_t 4043 valid_uint(char *s, uint64_t *n) 4044 { 4045 char *endp; 4046 4047 /* strtoull accepts '-'?! so we want to flag that as an error */ 4048 if (strchr(s, '-') != NULL) 4049 return (B_FALSE); 4050 4051 errno = 0; 4052 *n = strtoull(s, &endp, 10); 4053 4054 if (errno != 0 || *endp != '\0') 4055 return (B_FALSE); 4056 return (B_TRUE); 4057 } 4058 4059 /* 4060 * Convert a string representing a number (possibly a fraction) into an integer. 4061 * The string can have a modifier (K, M, G or T). The modifiers are treated 4062 * as powers of two (not 10). 4063 */ 4064 int 4065 zonecfg_str_to_bytes(char *str, uint64_t *bytes) 4066 { 4067 long double val; 4068 char *unitp; 4069 uint64_t scale; 4070 4071 if ((val = strtold(str, &unitp)) < 0) 4072 return (-1); 4073 4074 /* remove any leading white space from units string */ 4075 while (isspace(*unitp) != 0) 4076 ++unitp; 4077 4078 /* if no units explicitly set, error */ 4079 if (unitp == NULL || *unitp == '\0') { 4080 scale = 1; 4081 } else { 4082 int i; 4083 char *units[] = {"K", "M", "G", "T", NULL}; 4084 4085 scale = 1024; 4086 4087 /* update scale based on units */ 4088 for (i = 0; units[i] != NULL; i++) { 4089 if (strcasecmp(unitp, units[i]) == 0) 4090 break; 4091 scale <<= 10; 4092 } 4093 4094 if (units[i] == NULL) 4095 return (-1); 4096 } 4097 4098 *bytes = (uint64_t)(val * scale); 4099 return (0); 4100 } 4101 4102 boolean_t 4103 zonecfg_valid_ncpus(char *lowstr, char *highstr) 4104 { 4105 uint64_t low, high; 4106 4107 if (!valid_uint(lowstr, &low) || !valid_uint(highstr, &high) || 4108 low < 1 || low > high) 4109 return (B_FALSE); 4110 4111 return (B_TRUE); 4112 } 4113 4114 boolean_t 4115 zonecfg_valid_importance(char *impstr) 4116 { 4117 uint64_t num; 4118 4119 if (!valid_uint(impstr, &num)) 4120 return (B_FALSE); 4121 4122 return (B_TRUE); 4123 } 4124 4125 boolean_t 4126 zonecfg_valid_alias_limit(char *name, char *limitstr, uint64_t *limit) 4127 { 4128 int i; 4129 4130 for (i = 0; aliases[i].shortname != NULL; i++) 4131 if (strcmp(name, aliases[i].shortname) == 0) 4132 break; 4133 4134 if (aliases[i].shortname == NULL) 4135 return (B_FALSE); 4136 4137 if (!valid_uint(limitstr, limit) || *limit < aliases[i].low_limit) 4138 return (B_FALSE); 4139 4140 return (B_TRUE); 4141 } 4142 4143 boolean_t 4144 zonecfg_valid_memlimit(char *memstr, uint64_t *mem_val) 4145 { 4146 if (zonecfg_str_to_bytes(memstr, mem_val) != 0) 4147 return (B_FALSE); 4148 4149 return (B_TRUE); 4150 } 4151 4152 static int 4153 zerr_pool(char *pool_err, int err_size, int res) 4154 { 4155 (void) strlcpy(pool_err, pool_strerror(pool_error()), err_size); 4156 return (res); 4157 } 4158 4159 static int 4160 create_tmp_pset(char *pool_err, int err_size, pool_conf_t *pconf, pool_t *pool, 4161 char *name, int min, int max) 4162 { 4163 pool_resource_t *res; 4164 pool_elem_t *elem; 4165 pool_value_t *val; 4166 4167 if ((res = pool_resource_create(pconf, "pset", name)) == NULL) 4168 return (zerr_pool(pool_err, err_size, Z_POOL)); 4169 4170 if (pool_associate(pconf, pool, res) != PO_SUCCESS) 4171 return (zerr_pool(pool_err, err_size, Z_POOL)); 4172 4173 if ((elem = pool_resource_to_elem(pconf, res)) == NULL) 4174 return (zerr_pool(pool_err, err_size, Z_POOL)); 4175 4176 if ((val = pool_value_alloc()) == NULL) 4177 return (zerr_pool(pool_err, err_size, Z_POOL)); 4178 4179 /* set the maximum number of cpus for the pset */ 4180 pool_value_set_uint64(val, (uint64_t)max); 4181 4182 if (pool_put_property(pconf, elem, "pset.max", val) != PO_SUCCESS) { 4183 pool_value_free(val); 4184 return (zerr_pool(pool_err, err_size, Z_POOL)); 4185 } 4186 4187 /* set the minimum number of cpus for the pset */ 4188 pool_value_set_uint64(val, (uint64_t)min); 4189 4190 if (pool_put_property(pconf, elem, "pset.min", val) != PO_SUCCESS) { 4191 pool_value_free(val); 4192 return (zerr_pool(pool_err, err_size, Z_POOL)); 4193 } 4194 4195 pool_value_free(val); 4196 4197 return (Z_OK); 4198 } 4199 4200 static int 4201 create_tmp_pool(char *pool_err, int err_size, pool_conf_t *pconf, char *name, 4202 struct zone_psettab *pset_tab) 4203 { 4204 pool_t *pool; 4205 int res = Z_OK; 4206 4207 /* create a temporary pool configuration */ 4208 if (pool_conf_open(pconf, NULL, PO_TEMP) != PO_SUCCESS) { 4209 res = zerr_pool(pool_err, err_size, Z_POOL); 4210 return (res); 4211 } 4212 4213 if ((pool = pool_create(pconf, name)) == NULL) { 4214 res = zerr_pool(pool_err, err_size, Z_POOL_CREATE); 4215 goto done; 4216 } 4217 4218 /* set pool importance */ 4219 if (pset_tab->zone_importance[0] != '\0') { 4220 pool_elem_t *elem; 4221 pool_value_t *val; 4222 4223 if ((elem = pool_to_elem(pconf, pool)) == NULL) { 4224 res = zerr_pool(pool_err, err_size, Z_POOL); 4225 goto done; 4226 } 4227 4228 if ((val = pool_value_alloc()) == NULL) { 4229 res = zerr_pool(pool_err, err_size, Z_POOL); 4230 goto done; 4231 } 4232 4233 pool_value_set_int64(val, 4234 (int64_t)atoi(pset_tab->zone_importance)); 4235 4236 if (pool_put_property(pconf, elem, "pool.importance", val) 4237 != PO_SUCCESS) { 4238 res = zerr_pool(pool_err, err_size, Z_POOL); 4239 pool_value_free(val); 4240 goto done; 4241 } 4242 4243 pool_value_free(val); 4244 } 4245 4246 if ((res = create_tmp_pset(pool_err, err_size, pconf, pool, name, 4247 atoi(pset_tab->zone_ncpu_min), 4248 atoi(pset_tab->zone_ncpu_max))) != Z_OK) 4249 goto done; 4250 4251 /* validation */ 4252 if (pool_conf_status(pconf) == POF_INVALID) { 4253 res = zerr_pool(pool_err, err_size, Z_POOL); 4254 goto done; 4255 } 4256 4257 /* 4258 * This validation is the one we expect to fail if the user specified 4259 * an invalid configuration (too many cpus) for this system. 4260 */ 4261 if (pool_conf_validate(pconf, POV_RUNTIME) != PO_SUCCESS) { 4262 res = zerr_pool(pool_err, err_size, Z_POOL_CREATE); 4263 goto done; 4264 } 4265 4266 /* 4267 * Commit the dynamic configuration but not the pool configuration 4268 * file. 4269 */ 4270 if (pool_conf_commit(pconf, 1) != PO_SUCCESS) 4271 res = zerr_pool(pool_err, err_size, Z_POOL); 4272 4273 done: 4274 (void) pool_conf_close(pconf); 4275 return (res); 4276 } 4277 4278 static int 4279 get_running_tmp_pset(pool_conf_t *pconf, pool_t *pool, pool_resource_t *pset, 4280 struct zone_psettab *pset_tab) 4281 { 4282 int nfound = 0; 4283 pool_elem_t *pe; 4284 pool_value_t *pv = pool_value_alloc(); 4285 uint64_t val_uint; 4286 4287 if (pool != NULL) { 4288 pe = pool_to_elem(pconf, pool); 4289 if (pool_get_property(pconf, pe, "pool.importance", pv) 4290 != POC_INVAL) { 4291 int64_t val_int; 4292 4293 (void) pool_value_get_int64(pv, &val_int); 4294 (void) snprintf(pset_tab->zone_importance, 4295 sizeof (pset_tab->zone_importance), "%d", val_int); 4296 nfound++; 4297 } 4298 } 4299 4300 if (pset != NULL) { 4301 pe = pool_resource_to_elem(pconf, pset); 4302 if (pool_get_property(pconf, pe, "pset.min", pv) != POC_INVAL) { 4303 (void) pool_value_get_uint64(pv, &val_uint); 4304 (void) snprintf(pset_tab->zone_ncpu_min, 4305 sizeof (pset_tab->zone_ncpu_min), "%u", val_uint); 4306 nfound++; 4307 } 4308 4309 if (pool_get_property(pconf, pe, "pset.max", pv) != POC_INVAL) { 4310 (void) pool_value_get_uint64(pv, &val_uint); 4311 (void) snprintf(pset_tab->zone_ncpu_max, 4312 sizeof (pset_tab->zone_ncpu_max), "%u", val_uint); 4313 nfound++; 4314 } 4315 } 4316 4317 pool_value_free(pv); 4318 4319 if (nfound == 3) 4320 return (PO_SUCCESS); 4321 4322 return (PO_FAIL); 4323 } 4324 4325 /* 4326 * Determine if a tmp pool is configured and if so, if the configuration is 4327 * still valid or if it has been changed since the tmp pool was created. 4328 * If the tmp pool configuration is no longer valid, delete the tmp pool. 4329 * 4330 * Set *valid=B_TRUE if there is an existing, valid tmp pool configuration. 4331 */ 4332 static int 4333 verify_del_tmp_pool(pool_conf_t *pconf, char *tmp_name, char *pool_err, 4334 int err_size, struct zone_psettab *pset_tab, boolean_t *exists) 4335 { 4336 int res = Z_OK; 4337 pool_t *pool; 4338 pool_resource_t *pset; 4339 struct zone_psettab pset_current; 4340 4341 *exists = B_FALSE; 4342 4343 if (pool_conf_open(pconf, pool_dynamic_location(), PO_RDWR) 4344 != PO_SUCCESS) { 4345 res = zerr_pool(pool_err, err_size, Z_POOL); 4346 return (res); 4347 } 4348 4349 pool = pool_get_pool(pconf, tmp_name); 4350 pset = pool_get_resource(pconf, "pset", tmp_name); 4351 4352 if (pool == NULL && pset == NULL) { 4353 /* no tmp pool configured */ 4354 goto done; 4355 } 4356 4357 /* 4358 * If an existing tmp pool for this zone is configured with the proper 4359 * settings, then the tmp pool is valid. 4360 */ 4361 if (get_running_tmp_pset(pconf, pool, pset, &pset_current) 4362 == PO_SUCCESS && 4363 strcmp(pset_tab->zone_ncpu_min, 4364 pset_current.zone_ncpu_min) == 0 && 4365 strcmp(pset_tab->zone_ncpu_max, 4366 pset_current.zone_ncpu_max) == 0 && 4367 strcmp(pset_tab->zone_importance, 4368 pset_current.zone_importance) == 0) { 4369 *exists = B_TRUE; 4370 4371 } else { 4372 /* 4373 * An out-of-date tmp pool configuration exists. Delete it 4374 * so that we can create the correct tmp pool config. 4375 */ 4376 if (pset != NULL && 4377 pool_resource_destroy(pconf, pset) != PO_SUCCESS) { 4378 res = zerr_pool(pool_err, err_size, Z_POOL); 4379 goto done; 4380 } 4381 4382 if (pool != NULL && 4383 pool_destroy(pconf, pool) != PO_SUCCESS) { 4384 res = zerr_pool(pool_err, err_size, Z_POOL); 4385 goto done; 4386 } 4387 4388 /* commit dynamic config */ 4389 if (pool_conf_commit(pconf, 0) != PO_SUCCESS) 4390 res = zerr_pool(pool_err, err_size, Z_POOL); 4391 } 4392 4393 done: 4394 (void) pool_conf_close(pconf); 4395 4396 return (res); 4397 } 4398 4399 /* 4400 * Destroy any existing tmp pool. 4401 */ 4402 int 4403 zonecfg_destroy_tmp_pool(char *zone_name, char *pool_err, int err_size) 4404 { 4405 int status; 4406 int res = Z_OK; 4407 pool_conf_t *pconf; 4408 pool_t *pool; 4409 pool_resource_t *pset; 4410 char tmp_name[MAX_TMP_POOL_NAME]; 4411 4412 /* if pools not enabled then nothing to do */ 4413 if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) 4414 return (Z_OK); 4415 4416 if ((pconf = pool_conf_alloc()) == NULL) 4417 return (zerr_pool(pool_err, err_size, Z_POOL)); 4418 4419 (void) snprintf(tmp_name, sizeof (tmp_name), TMP_POOL_NAME, zone_name); 4420 4421 if (pool_conf_open(pconf, pool_dynamic_location(), PO_RDWR) 4422 != PO_SUCCESS) { 4423 res = zerr_pool(pool_err, err_size, Z_POOL); 4424 pool_conf_free(pconf); 4425 return (res); 4426 } 4427 4428 pool = pool_get_pool(pconf, tmp_name); 4429 pset = pool_get_resource(pconf, "pset", tmp_name); 4430 4431 if (pool == NULL && pset == NULL) { 4432 /* nothing to destroy, we're done */ 4433 goto done; 4434 } 4435 4436 if (pset != NULL && pool_resource_destroy(pconf, pset) != PO_SUCCESS) { 4437 res = zerr_pool(pool_err, err_size, Z_POOL); 4438 goto done; 4439 } 4440 4441 if (pool != NULL && pool_destroy(pconf, pool) != PO_SUCCESS) { 4442 res = zerr_pool(pool_err, err_size, Z_POOL); 4443 goto done; 4444 } 4445 4446 /* commit dynamic config */ 4447 if (pool_conf_commit(pconf, 0) != PO_SUCCESS) 4448 res = zerr_pool(pool_err, err_size, Z_POOL); 4449 4450 done: 4451 (void) pool_conf_close(pconf); 4452 pool_conf_free(pconf); 4453 4454 return (res); 4455 } 4456 4457 /* 4458 * Attempt to bind to a tmp pool for this zone. If there is no tmp pool 4459 * configured, we just return Z_OK. 4460 * 4461 * We either attempt to create the tmp pool for this zone or rebind to an 4462 * existing tmp pool for this zone. 4463 * 4464 * Rebinding is used when a zone with a tmp pool reboots so that we don't have 4465 * to recreate the tmp pool. To do this we need to be sure we work correctly 4466 * for the following cases: 4467 * 4468 * - there is an existing, properly configured tmp pool. 4469 * - zonecfg added tmp pool after zone was booted, must now create. 4470 * - zonecfg updated tmp pool config after zone was booted, in this case 4471 * we destroy the old tmp pool and create a new one. 4472 */ 4473 int 4474 zonecfg_bind_tmp_pool(zone_dochandle_t handle, zoneid_t zoneid, char *pool_err, 4475 int err_size) 4476 { 4477 struct zone_psettab pset_tab; 4478 int err; 4479 int status; 4480 pool_conf_t *pconf; 4481 boolean_t exists; 4482 char zone_name[ZONENAME_MAX]; 4483 char tmp_name[MAX_TMP_POOL_NAME]; 4484 4485 (void) getzonenamebyid(zoneid, zone_name, sizeof (zone_name)); 4486 4487 err = zonecfg_lookup_pset(handle, &pset_tab); 4488 4489 /* if no temporary pool configured, we're done */ 4490 if (err == Z_NO_ENTRY) 4491 return (Z_OK); 4492 4493 /* 4494 * importance might not have a value but we need to validate it here, 4495 * so set the default. 4496 */ 4497 if (pset_tab.zone_importance[0] == '\0') 4498 (void) strlcpy(pset_tab.zone_importance, "1", 4499 sizeof (pset_tab.zone_importance)); 4500 4501 /* if pools not enabled, enable them now */ 4502 if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) { 4503 if (pool_set_status(POOL_ENABLED) != PO_SUCCESS) 4504 return (Z_POOL_ENABLE); 4505 } 4506 4507 if ((pconf = pool_conf_alloc()) == NULL) 4508 return (zerr_pool(pool_err, err_size, Z_POOL)); 4509 4510 (void) snprintf(tmp_name, sizeof (tmp_name), TMP_POOL_NAME, zone_name); 4511 4512 /* 4513 * Check if a valid tmp pool/pset already exists. If so, we just 4514 * reuse it. 4515 */ 4516 if ((err = verify_del_tmp_pool(pconf, tmp_name, pool_err, err_size, 4517 &pset_tab, &exists)) != Z_OK) { 4518 pool_conf_free(pconf); 4519 return (err); 4520 } 4521 4522 if (!exists) 4523 err = create_tmp_pool(pool_err, err_size, pconf, tmp_name, 4524 &pset_tab); 4525 4526 pool_conf_free(pconf); 4527 4528 if (err != Z_OK) 4529 return (err); 4530 4531 /* Bind the zone to the pool. */ 4532 if (pool_set_binding(tmp_name, P_ZONEID, zoneid) != PO_SUCCESS) 4533 return (zerr_pool(pool_err, err_size, Z_POOL_BIND)); 4534 4535 return (Z_OK); 4536 } 4537 4538 /* 4539 * Attempt to bind to a permanent pool for this zone. If there is no 4540 * permanent pool configured, we just return Z_OK. 4541 */ 4542 int 4543 zonecfg_bind_pool(zone_dochandle_t handle, zoneid_t zoneid, char *pool_err, 4544 int err_size) 4545 { 4546 pool_conf_t *poolconf; 4547 pool_t *pool; 4548 char poolname[MAXPATHLEN]; 4549 int status; 4550 int error; 4551 4552 /* 4553 * Find the pool mentioned in the zone configuration, and bind to it. 4554 */ 4555 error = zonecfg_get_pool(handle, poolname, sizeof (poolname)); 4556 if (error == Z_NO_ENTRY || (error == Z_OK && strlen(poolname) == 0)) { 4557 /* 4558 * The property is not set on the zone, so the pool 4559 * should be bound to the default pool. But that's 4560 * already done by the kernel, so we can just return. 4561 */ 4562 return (Z_OK); 4563 } 4564 if (error != Z_OK) { 4565 /* 4566 * Not an error, even though it shouldn't be happening. 4567 */ 4568 return (Z_OK); 4569 } 4570 /* 4571 * Don't do anything if pools aren't enabled. 4572 */ 4573 if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) 4574 return (Z_POOLS_NOT_ACTIVE); 4575 4576 /* 4577 * Try to provide a sane error message if the requested pool doesn't 4578 * exist. 4579 */ 4580 if ((poolconf = pool_conf_alloc()) == NULL) 4581 return (zerr_pool(pool_err, err_size, Z_POOL)); 4582 4583 if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) != 4584 PO_SUCCESS) { 4585 pool_conf_free(poolconf); 4586 return (zerr_pool(pool_err, err_size, Z_POOL)); 4587 } 4588 pool = pool_get_pool(poolconf, poolname); 4589 (void) pool_conf_close(poolconf); 4590 pool_conf_free(poolconf); 4591 if (pool == NULL) 4592 return (Z_NO_POOL); 4593 4594 /* 4595 * Bind the zone to the pool. 4596 */ 4597 if (pool_set_binding(poolname, P_ZONEID, zoneid) != PO_SUCCESS) { 4598 /* if bind fails, return poolname for the error msg */ 4599 (void) strlcpy(pool_err, poolname, err_size); 4600 return (Z_POOL_BIND); 4601 } 4602 4603 return (Z_OK); 4604 } 4605 4606 int 4607 zonecfg_get_poolname(zone_dochandle_t handle, char *zone, char *pool, 4608 size_t poolsize) 4609 { 4610 int err; 4611 struct zone_psettab pset_tab; 4612 4613 err = zonecfg_lookup_pset(handle, &pset_tab); 4614 if ((err != Z_NO_ENTRY) && (err != Z_OK)) 4615 return (err); 4616 4617 /* pset was found so a temporary pool was created */ 4618 if (err == Z_OK) { 4619 (void) snprintf(pool, poolsize, TMP_POOL_NAME, zone); 4620 return (Z_OK); 4621 } 4622 4623 /* lookup the poolname in zonecfg */ 4624 return (zonecfg_get_pool(handle, pool, poolsize)); 4625 } 4626 4627 static boolean_t 4628 svc_enabled(char *svc_name) 4629 { 4630 scf_simple_prop_t *prop; 4631 boolean_t found = B_FALSE; 4632 4633 prop = scf_simple_prop_get(NULL, svc_name, SCF_PG_GENERAL, 4634 SCF_PROPERTY_ENABLED); 4635 4636 if (scf_simple_prop_numvalues(prop) == 1 && 4637 *scf_simple_prop_next_boolean(prop) != 0) 4638 found = B_TRUE; 4639 4640 scf_simple_prop_free(prop); 4641 4642 return (found); 4643 } 4644 4645 /* 4646 * If the zone has capped-memory, make sure the rcap service is enabled. 4647 */ 4648 int 4649 zonecfg_enable_rcapd(char *err, int size) 4650 { 4651 if (!svc_enabled(RCAP_SERVICE) && 4652 smf_enable_instance(RCAP_SERVICE, 0) == -1) { 4653 (void) strlcpy(err, scf_strerror(scf_error()), size); 4654 return (Z_SYSTEM); 4655 } 4656 4657 return (Z_OK); 4658 } 4659 4660 /* 4661 * Return true if pset has cpu range specified and poold is not enabled. 4662 */ 4663 boolean_t 4664 zonecfg_warn_poold(zone_dochandle_t handle) 4665 { 4666 struct zone_psettab pset_tab; 4667 int min, max; 4668 int err; 4669 4670 err = zonecfg_lookup_pset(handle, &pset_tab); 4671 4672 /* if no temporary pool configured, we're done */ 4673 if (err == Z_NO_ENTRY) 4674 return (B_FALSE); 4675 4676 min = atoi(pset_tab.zone_ncpu_min); 4677 max = atoi(pset_tab.zone_ncpu_max); 4678 4679 /* range not specified, no need for poold */ 4680 if (min == max) 4681 return (B_FALSE); 4682 4683 /* we have a range, check if poold service is enabled */ 4684 if (svc_enabled(POOLD_SERVICE)) 4685 return (B_FALSE); 4686 4687 return (B_TRUE); 4688 } 4689 4690 /* 4691 * Retrieve the specified pool's thread scheduling class. 'poolname' must 4692 * refer to the name of a configured resource pool. The thread scheduling 4693 * class specified by the pool will be stored in the buffer to which 'class' 4694 * points. 'clsize' is the byte size of the buffer to which 'class' points. 4695 * 4696 * This function returns Z_OK if it successfully stored the specified pool's 4697 * thread scheduling class into the buffer to which 'class' points. It returns 4698 * Z_NO_POOL if resource pools are not enabled, the function is unable to 4699 * access the system's resource pools configuration, or the specified pool 4700 * does not exist. The function returns Z_TOO_BIG if the buffer to which 4701 * 'class' points is not large enough to contain the thread scheduling class' 4702 * name. The function returns Z_NO_ENTRY if the pool does not specify a thread 4703 * scheduling class. 4704 */ 4705 static int 4706 get_pool_sched_class(char *poolname, char *class, int clsize) 4707 { 4708 int status; 4709 pool_conf_t *poolconf; 4710 pool_t *pool; 4711 pool_elem_t *pe; 4712 pool_value_t *pv = pool_value_alloc(); 4713 const char *sched_str; 4714 4715 if (pool_get_status(&status) != PO_SUCCESS || status != POOL_ENABLED) 4716 return (Z_NO_POOL); 4717 4718 if ((poolconf = pool_conf_alloc()) == NULL) 4719 return (Z_NO_POOL); 4720 4721 if (pool_conf_open(poolconf, pool_dynamic_location(), PO_RDONLY) != 4722 PO_SUCCESS) { 4723 pool_conf_free(poolconf); 4724 return (Z_NO_POOL); 4725 } 4726 4727 if ((pool = pool_get_pool(poolconf, poolname)) == NULL) { 4728 (void) pool_conf_close(poolconf); 4729 pool_conf_free(poolconf); 4730 return (Z_NO_POOL); 4731 } 4732 4733 pe = pool_to_elem(poolconf, pool); 4734 if (pool_get_property(poolconf, pe, "pool.scheduler", pv) != 4735 POC_STRING) { 4736 (void) pool_conf_close(poolconf); 4737 pool_conf_free(poolconf); 4738 return (Z_NO_ENTRY); 4739 } 4740 (void) pool_value_get_string(pv, &sched_str); 4741 (void) pool_conf_close(poolconf); 4742 pool_conf_free(poolconf); 4743 if (strlcpy(class, sched_str, clsize) >= clsize) 4744 return (Z_TOO_BIG); 4745 return (Z_OK); 4746 } 4747 4748 /* 4749 * Get the default scheduling class for the zone. This will either be the 4750 * class set on the zone's pool or the system default scheduling class. 4751 */ 4752 int 4753 zonecfg_get_dflt_sched_class(zone_dochandle_t handle, char *class, int clsize) 4754 { 4755 char poolname[MAXPATHLEN]; 4756 4757 if (zonecfg_get_pool(handle, poolname, sizeof (poolname)) == Z_OK) { 4758 /* check if the zone's pool specified a sched class */ 4759 if (get_pool_sched_class(poolname, class, clsize) == Z_OK) 4760 return (Z_OK); 4761 } 4762 4763 if (priocntl(0, 0, PC_GETDFLCL, class, (uint64_t)clsize) == -1) 4764 return (Z_TOO_BIG); 4765 4766 return (Z_OK); 4767 } 4768 4769 int 4770 zonecfg_setfsent(zone_dochandle_t handle) 4771 { 4772 return (zonecfg_setent(handle)); 4773 } 4774 4775 int 4776 zonecfg_getfsent(zone_dochandle_t handle, struct zone_fstab *tabptr) 4777 { 4778 xmlNodePtr cur, options; 4779 char options_str[MAX_MNTOPT_STR]; 4780 int err; 4781 4782 if (handle == NULL) 4783 return (Z_INVAL); 4784 4785 if ((cur = handle->zone_dh_cur) == NULL) 4786 return (Z_NO_ENTRY); 4787 4788 for (; cur != NULL; cur = cur->next) 4789 if (!xmlStrcmp(cur->name, DTD_ELEM_FS)) 4790 break; 4791 if (cur == NULL) { 4792 handle->zone_dh_cur = handle->zone_dh_top; 4793 return (Z_NO_ENTRY); 4794 } 4795 4796 if ((err = fetchprop(cur, DTD_ATTR_SPECIAL, tabptr->zone_fs_special, 4797 sizeof (tabptr->zone_fs_special))) != Z_OK) { 4798 handle->zone_dh_cur = handle->zone_dh_top; 4799 return (err); 4800 } 4801 4802 if ((err = fetchprop(cur, DTD_ATTR_RAW, tabptr->zone_fs_raw, 4803 sizeof (tabptr->zone_fs_raw))) != Z_OK) { 4804 handle->zone_dh_cur = handle->zone_dh_top; 4805 return (err); 4806 } 4807 4808 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 4809 sizeof (tabptr->zone_fs_dir))) != Z_OK) { 4810 handle->zone_dh_cur = handle->zone_dh_top; 4811 return (err); 4812 } 4813 4814 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_fs_type, 4815 sizeof (tabptr->zone_fs_type))) != Z_OK) { 4816 handle->zone_dh_cur = handle->zone_dh_top; 4817 return (err); 4818 } 4819 4820 /* OK for options to be NULL */ 4821 tabptr->zone_fs_options = NULL; 4822 for (options = cur->xmlChildrenNode; options != NULL; 4823 options = options->next) { 4824 if (fetchprop(options, DTD_ATTR_NAME, options_str, 4825 sizeof (options_str)) != Z_OK) 4826 break; 4827 if (zonecfg_add_fs_option(tabptr, options_str) != Z_OK) 4828 break; 4829 } 4830 4831 handle->zone_dh_cur = cur->next; 4832 return (Z_OK); 4833 } 4834 4835 int 4836 zonecfg_endfsent(zone_dochandle_t handle) 4837 { 4838 return (zonecfg_endent(handle)); 4839 } 4840 4841 int 4842 zonecfg_setipdent(zone_dochandle_t handle) 4843 { 4844 return (zonecfg_setent(handle)); 4845 } 4846 4847 int 4848 zonecfg_getipdent(zone_dochandle_t handle, struct zone_fstab *tabptr) 4849 { 4850 xmlNodePtr cur; 4851 int err; 4852 4853 if (handle == NULL) 4854 return (Z_INVAL); 4855 4856 if ((cur = handle->zone_dh_cur) == NULL) 4857 return (Z_NO_ENTRY); 4858 4859 for (; cur != NULL; cur = cur->next) 4860 if (!xmlStrcmp(cur->name, DTD_ELEM_IPD)) 4861 break; 4862 if (cur == NULL) { 4863 handle->zone_dh_cur = handle->zone_dh_top; 4864 return (Z_NO_ENTRY); 4865 } 4866 4867 if ((err = fetchprop(cur, DTD_ATTR_DIR, tabptr->zone_fs_dir, 4868 sizeof (tabptr->zone_fs_dir))) != Z_OK) { 4869 handle->zone_dh_cur = handle->zone_dh_top; 4870 return (err); 4871 } 4872 4873 handle->zone_dh_cur = cur->next; 4874 return (Z_OK); 4875 } 4876 4877 int 4878 zonecfg_endipdent(zone_dochandle_t handle) 4879 { 4880 return (zonecfg_endent(handle)); 4881 } 4882 4883 int 4884 zonecfg_setnwifent(zone_dochandle_t handle) 4885 { 4886 return (zonecfg_setent(handle)); 4887 } 4888 4889 int 4890 zonecfg_getnwifent(zone_dochandle_t handle, struct zone_nwiftab *tabptr) 4891 { 4892 xmlNodePtr cur; 4893 int err; 4894 4895 if (handle == NULL) 4896 return (Z_INVAL); 4897 4898 if ((cur = handle->zone_dh_cur) == NULL) 4899 return (Z_NO_ENTRY); 4900 4901 for (; cur != NULL; cur = cur->next) 4902 if (!xmlStrcmp(cur->name, DTD_ELEM_NET)) 4903 break; 4904 if (cur == NULL) { 4905 handle->zone_dh_cur = handle->zone_dh_top; 4906 return (Z_NO_ENTRY); 4907 } 4908 4909 if ((err = fetchprop(cur, DTD_ATTR_ADDRESS, tabptr->zone_nwif_address, 4910 sizeof (tabptr->zone_nwif_address))) != Z_OK) { 4911 handle->zone_dh_cur = handle->zone_dh_top; 4912 return (err); 4913 } 4914 4915 if ((err = fetchprop(cur, DTD_ATTR_PHYSICAL, tabptr->zone_nwif_physical, 4916 sizeof (tabptr->zone_nwif_physical))) != Z_OK) { 4917 handle->zone_dh_cur = handle->zone_dh_top; 4918 return (err); 4919 } 4920 4921 if ((err = fetchprop(cur, DTD_ATTR_DEFROUTER, 4922 tabptr->zone_nwif_defrouter, 4923 sizeof (tabptr->zone_nwif_defrouter))) != Z_OK) { 4924 handle->zone_dh_cur = handle->zone_dh_top; 4925 return (err); 4926 } 4927 4928 handle->zone_dh_cur = cur->next; 4929 return (Z_OK); 4930 } 4931 4932 int 4933 zonecfg_endnwifent(zone_dochandle_t handle) 4934 { 4935 return (zonecfg_endent(handle)); 4936 } 4937 4938 int 4939 zonecfg_setdevent(zone_dochandle_t handle) 4940 { 4941 return (zonecfg_setent(handle)); 4942 } 4943 4944 int 4945 zonecfg_getdevent(zone_dochandle_t handle, struct zone_devtab *tabptr) 4946 { 4947 xmlNodePtr cur; 4948 int err; 4949 4950 if (handle == NULL) 4951 return (Z_INVAL); 4952 4953 if ((cur = handle->zone_dh_cur) == NULL) 4954 return (Z_NO_ENTRY); 4955 4956 for (; cur != NULL; cur = cur->next) 4957 if (!xmlStrcmp(cur->name, DTD_ELEM_DEVICE)) 4958 break; 4959 if (cur == NULL) { 4960 handle->zone_dh_cur = handle->zone_dh_top; 4961 return (Z_NO_ENTRY); 4962 } 4963 4964 if ((err = fetchprop(cur, DTD_ATTR_MATCH, tabptr->zone_dev_match, 4965 sizeof (tabptr->zone_dev_match))) != Z_OK) { 4966 handle->zone_dh_cur = handle->zone_dh_top; 4967 return (err); 4968 } 4969 4970 handle->zone_dh_cur = cur->next; 4971 return (Z_OK); 4972 } 4973 4974 int 4975 zonecfg_enddevent(zone_dochandle_t handle) 4976 { 4977 return (zonecfg_endent(handle)); 4978 } 4979 4980 int 4981 zonecfg_setrctlent(zone_dochandle_t handle) 4982 { 4983 return (zonecfg_setent(handle)); 4984 } 4985 4986 int 4987 zonecfg_getrctlent(zone_dochandle_t handle, struct zone_rctltab *tabptr) 4988 { 4989 xmlNodePtr cur, val; 4990 struct zone_rctlvaltab *valptr; 4991 int err; 4992 4993 if (handle == NULL) 4994 return (Z_INVAL); 4995 4996 if ((cur = handle->zone_dh_cur) == NULL) 4997 return (Z_NO_ENTRY); 4998 4999 for (; cur != NULL; cur = cur->next) 5000 if (!xmlStrcmp(cur->name, DTD_ELEM_RCTL)) 5001 break; 5002 if (cur == NULL) { 5003 handle->zone_dh_cur = handle->zone_dh_top; 5004 return (Z_NO_ENTRY); 5005 } 5006 5007 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_rctl_name, 5008 sizeof (tabptr->zone_rctl_name))) != Z_OK) { 5009 handle->zone_dh_cur = handle->zone_dh_top; 5010 return (err); 5011 } 5012 5013 tabptr->zone_rctl_valptr = NULL; 5014 for (val = cur->xmlChildrenNode; val != NULL; val = val->next) { 5015 valptr = (struct zone_rctlvaltab *)malloc( 5016 sizeof (struct zone_rctlvaltab)); 5017 if (valptr == NULL) 5018 return (Z_NOMEM); 5019 if (fetchprop(val, DTD_ATTR_PRIV, valptr->zone_rctlval_priv, 5020 sizeof (valptr->zone_rctlval_priv)) != Z_OK) 5021 break; 5022 if (fetchprop(val, DTD_ATTR_LIMIT, valptr->zone_rctlval_limit, 5023 sizeof (valptr->zone_rctlval_limit)) != Z_OK) 5024 break; 5025 if (fetchprop(val, DTD_ATTR_ACTION, valptr->zone_rctlval_action, 5026 sizeof (valptr->zone_rctlval_action)) != Z_OK) 5027 break; 5028 if (zonecfg_add_rctl_value(tabptr, valptr) != Z_OK) 5029 break; 5030 } 5031 5032 handle->zone_dh_cur = cur->next; 5033 return (Z_OK); 5034 } 5035 5036 int 5037 zonecfg_endrctlent(zone_dochandle_t handle) 5038 { 5039 return (zonecfg_endent(handle)); 5040 } 5041 5042 int 5043 zonecfg_setattrent(zone_dochandle_t handle) 5044 { 5045 return (zonecfg_setent(handle)); 5046 } 5047 5048 int 5049 zonecfg_getattrent(zone_dochandle_t handle, struct zone_attrtab *tabptr) 5050 { 5051 xmlNodePtr cur; 5052 int err; 5053 5054 if (handle == NULL) 5055 return (Z_INVAL); 5056 5057 if ((cur = handle->zone_dh_cur) == NULL) 5058 return (Z_NO_ENTRY); 5059 5060 for (; cur != NULL; cur = cur->next) 5061 if (!xmlStrcmp(cur->name, DTD_ELEM_ATTR)) 5062 break; 5063 if (cur == NULL) { 5064 handle->zone_dh_cur = handle->zone_dh_top; 5065 return (Z_NO_ENTRY); 5066 } 5067 5068 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_attr_name, 5069 sizeof (tabptr->zone_attr_name))) != Z_OK) { 5070 handle->zone_dh_cur = handle->zone_dh_top; 5071 return (err); 5072 } 5073 5074 if ((err = fetchprop(cur, DTD_ATTR_TYPE, tabptr->zone_attr_type, 5075 sizeof (tabptr->zone_attr_type))) != Z_OK) { 5076 handle->zone_dh_cur = handle->zone_dh_top; 5077 return (err); 5078 } 5079 5080 if ((err = fetchprop(cur, DTD_ATTR_VALUE, tabptr->zone_attr_value, 5081 sizeof (tabptr->zone_attr_value))) != Z_OK) { 5082 handle->zone_dh_cur = handle->zone_dh_top; 5083 return (err); 5084 } 5085 5086 handle->zone_dh_cur = cur->next; 5087 return (Z_OK); 5088 } 5089 5090 int 5091 zonecfg_endattrent(zone_dochandle_t handle) 5092 { 5093 return (zonecfg_endent(handle)); 5094 } 5095 5096 int 5097 zonecfg_setadminent(zone_dochandle_t handle) 5098 { 5099 return (zonecfg_setent(handle)); 5100 } 5101 5102 int 5103 zonecfg_getadminent(zone_dochandle_t handle, struct zone_admintab *tabptr) 5104 { 5105 xmlNodePtr cur; 5106 int err; 5107 5108 if (handle == NULL) 5109 return (Z_INVAL); 5110 5111 if ((cur = handle->zone_dh_cur) == NULL) 5112 return (Z_NO_ENTRY); 5113 5114 for (; cur != NULL; cur = cur->next) 5115 if (!xmlStrcmp(cur->name, DTD_ELEM_ADMIN)) 5116 break; 5117 if (cur == NULL) { 5118 handle->zone_dh_cur = handle->zone_dh_top; 5119 return (Z_NO_ENTRY); 5120 } 5121 5122 if ((err = fetchprop(cur, DTD_ATTR_USER, tabptr->zone_admin_user, 5123 sizeof (tabptr->zone_admin_user))) != Z_OK) { 5124 handle->zone_dh_cur = handle->zone_dh_top; 5125 return (err); 5126 } 5127 5128 5129 if ((err = fetchprop(cur, DTD_ATTR_AUTHS, tabptr->zone_admin_auths, 5130 sizeof (tabptr->zone_admin_auths))) != Z_OK) { 5131 handle->zone_dh_cur = handle->zone_dh_top; 5132 return (err); 5133 } 5134 5135 handle->zone_dh_cur = cur->next; 5136 return (Z_OK); 5137 } 5138 5139 int 5140 zonecfg_endadminent(zone_dochandle_t handle) 5141 { 5142 return (zonecfg_endent(handle)); 5143 } 5144 5145 /* 5146 * The privileges available on the system and described in privileges(5) 5147 * fall into four categories with respect to non-global zones: 5148 * 5149 * Default set of privileges considered safe for all non-global 5150 * zones. These privileges are "safe" in the sense that a 5151 * privileged process in the zone cannot affect processes in any 5152 * other zone on the system. 5153 * 5154 * Set of privileges not currently permitted within a non-global 5155 * zone. These privileges are considered by default, "unsafe," 5156 * and include ones which affect global resources (such as the 5157 * system clock or physical memory) or are overly broad and cover 5158 * more than one mechanism in the system. In other cases, there 5159 * has not been sufficient virtualization in the parts of the 5160 * system the privilege covers to allow its use within a 5161 * non-global zone. 5162 * 5163 * Set of privileges required in order to get a zone booted and 5164 * init(1M) started. These cannot be removed from the zone's 5165 * privilege set. 5166 * 5167 * All other privileges are optional and are potentially useful for 5168 * processes executing inside a non-global zone. 5169 * 5170 * When privileges are added to the system, a determination needs to be 5171 * made as to which category the privilege belongs to. Ideally, 5172 * privileges should be fine-grained enough and the mechanisms they cover 5173 * virtualized enough so that they can be made available to non-global 5174 * zones. 5175 */ 5176 5177 /* 5178 * Define some of the tokens that priv_str_to_set(3C) recognizes. Since 5179 * the privilege string separator can be any character, although it is 5180 * usually a comma character, define these here as well in the event that 5181 * they change or are augmented in the future. 5182 */ 5183 #define BASIC_TOKEN "basic" 5184 #define DEFAULT_TOKEN "default" 5185 #define ZONE_TOKEN "zone" 5186 #define TOKEN_PRIV_CHAR ',' 5187 #define TOKEN_PRIV_STR "," 5188 5189 typedef struct priv_node { 5190 struct priv_node *pn_next; /* Next privilege */ 5191 char *pn_priv; /* Privileges name */ 5192 } priv_node_t; 5193 5194 /* Privileges lists can differ across brands */ 5195 typedef struct priv_lists { 5196 /* Privileges considered safe for all non-global zones of a brand */ 5197 struct priv_node *pl_default; 5198 5199 /* Privileges not permitted for all non-global zones of a brand */ 5200 struct priv_node *pl_prohibited; 5201 5202 /* Privileges required for all non-global zones of a brand */ 5203 struct priv_node *pl_required; 5204 5205 /* 5206 * ip-type of the zone these privileges lists apply to. 5207 * It is used to pass ip-type to the callback function, 5208 * priv_lists_cb, which has no way of getting the ip-type. 5209 */ 5210 const char *pl_iptype; 5211 } priv_lists_t; 5212 5213 static int 5214 priv_lists_cb(void *data, priv_iter_t *priv_iter) 5215 { 5216 priv_lists_t *plp = (priv_lists_t *)data; 5217 priv_node_t *pnp; 5218 5219 /* Skip this privilege if ip-type does not match */ 5220 if ((strcmp(priv_iter->pi_iptype, "all") != 0) && 5221 (strcmp(priv_iter->pi_iptype, plp->pl_iptype) != 0)) 5222 return (0); 5223 5224 /* Allocate a new priv list node. */ 5225 if ((pnp = malloc(sizeof (*pnp))) == NULL) 5226 return (-1); 5227 if ((pnp->pn_priv = strdup(priv_iter->pi_name)) == NULL) { 5228 free(pnp); 5229 return (-1); 5230 } 5231 5232 /* Insert the new priv list node into the right list */ 5233 if (strcmp(priv_iter->pi_set, "default") == 0) { 5234 pnp->pn_next = plp->pl_default; 5235 plp->pl_default = pnp; 5236 } else if (strcmp(priv_iter->pi_set, "prohibited") == 0) { 5237 pnp->pn_next = plp->pl_prohibited; 5238 plp->pl_prohibited = pnp; 5239 } else if (strcmp(priv_iter->pi_set, "required") == 0) { 5240 pnp->pn_next = plp->pl_required; 5241 plp->pl_required = pnp; 5242 } else { 5243 free(pnp->pn_priv); 5244 free(pnp); 5245 return (-1); 5246 } 5247 return (0); 5248 } 5249 5250 static void 5251 priv_lists_destroy(priv_lists_t *plp) 5252 { 5253 priv_node_t *pnp; 5254 5255 assert(plp != NULL); 5256 5257 while ((pnp = plp->pl_default) != NULL) { 5258 plp->pl_default = pnp->pn_next; 5259 free(pnp->pn_priv); 5260 free(pnp); 5261 } 5262 while ((pnp = plp->pl_prohibited) != NULL) { 5263 plp->pl_prohibited = pnp->pn_next; 5264 free(pnp->pn_priv); 5265 free(pnp); 5266 } 5267 while ((pnp = plp->pl_required) != NULL) { 5268 plp->pl_required = pnp->pn_next; 5269 free(pnp->pn_priv); 5270 free(pnp); 5271 } 5272 free(plp); 5273 } 5274 5275 static int 5276 priv_lists_create(zone_dochandle_t handle, char *brand, priv_lists_t **plpp, 5277 const char *curr_iptype) 5278 { 5279 priv_lists_t *plp; 5280 brand_handle_t bh; 5281 char brand_str[MAXNAMELEN]; 5282 5283 /* handle or brand must be set, but never both */ 5284 assert((handle != NULL) || (brand != NULL)); 5285 assert((handle == NULL) || (brand == NULL)); 5286 5287 if (handle != NULL) { 5288 brand = brand_str; 5289 if (zonecfg_get_brand(handle, brand, sizeof (brand_str)) != 0) 5290 return (Z_BRAND_ERROR); 5291 } 5292 5293 if ((bh = brand_open(brand)) == NULL) 5294 return (Z_BRAND_ERROR); 5295 5296 if ((plp = calloc(1, sizeof (priv_lists_t))) == NULL) { 5297 brand_close(bh); 5298 return (Z_NOMEM); 5299 } 5300 5301 plp->pl_iptype = curr_iptype; 5302 5303 /* construct the privilege lists */ 5304 if (brand_config_iter_privilege(bh, priv_lists_cb, plp) != 0) { 5305 priv_lists_destroy(plp); 5306 brand_close(bh); 5307 return (Z_BRAND_ERROR); 5308 } 5309 5310 brand_close(bh); 5311 *plpp = plp; 5312 return (Z_OK); 5313 } 5314 5315 static int 5316 get_default_privset(priv_set_t *privs, priv_lists_t *plp) 5317 { 5318 priv_node_t *pnp; 5319 priv_set_t *basic; 5320 5321 basic = priv_str_to_set(BASIC_TOKEN, TOKEN_PRIV_STR, NULL); 5322 if (basic == NULL) 5323 return (errno == ENOMEM ? Z_NOMEM : Z_INVAL); 5324 5325 priv_union(basic, privs); 5326 priv_freeset(basic); 5327 5328 for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) { 5329 if (priv_addset(privs, pnp->pn_priv) != 0) 5330 return (Z_INVAL); 5331 } 5332 5333 return (Z_OK); 5334 } 5335 5336 int 5337 zonecfg_default_brand(char *brand, size_t brandsize) 5338 { 5339 zone_dochandle_t handle; 5340 int myzoneid = getzoneid(); 5341 int ret; 5342 5343 /* 5344 * If we're running within a zone, then the default brand is the 5345 * current zone's brand. 5346 */ 5347 if (myzoneid != GLOBAL_ZONEID) { 5348 ret = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brand, brandsize); 5349 if (ret < 0) 5350 return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL); 5351 return (Z_OK); 5352 } 5353 5354 if ((handle = zonecfg_init_handle()) == NULL) 5355 return (Z_NOMEM); 5356 if ((ret = zonecfg_get_handle("SUNWdefault", handle)) == Z_OK) { 5357 ret = i_zonecfg_get_brand(handle, brand, brandsize, B_TRUE); 5358 zonecfg_fini_handle(handle); 5359 return (ret); 5360 } 5361 return (ret); 5362 } 5363 5364 int 5365 zonecfg_default_privset(priv_set_t *privs, const char *curr_iptype) 5366 { 5367 priv_lists_t *plp; 5368 char buf[MAXNAMELEN]; 5369 int ret; 5370 5371 if ((ret = zonecfg_default_brand(buf, sizeof (buf))) != Z_OK) 5372 return (ret); 5373 if ((ret = priv_lists_create(NULL, buf, &plp, curr_iptype)) != Z_OK) 5374 return (ret); 5375 ret = get_default_privset(privs, plp); 5376 priv_lists_destroy(plp); 5377 return (ret); 5378 } 5379 5380 void 5381 append_priv_token(char *priv, char *str, size_t strlen) 5382 { 5383 if (*str != '\0') 5384 (void) strlcat(str, TOKEN_PRIV_STR, strlen); 5385 (void) strlcat(str, priv, strlen); 5386 } 5387 5388 /* 5389 * Verify that the supplied string is a valid privilege limit set for a 5390 * non-global zone. This string must not only be acceptable to 5391 * priv_str_to_set(3C) which parses it, but it also must resolve to a 5392 * privilege set that includes certain required privileges and lacks 5393 * certain prohibited privileges. 5394 */ 5395 static int 5396 verify_privset(char *privbuf, priv_set_t *privs, char **privname, 5397 boolean_t add_default, priv_lists_t *plp) 5398 { 5399 priv_node_t *pnp; 5400 char *tmp, *cp, *lasts; 5401 size_t len; 5402 priv_set_t *mergeset; 5403 const char *token; 5404 5405 /* 5406 * The verification of the privilege string occurs in several 5407 * phases. In the first phase, the supplied string is scanned for 5408 * the ZONE_TOKEN token which is not support as part of the 5409 * "limitpriv" property. 5410 * 5411 * Duplicate the supplied privilege string since strtok_r(3C) 5412 * tokenizes its input by null-terminating the tokens. 5413 */ 5414 if ((tmp = strdup(privbuf)) == NULL) 5415 return (Z_NOMEM); 5416 for (cp = strtok_r(tmp, TOKEN_PRIV_STR, &lasts); cp != NULL; 5417 cp = strtok_r(NULL, TOKEN_PRIV_STR, &lasts)) { 5418 if (strcmp(cp, ZONE_TOKEN) == 0) { 5419 free(tmp); 5420 if ((*privname = strdup(ZONE_TOKEN)) == NULL) 5421 return (Z_NOMEM); 5422 else 5423 return (Z_PRIV_UNKNOWN); 5424 } 5425 } 5426 free(tmp); 5427 5428 if (add_default) { 5429 /* 5430 * If DEFAULT_TOKEN was specified, a string needs to be 5431 * built containing the privileges from the default, safe 5432 * set along with those of the "limitpriv" property. 5433 */ 5434 len = strlen(privbuf) + sizeof (BASIC_TOKEN) + 2; 5435 5436 for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) 5437 len += strlen(pnp->pn_priv) + 1; 5438 tmp = alloca(len); 5439 *tmp = '\0'; 5440 5441 append_priv_token(BASIC_TOKEN, tmp, len); 5442 for (pnp = plp->pl_default; pnp != NULL; pnp = pnp->pn_next) 5443 append_priv_token(pnp->pn_priv, tmp, len); 5444 (void) strlcat(tmp, TOKEN_PRIV_STR, len); 5445 (void) strlcat(tmp, privbuf, len); 5446 } else { 5447 tmp = privbuf; 5448 } 5449 5450 5451 /* 5452 * In the next phase, attempt to convert the merged privilege 5453 * string into a privilege set. In the case of an error, either 5454 * there was a memory allocation failure or there was an invalid 5455 * privilege token in the string. In either case, return an 5456 * appropriate error code but in the event of an invalid token, 5457 * allocate a string containing its name and return that back to 5458 * the caller. 5459 */ 5460 mergeset = priv_str_to_set(tmp, TOKEN_PRIV_STR, &token); 5461 if (mergeset == NULL) { 5462 if (token == NULL) 5463 return (Z_NOMEM); 5464 if ((cp = strchr(token, TOKEN_PRIV_CHAR)) != NULL) 5465 *cp = '\0'; 5466 if ((*privname = strdup(token)) == NULL) 5467 return (Z_NOMEM); 5468 else 5469 return (Z_PRIV_UNKNOWN); 5470 } 5471 5472 /* 5473 * Next, verify that none of the prohibited zone privileges are 5474 * present in the merged privilege set. 5475 */ 5476 for (pnp = plp->pl_prohibited; pnp != NULL; pnp = pnp->pn_next) { 5477 if (priv_ismember(mergeset, pnp->pn_priv)) { 5478 priv_freeset(mergeset); 5479 if ((*privname = strdup(pnp->pn_priv)) == NULL) 5480 return (Z_NOMEM); 5481 else 5482 return (Z_PRIV_PROHIBITED); 5483 } 5484 } 5485 5486 /* 5487 * Finally, verify that all of the required zone privileges are 5488 * present in the merged privilege set. 5489 */ 5490 for (pnp = plp->pl_required; pnp != NULL; pnp = pnp->pn_next) { 5491 if (!priv_ismember(mergeset, pnp->pn_priv)) { 5492 priv_freeset(mergeset); 5493 if ((*privname = strdup(pnp->pn_priv)) == NULL) 5494 return (Z_NOMEM); 5495 else 5496 return (Z_PRIV_REQUIRED); 5497 } 5498 } 5499 5500 priv_copyset(mergeset, privs); 5501 priv_freeset(mergeset); 5502 return (Z_OK); 5503 } 5504 5505 /* 5506 * Fill in the supplied privilege set with either the default, safe set of 5507 * privileges suitable for a non-global zone, or one based on the 5508 * "limitpriv" property in the zone's configuration. 5509 * 5510 * In the event of an invalid privilege specification in the 5511 * configuration, a string is allocated and returned containing the 5512 * "privilege" causing the issue. It is the caller's responsibility to 5513 * free this memory when it is done with it. 5514 */ 5515 int 5516 zonecfg_get_privset(zone_dochandle_t handle, priv_set_t *privs, 5517 char **privname) 5518 { 5519 priv_lists_t *plp; 5520 char *cp, *limitpriv = NULL; 5521 int err, limitlen; 5522 zone_iptype_t iptype; 5523 const char *curr_iptype; 5524 5525 /* 5526 * Attempt to lookup the "limitpriv" property. If it does not 5527 * exist or matches the string DEFAULT_TOKEN exactly, then the 5528 * default, safe privilege set is returned. 5529 */ 5530 if ((err = zonecfg_get_limitpriv(handle, &limitpriv)) != Z_OK) 5531 return (err); 5532 5533 if ((err = zonecfg_get_iptype(handle, &iptype)) != Z_OK) 5534 return (err); 5535 5536 switch (iptype) { 5537 case ZS_SHARED: 5538 curr_iptype = "shared"; 5539 break; 5540 case ZS_EXCLUSIVE: 5541 curr_iptype = "exclusive"; 5542 break; 5543 } 5544 5545 if ((err = priv_lists_create(handle, NULL, &plp, curr_iptype)) != Z_OK) 5546 return (err); 5547 5548 limitlen = strlen(limitpriv); 5549 if (limitlen == 0 || strcmp(limitpriv, DEFAULT_TOKEN) == 0) { 5550 free(limitpriv); 5551 err = get_default_privset(privs, plp); 5552 priv_lists_destroy(plp); 5553 return (err); 5554 } 5555 5556 /* 5557 * Check if the string DEFAULT_TOKEN is the first token in a list 5558 * of privileges. 5559 */ 5560 cp = strchr(limitpriv, TOKEN_PRIV_CHAR); 5561 if (cp != NULL && 5562 strncmp(limitpriv, DEFAULT_TOKEN, cp - limitpriv) == 0) 5563 err = verify_privset(cp + 1, privs, privname, B_TRUE, plp); 5564 else 5565 err = verify_privset(limitpriv, privs, privname, B_FALSE, plp); 5566 5567 free(limitpriv); 5568 priv_lists_destroy(plp); 5569 return (err); 5570 } 5571 5572 int 5573 zone_get_zonepath(char *zone_name, char *zonepath, size_t rp_sz) 5574 { 5575 zone_dochandle_t handle; 5576 boolean_t found = B_FALSE; 5577 struct zoneent *ze; 5578 FILE *cookie; 5579 int err; 5580 char *cp; 5581 5582 if (zone_name == NULL) 5583 return (Z_INVAL); 5584 5585 (void) strlcpy(zonepath, zonecfg_root, rp_sz); 5586 cp = zonepath + strlen(zonepath); 5587 while (cp > zonepath && cp[-1] == '/') 5588 *--cp = '\0'; 5589 5590 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) { 5591 if (zonepath[0] == '\0') 5592 (void) strlcpy(zonepath, "/", rp_sz); 5593 return (Z_OK); 5594 } 5595 5596 /* 5597 * First check the index file. Because older versions did not have 5598 * a copy of the zone path, allow for it to be zero length, in which 5599 * case we ignore this result and fall back to the XML files. 5600 */ 5601 cookie = setzoneent(); 5602 while ((ze = getzoneent_private(cookie)) != NULL) { 5603 if (strcmp(ze->zone_name, zone_name) == 0) { 5604 found = B_TRUE; 5605 if (ze->zone_path[0] != '\0') 5606 (void) strlcpy(cp, ze->zone_path, 5607 rp_sz - (cp - zonepath)); 5608 } 5609 free(ze); 5610 if (found) 5611 break; 5612 } 5613 endzoneent(cookie); 5614 if (found && *cp != '\0') 5615 return (Z_OK); 5616 5617 /* Fall back to the XML files. */ 5618 if ((handle = zonecfg_init_handle()) == NULL) 5619 return (Z_NOMEM); 5620 5621 /* 5622 * Check the snapshot first: if a zone is running, its zonepath 5623 * may have changed. 5624 */ 5625 if (zonecfg_get_snapshot_handle(zone_name, handle) != Z_OK) { 5626 if ((err = zonecfg_get_handle(zone_name, handle)) != Z_OK) { 5627 zonecfg_fini_handle(handle); 5628 return (err); 5629 } 5630 } 5631 err = zonecfg_get_zonepath(handle, zonepath, rp_sz); 5632 zonecfg_fini_handle(handle); 5633 return (err); 5634 } 5635 5636 int 5637 zone_get_rootpath(char *zone_name, char *rootpath, size_t rp_sz) 5638 { 5639 int err; 5640 5641 /* This function makes sense for non-global zones only. */ 5642 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) 5643 return (Z_BOGUS_ZONE_NAME); 5644 if ((err = zone_get_zonepath(zone_name, rootpath, rp_sz)) != Z_OK) 5645 return (err); 5646 if (strlcat(rootpath, "/root", rp_sz) >= rp_sz) 5647 return (Z_TOO_BIG); 5648 return (Z_OK); 5649 } 5650 5651 int 5652 zone_get_brand(char *zone_name, char *brandname, size_t rp_sz) 5653 { 5654 int err; 5655 zone_dochandle_t handle; 5656 char myzone[MAXNAMELEN]; 5657 int myzoneid = getzoneid(); 5658 5659 /* 5660 * If we are not in the global zone, then we don't have the zone 5661 * .xml files with the brand name available. Thus, we are going to 5662 * have to ask the kernel for the information. 5663 */ 5664 if (myzoneid != GLOBAL_ZONEID) { 5665 if (is_system_labeled()) { 5666 (void) strlcpy(brandname, NATIVE_BRAND_NAME, rp_sz); 5667 return (Z_OK); 5668 } 5669 if (zone_getattr(myzoneid, ZONE_ATTR_NAME, myzone, 5670 sizeof (myzone)) < 0) 5671 return (Z_NO_ZONE); 5672 if (!zonecfg_is_scratch(myzone)) { 5673 if (strncmp(zone_name, myzone, MAXNAMELEN) != 0) 5674 return (Z_NO_ZONE); 5675 } 5676 err = zone_getattr(myzoneid, ZONE_ATTR_BRAND, brandname, rp_sz); 5677 if (err < 0) 5678 return ((errno == EFAULT) ? Z_TOO_BIG : Z_INVAL); 5679 5680 return (Z_OK); 5681 } 5682 5683 if (strcmp(zone_name, "global") == 0) 5684 return (zonecfg_default_brand(brandname, rp_sz)); 5685 5686 if ((handle = zonecfg_init_handle()) == NULL) 5687 return (Z_NOMEM); 5688 5689 err = zonecfg_get_handle((char *)zone_name, handle); 5690 if (err == Z_OK) 5691 err = zonecfg_get_brand(handle, brandname, rp_sz); 5692 5693 zonecfg_fini_handle(handle); 5694 return (err); 5695 } 5696 5697 /* 5698 * Return the appropriate root for the active /dev. 5699 * For normal zone, the path is $ZONEPATH/root; 5700 * for scratch zone, the dev path is $ZONEPATH/lu. 5701 */ 5702 int 5703 zone_get_devroot(char *zone_name, char *devroot, size_t rp_sz) 5704 { 5705 int err; 5706 char *suffix; 5707 zone_state_t state; 5708 5709 /* This function makes sense for non-global zones only. */ 5710 if (strcmp(zone_name, GLOBAL_ZONENAME) == 0) 5711 return (Z_BOGUS_ZONE_NAME); 5712 if ((err = zone_get_zonepath(zone_name, devroot, rp_sz)) != Z_OK) 5713 return (err); 5714 5715 if (zone_get_state(zone_name, &state) == Z_OK && 5716 state == ZONE_STATE_MOUNTED) 5717 suffix = "/lu"; 5718 else 5719 suffix = "/root"; 5720 if (strlcat(devroot, suffix, rp_sz) >= rp_sz) 5721 return (Z_TOO_BIG); 5722 return (Z_OK); 5723 } 5724 5725 static zone_state_t 5726 kernel_state_to_user_state(zoneid_t zoneid, zone_status_t kernel_state) 5727 { 5728 char zoneroot[MAXPATHLEN]; 5729 size_t zlen; 5730 5731 assert(kernel_state <= ZONE_MAX_STATE); 5732 switch (kernel_state) { 5733 case ZONE_IS_UNINITIALIZED: 5734 case ZONE_IS_INITIALIZED: 5735 /* The kernel will not return these two states */ 5736 return (ZONE_STATE_READY); 5737 case ZONE_IS_READY: 5738 /* 5739 * If the zone's root is mounted on $ZONEPATH/lu, then 5740 * it's a mounted scratch zone. 5741 */ 5742 if (zone_getattr(zoneid, ZONE_ATTR_ROOT, zoneroot, 5743 sizeof (zoneroot)) >= 0) { 5744 zlen = strlen(zoneroot); 5745 if (zlen > 3 && 5746 strcmp(zoneroot + zlen - 3, "/lu") == 0) 5747 return (ZONE_STATE_MOUNTED); 5748 } 5749 return (ZONE_STATE_READY); 5750 case ZONE_IS_BOOTING: 5751 case ZONE_IS_RUNNING: 5752 return (ZONE_STATE_RUNNING); 5753 case ZONE_IS_SHUTTING_DOWN: 5754 case ZONE_IS_EMPTY: 5755 return (ZONE_STATE_SHUTTING_DOWN); 5756 case ZONE_IS_DOWN: 5757 case ZONE_IS_DYING: 5758 case ZONE_IS_DEAD: 5759 default: 5760 return (ZONE_STATE_DOWN); 5761 } 5762 /* NOTREACHED */ 5763 } 5764 5765 int 5766 zone_get_state(char *zone_name, zone_state_t *state_num) 5767 { 5768 zone_status_t status; 5769 zoneid_t zone_id; 5770 struct zoneent *ze; 5771 boolean_t found = B_FALSE; 5772 FILE *cookie; 5773 char kernzone[ZONENAME_MAX]; 5774 FILE *fp; 5775 5776 if (zone_name == NULL) 5777 return (Z_INVAL); 5778 5779 /* 5780 * If we're looking at an alternate root, then we need to query the 5781 * kernel using the scratch zone name. 5782 */ 5783 zone_id = -1; 5784 if (*zonecfg_root != '\0' && !zonecfg_is_scratch(zone_name)) { 5785 if ((fp = zonecfg_open_scratch("", B_FALSE)) != NULL) { 5786 if (zonecfg_find_scratch(fp, zone_name, zonecfg_root, 5787 kernzone, sizeof (kernzone)) == 0) 5788 zone_id = getzoneidbyname(kernzone); 5789 zonecfg_close_scratch(fp); 5790 } 5791 } else { 5792 zone_id = getzoneidbyname(zone_name); 5793 } 5794 5795 /* check to see if zone is running */ 5796 if (zone_id != -1 && 5797 zone_getattr(zone_id, ZONE_ATTR_STATUS, &status, 5798 sizeof (status)) >= 0) { 5799 *state_num = kernel_state_to_user_state(zone_id, status); 5800 return (Z_OK); 5801 } 5802 5803 cookie = setzoneent(); 5804 while ((ze = getzoneent_private(cookie)) != NULL) { 5805 if (strcmp(ze->zone_name, zone_name) == 0) { 5806 found = B_TRUE; 5807 *state_num = ze->zone_state; 5808 } 5809 free(ze); 5810 if (found) 5811 break; 5812 } 5813 endzoneent(cookie); 5814 return ((found) ? Z_OK : Z_NO_ZONE); 5815 } 5816 5817 int 5818 zone_set_state(char *zone, zone_state_t state) 5819 { 5820 struct zoneent ze; 5821 5822 if (state != ZONE_STATE_CONFIGURED && state != ZONE_STATE_INSTALLED && 5823 state != ZONE_STATE_INCOMPLETE) 5824 return (Z_INVAL); 5825 5826 bzero(&ze, sizeof (ze)); 5827 (void) strlcpy(ze.zone_name, zone, sizeof (ze.zone_name)); 5828 ze.zone_state = state; 5829 (void) strlcpy(ze.zone_path, "", sizeof (ze.zone_path)); 5830 return (putzoneent(&ze, PZE_MODIFY)); 5831 } 5832 5833 /* 5834 * Get id (if any) for specified zone. There are four possible outcomes: 5835 * - If the string corresponds to the numeric id of an active (booted) 5836 * zone, sets *zip to the zone id and returns 0. 5837 * - If the string corresponds to the name of an active (booted) zone, 5838 * sets *zip to the zone id and returns 0. 5839 * - If the string is a name in the configuration but is not booted, 5840 * sets *zip to ZONE_ID_UNDEFINED and returns 0. 5841 * - Otherwise, leaves *zip unchanged and returns -1. 5842 * 5843 * This function acts as an auxiliary filter on the function of the same 5844 * name in libc; the linker binds to this version if libzonecfg exists, 5845 * and the libc version if it doesn't. Any changes to this version of 5846 * the function should probably be reflected in the libc version as well. 5847 */ 5848 int 5849 zone_get_id(const char *str, zoneid_t *zip) 5850 { 5851 zone_dochandle_t hdl; 5852 zoneid_t zoneid; 5853 char *cp; 5854 int err; 5855 5856 /* first try looking for active zone by id */ 5857 errno = 0; 5858 zoneid = (zoneid_t)strtol(str, &cp, 0); 5859 if (errno == 0 && cp != str && *cp == '\0' && 5860 getzonenamebyid(zoneid, NULL, 0) != -1) { 5861 *zip = zoneid; 5862 return (0); 5863 } 5864 5865 /* then look for active zone by name */ 5866 if ((zoneid = getzoneidbyname(str)) != -1) { 5867 *zip = zoneid; 5868 return (0); 5869 } 5870 5871 /* if in global zone, try looking up name in configuration database */ 5872 if (getzoneid() != GLOBAL_ZONEID || 5873 (hdl = zonecfg_init_handle()) == NULL) 5874 return (-1); 5875 5876 if (zonecfg_get_handle(str, hdl) == Z_OK) { 5877 /* zone exists but isn't active */ 5878 *zip = ZONE_ID_UNDEFINED; 5879 err = 0; 5880 } else { 5881 err = -1; 5882 } 5883 5884 zonecfg_fini_handle(hdl); 5885 return (err); 5886 } 5887 5888 char * 5889 zone_state_str(zone_state_t state_num) 5890 { 5891 switch (state_num) { 5892 case ZONE_STATE_CONFIGURED: 5893 return (ZONE_STATE_STR_CONFIGURED); 5894 case ZONE_STATE_INCOMPLETE: 5895 return (ZONE_STATE_STR_INCOMPLETE); 5896 case ZONE_STATE_INSTALLED: 5897 return (ZONE_STATE_STR_INSTALLED); 5898 case ZONE_STATE_READY: 5899 return (ZONE_STATE_STR_READY); 5900 case ZONE_STATE_MOUNTED: 5901 return (ZONE_STATE_STR_MOUNTED); 5902 case ZONE_STATE_RUNNING: 5903 return (ZONE_STATE_STR_RUNNING); 5904 case ZONE_STATE_SHUTTING_DOWN: 5905 return (ZONE_STATE_STR_SHUTTING_DOWN); 5906 case ZONE_STATE_DOWN: 5907 return (ZONE_STATE_STR_DOWN); 5908 default: 5909 return ("unknown"); 5910 } 5911 } 5912 5913 /* 5914 * Given a UUID value, find an associated zone name. This is intended to be 5915 * used by callers who set up some 'default' name (corresponding to the 5916 * expected name for the zone) in the zonename buffer, and thus the function 5917 * doesn't touch this buffer on failure. 5918 */ 5919 int 5920 zonecfg_get_name_by_uuid(const uuid_t uuidin, char *zonename, size_t namelen) 5921 { 5922 FILE *fp; 5923 struct zoneent *ze; 5924 uchar_t *uuid; 5925 5926 /* 5927 * A small amount of subterfuge via casts is necessary here because 5928 * libuuid doesn't use const correctly, but we don't want to export 5929 * this brokenness to our clients. 5930 */ 5931 uuid = (uchar_t *)uuidin; 5932 if (uuid_is_null(uuid)) 5933 return (Z_NO_ZONE); 5934 if ((fp = setzoneent()) == NULL) 5935 return (Z_NO_ZONE); 5936 while ((ze = getzoneent_private(fp)) != NULL) { 5937 if (uuid_compare(uuid, ze->zone_uuid) == 0) 5938 break; 5939 free(ze); 5940 } 5941 endzoneent(fp); 5942 if (ze != NULL) { 5943 (void) strlcpy(zonename, ze->zone_name, namelen); 5944 free(ze); 5945 return (Z_OK); 5946 } else { 5947 return (Z_NO_ZONE); 5948 } 5949 } 5950 5951 /* 5952 * Given a zone name, get its UUID. Returns a "NULL" UUID value if the zone 5953 * exists but the file doesn't have a value set yet. Returns an error if the 5954 * zone cannot be located. 5955 */ 5956 int 5957 zonecfg_get_uuid(const char *zonename, uuid_t uuid) 5958 { 5959 FILE *fp; 5960 struct zoneent *ze; 5961 5962 if ((fp = setzoneent()) == NULL) 5963 return (Z_NO_ZONE); 5964 while ((ze = getzoneent_private(fp)) != NULL) { 5965 if (strcmp(ze->zone_name, zonename) == 0) 5966 break; 5967 free(ze); 5968 } 5969 endzoneent(fp); 5970 if (ze != NULL) { 5971 uuid_copy(uuid, ze->zone_uuid); 5972 free(ze); 5973 return (Z_OK); 5974 } else { 5975 return (Z_NO_ZONE); 5976 } 5977 } 5978 5979 /* 5980 * File-system convenience functions. 5981 */ 5982 boolean_t 5983 zonecfg_valid_fs_type(const char *type) 5984 { 5985 /* 5986 * We already know which FS types don't work. 5987 */ 5988 if (strcmp(type, "proc") == 0 || 5989 strcmp(type, "mntfs") == 0 || 5990 strcmp(type, "autofs") == 0 || 5991 strncmp(type, "nfs", sizeof ("nfs") - 1) == 0 || 5992 strcmp(type, "cachefs") == 0) 5993 return (B_FALSE); 5994 /* 5995 * The caller may do more detailed verification to make sure other 5996 * aspects of this filesystem type make sense. 5997 */ 5998 return (B_TRUE); 5999 } 6000 6001 /* 6002 * Generally uninteresting rctl convenience functions. 6003 */ 6004 6005 int 6006 zonecfg_construct_rctlblk(const struct zone_rctlvaltab *rctlval, 6007 rctlblk_t *rctlblk) 6008 { 6009 unsigned long long ull; 6010 char *endp; 6011 rctl_priv_t priv; 6012 rctl_qty_t limit; 6013 uint_t action; 6014 6015 /* Get the privilege */ 6016 if (strcmp(rctlval->zone_rctlval_priv, "basic") == 0) { 6017 priv = RCPRIV_BASIC; 6018 } else if (strcmp(rctlval->zone_rctlval_priv, "privileged") == 0) { 6019 priv = RCPRIV_PRIVILEGED; 6020 } else { 6021 /* Invalid privilege */ 6022 return (Z_INVAL); 6023 } 6024 6025 /* deal with negative input; strtoull(3c) doesn't do what we want */ 6026 if (rctlval->zone_rctlval_limit[0] == '-') 6027 return (Z_INVAL); 6028 /* Get the limit */ 6029 errno = 0; 6030 ull = strtoull(rctlval->zone_rctlval_limit, &endp, 0); 6031 if (errno != 0 || *endp != '\0') { 6032 /* parse failed */ 6033 return (Z_INVAL); 6034 } 6035 limit = (rctl_qty_t)ull; 6036 6037 /* Get the action */ 6038 if (strcmp(rctlval->zone_rctlval_action, "none") == 0) { 6039 action = RCTL_LOCAL_NOACTION; 6040 } else if (strcmp(rctlval->zone_rctlval_action, "signal") == 0) { 6041 action = RCTL_LOCAL_SIGNAL; 6042 } else if (strcmp(rctlval->zone_rctlval_action, "deny") == 0) { 6043 action = RCTL_LOCAL_DENY; 6044 } else { 6045 /* Invalid Action */ 6046 return (Z_INVAL); 6047 } 6048 rctlblk_set_local_action(rctlblk, action, 0); 6049 rctlblk_set_privilege(rctlblk, priv); 6050 rctlblk_set_value(rctlblk, limit); 6051 return (Z_OK); 6052 } 6053 6054 static int 6055 rctl_check(const char *rctlname, void *arg) 6056 { 6057 const char *attrname = arg; 6058 6059 /* 6060 * Returning 1 here is our signal to zonecfg_is_rctl() that it is 6061 * indeed an rctl name recognized by the system. 6062 */ 6063 return (strcmp(rctlname, attrname) == 0 ? 1 : 0); 6064 } 6065 6066 boolean_t 6067 zonecfg_is_rctl(const char *name) 6068 { 6069 return (rctl_walk(rctl_check, (void *)name) == 1); 6070 } 6071 6072 boolean_t 6073 zonecfg_valid_rctlname(const char *name) 6074 { 6075 const char *c; 6076 6077 if (strncmp(name, "zone.", sizeof ("zone.") - 1) != 0) 6078 return (B_FALSE); 6079 if (strlen(name) == sizeof ("zone.") - 1) 6080 return (B_FALSE); 6081 for (c = name + sizeof ("zone.") - 1; *c != '\0'; c++) { 6082 if (!isalpha(*c) && *c != '-') 6083 return (B_FALSE); 6084 } 6085 return (B_TRUE); 6086 } 6087 6088 boolean_t 6089 zonecfg_valid_rctlblk(const rctlblk_t *rctlblk) 6090 { 6091 rctl_priv_t priv = rctlblk_get_privilege((rctlblk_t *)rctlblk); 6092 uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL); 6093 6094 if (priv != RCPRIV_PRIVILEGED) 6095 return (B_FALSE); 6096 if (action != RCTL_LOCAL_NOACTION && action != RCTL_LOCAL_DENY) 6097 return (B_FALSE); 6098 return (B_TRUE); 6099 } 6100 6101 boolean_t 6102 zonecfg_valid_rctl(const char *name, const rctlblk_t *rctlblk) 6103 { 6104 rctlblk_t *current, *next; 6105 rctl_qty_t limit = rctlblk_get_value((rctlblk_t *)rctlblk); 6106 uint_t action = rctlblk_get_local_action((rctlblk_t *)rctlblk, NULL); 6107 uint_t global_flags; 6108 6109 if (!zonecfg_valid_rctlblk(rctlblk)) 6110 return (B_FALSE); 6111 if (!zonecfg_valid_rctlname(name)) 6112 return (B_FALSE); 6113 6114 current = alloca(rctlblk_size()); 6115 if (getrctl(name, NULL, current, RCTL_FIRST) != 0) 6116 return (B_TRUE); /* not an rctl on this system */ 6117 /* 6118 * Make sure the proposed value isn't greater than the current system 6119 * value. 6120 */ 6121 next = alloca(rctlblk_size()); 6122 while (rctlblk_get_privilege(current) != RCPRIV_SYSTEM) { 6123 rctlblk_t *tmp; 6124 6125 if (getrctl(name, current, next, RCTL_NEXT) != 0) 6126 return (B_FALSE); /* shouldn't happen */ 6127 tmp = current; 6128 current = next; 6129 next = tmp; 6130 } 6131 if (limit > rctlblk_get_value(current)) 6132 return (B_FALSE); 6133 6134 /* 6135 * Make sure the proposed action is allowed. 6136 */ 6137 global_flags = rctlblk_get_global_flags(current); 6138 if ((global_flags & RCTL_GLOBAL_DENY_NEVER) && 6139 action == RCTL_LOCAL_DENY) 6140 return (B_FALSE); 6141 if ((global_flags & RCTL_GLOBAL_DENY_ALWAYS) && 6142 action == RCTL_LOCAL_NOACTION) 6143 return (B_FALSE); 6144 6145 return (B_TRUE); 6146 } 6147 6148 /* 6149 * There is always a race condition between reading the initial copy of 6150 * a zones state and its state changing. We address this by providing 6151 * zonecfg_notify_critical_enter and zonecfg_noticy_critical_exit functions. 6152 * When zonecfg_critical_enter is called, sets the state field to LOCKED 6153 * and aquires biglock. Biglock protects against other threads executing 6154 * critical_enter and the state field protects against state changes during 6155 * the critical period. 6156 * 6157 * If any state changes occur, zn_cb will set the failed field of the znotify 6158 * structure. This will cause the critical_exit function to re-lock the 6159 * channel and return an error. Since evsnts may be delayed, the critical_exit 6160 * function "flushes" the queue by putting an event on the queue and waiting for 6161 * zn_cb to notify critical_exit that it received the ping event. 6162 */ 6163 static const char * 6164 string_get_tok(const char *in, char delim, int num) 6165 { 6166 int i = 0; 6167 6168 for (; i < num; in++) { 6169 if (*in == delim) 6170 i++; 6171 if (*in == 0) 6172 return (NULL); 6173 } 6174 return (in); 6175 } 6176 6177 static boolean_t 6178 is_ping(sysevent_t *ev) 6179 { 6180 if (strcmp(sysevent_get_subclass_name(ev), 6181 ZONE_EVENT_PING_SUBCLASS) == 0) { 6182 return (B_TRUE); 6183 } else { 6184 return (B_FALSE); 6185 } 6186 } 6187 6188 static boolean_t 6189 is_my_ping(sysevent_t *ev) 6190 { 6191 const char *sender; 6192 char mypid[sizeof (pid_t) * 3 + 1]; 6193 6194 (void) snprintf(mypid, sizeof (mypid), "%i", getpid()); 6195 sender = string_get_tok(sysevent_get_pub(ev), ':', 3); 6196 if (sender == NULL) 6197 return (B_FALSE); 6198 if (strcmp(sender, mypid) != 0) 6199 return (B_FALSE); 6200 return (B_TRUE); 6201 } 6202 6203 static int 6204 do_callback(struct znotify *zevtchan, sysevent_t *ev) 6205 { 6206 nvlist_t *l; 6207 int zid; 6208 char *zonename; 6209 char *newstate; 6210 char *oldstate; 6211 int ret; 6212 hrtime_t when; 6213 6214 if (strcmp(sysevent_get_subclass_name(ev), 6215 ZONE_EVENT_STATUS_SUBCLASS) == 0) { 6216 6217 if (sysevent_get_attr_list(ev, &l) != 0) { 6218 if (errno == ENOMEM) { 6219 zevtchan->zn_failure_count++; 6220 return (EAGAIN); 6221 } 6222 return (0); 6223 } 6224 ret = 0; 6225 6226 if ((nvlist_lookup_string(l, ZONE_CB_NAME, &zonename) == 0) && 6227 (nvlist_lookup_string(l, ZONE_CB_NEWSTATE, &newstate) 6228 == 0) && 6229 (nvlist_lookup_string(l, ZONE_CB_OLDSTATE, &oldstate) 6230 == 0) && 6231 (nvlist_lookup_uint64(l, ZONE_CB_TIMESTAMP, 6232 (uint64_t *)&when) == 0) && 6233 (nvlist_lookup_int32(l, ZONE_CB_ZONEID, &zid) == 0)) { 6234 ret = zevtchan->zn_callback(zonename, zid, newstate, 6235 oldstate, when, zevtchan->zn_private); 6236 } 6237 6238 zevtchan->zn_failure_count = 0; 6239 nvlist_free(l); 6240 return (ret); 6241 } else { 6242 /* 6243 * We have received an event in an unknown subclass. Ignore. 6244 */ 6245 zevtchan->zn_failure_count = 0; 6246 return (0); 6247 } 6248 } 6249 6250 static int 6251 zn_cb(sysevent_t *ev, void *p) 6252 { 6253 struct znotify *zevtchan = p; 6254 int error; 6255 6256 (void) pthread_mutex_lock(&(zevtchan->zn_mutex)); 6257 6258 if (is_ping(ev) && !is_my_ping(ev)) { 6259 (void) pthread_mutex_unlock((&zevtchan->zn_mutex)); 6260 return (0); 6261 } 6262 6263 if (zevtchan->zn_state == ZN_LOCKED) { 6264 assert(!is_ping(ev)); 6265 zevtchan->zn_failed = B_TRUE; 6266 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 6267 return (0); 6268 } 6269 6270 if (zevtchan->zn_state == ZN_PING_INFLIGHT) { 6271 if (is_ping(ev)) { 6272 zevtchan->zn_state = ZN_PING_RECEIVED; 6273 (void) pthread_cond_signal(&(zevtchan->zn_cond)); 6274 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 6275 return (0); 6276 } else { 6277 zevtchan->zn_failed = B_TRUE; 6278 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 6279 return (0); 6280 } 6281 } 6282 6283 if (zevtchan->zn_state == ZN_UNLOCKED) { 6284 6285 error = do_callback(zevtchan, ev); 6286 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 6287 /* 6288 * Every ENOMEM failure causes do_callback to increment 6289 * zn_failure_count and every success causes it to 6290 * set zn_failure_count to zero. If we got EAGAIN, 6291 * we will sleep for zn_failure_count seconds and return 6292 * EAGAIN to gpec to try again. 6293 * 6294 * After 55 seconds, or 10 try's we give up and drop the 6295 * event. 6296 */ 6297 if (error == EAGAIN) { 6298 if (zevtchan->zn_failure_count > ZONE_CB_RETRY_COUNT) { 6299 return (0); 6300 } 6301 (void) sleep(zevtchan->zn_failure_count); 6302 } 6303 return (error); 6304 } 6305 6306 if (zevtchan->zn_state == ZN_PING_RECEIVED) { 6307 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 6308 return (0); 6309 } 6310 6311 abort(); 6312 return (0); 6313 } 6314 6315 void 6316 zonecfg_notify_critical_enter(void *h) 6317 { 6318 struct znotify *zevtchan = h; 6319 6320 (void) pthread_mutex_lock(&(zevtchan->zn_bigmutex)); 6321 zevtchan->zn_state = ZN_LOCKED; 6322 } 6323 6324 int 6325 zonecfg_notify_critical_exit(void * h) 6326 { 6327 6328 struct znotify *zevtchan = h; 6329 6330 if (zevtchan->zn_state == ZN_UNLOCKED) 6331 return (0); 6332 6333 (void) pthread_mutex_lock(&(zevtchan->zn_mutex)); 6334 zevtchan->zn_state = ZN_PING_INFLIGHT; 6335 6336 (void) sysevent_evc_publish(zevtchan->zn_eventchan, 6337 ZONE_EVENT_STATUS_CLASS, 6338 ZONE_EVENT_PING_SUBCLASS, ZONE_EVENT_PING_PUBLISHER, 6339 zevtchan->zn_subscriber_id, NULL, EVCH_SLEEP); 6340 6341 while (zevtchan->zn_state != ZN_PING_RECEIVED) { 6342 (void) pthread_cond_wait(&(zevtchan->zn_cond), 6343 &(zevtchan->zn_mutex)); 6344 } 6345 6346 if (zevtchan->zn_failed == B_TRUE) { 6347 zevtchan->zn_state = ZN_LOCKED; 6348 zevtchan->zn_failed = B_FALSE; 6349 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 6350 return (1); 6351 } 6352 6353 zevtchan->zn_state = ZN_UNLOCKED; 6354 (void) pthread_mutex_unlock(&(zevtchan->zn_mutex)); 6355 (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex)); 6356 return (0); 6357 } 6358 6359 void 6360 zonecfg_notify_critical_abort(void *h) 6361 { 6362 struct znotify *zevtchan = h; 6363 6364 zevtchan->zn_state = ZN_UNLOCKED; 6365 zevtchan->zn_failed = B_FALSE; 6366 /* 6367 * Don't do anything about zn_lock. If it is held, it could only be 6368 * held by zn_cb and it will be unlocked soon. 6369 */ 6370 (void) pthread_mutex_unlock(&(zevtchan->zn_bigmutex)); 6371 } 6372 6373 void * 6374 zonecfg_notify_bind(int(*func)(const char *zonename, zoneid_t zid, 6375 const char *newstate, const char *oldstate, hrtime_t when, void *p), 6376 void *p) 6377 { 6378 struct znotify *zevtchan; 6379 int i = 1; 6380 int r; 6381 6382 zevtchan = malloc(sizeof (struct znotify)); 6383 6384 if (zevtchan == NULL) 6385 return (NULL); 6386 6387 zevtchan->zn_private = p; 6388 zevtchan->zn_callback = func; 6389 zevtchan->zn_state = ZN_UNLOCKED; 6390 zevtchan->zn_failed = B_FALSE; 6391 6392 if (pthread_mutex_init(&(zevtchan->zn_mutex), NULL)) 6393 goto out3; 6394 if (pthread_cond_init(&(zevtchan->zn_cond), NULL)) { 6395 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex)); 6396 goto out3; 6397 } 6398 if (pthread_mutex_init(&(zevtchan->zn_bigmutex), NULL)) { 6399 (void) pthread_mutex_destroy(&(zevtchan->zn_mutex)); 6400 (void) pthread_cond_destroy(&(zevtchan->zn_cond)); 6401 goto out3; 6402 } 6403 6404 if (sysevent_evc_bind(ZONE_EVENT_CHANNEL, &(zevtchan->zn_eventchan), 6405 0) != 0) 6406 goto out2; 6407 6408 do { 6409 /* 6410 * At 4 digits the subscriber ID gets too long and we have 6411 * no chance of successfully registering. 6412 */ 6413 if (i > 999) 6414 goto out1; 6415 6416 (void) sprintf(zevtchan->zn_subscriber_id, "zone_%li_%i", 6417 getpid() % 999999l, i); 6418 6419 r = sysevent_evc_subscribe(zevtchan->zn_eventchan, 6420 zevtchan->zn_subscriber_id, ZONE_EVENT_STATUS_CLASS, zn_cb, 6421 zevtchan, 0); 6422 6423 i++; 6424 6425 } while (r); 6426 6427 return (zevtchan); 6428 out1: 6429 (void) sysevent_evc_unbind(zevtchan->zn_eventchan); 6430 out2: 6431 (void) pthread_mutex_destroy(&zevtchan->zn_mutex); 6432 (void) pthread_cond_destroy(&zevtchan->zn_cond); 6433 (void) pthread_mutex_destroy(&(zevtchan->zn_bigmutex)); 6434 out3: 6435 free(zevtchan); 6436 6437 return (NULL); 6438 } 6439 6440 void 6441 zonecfg_notify_unbind(void *handle) 6442 { 6443 6444 int ret; 6445 6446 (void) sysevent_evc_unbind(((struct znotify *)handle)->zn_eventchan); 6447 /* 6448 * Check that all evc threads have gone away. This should be 6449 * enforced by sysevent_evc_unbind. 6450 */ 6451 ret = pthread_mutex_trylock(&((struct znotify *)handle)->zn_mutex); 6452 6453 if (ret) 6454 abort(); 6455 6456 (void) pthread_mutex_unlock(&((struct znotify *)handle)->zn_mutex); 6457 (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_mutex); 6458 (void) pthread_cond_destroy(&((struct znotify *)handle)->zn_cond); 6459 (void) pthread_mutex_destroy(&((struct znotify *)handle)->zn_bigmutex); 6460 6461 free(handle); 6462 } 6463 6464 static int 6465 zonecfg_add_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr) 6466 { 6467 xmlNodePtr newnode, cur = handle->zone_dh_cur; 6468 int err; 6469 6470 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_DATASET, NULL); 6471 if ((err = newprop(newnode, DTD_ATTR_NAME, 6472 tabptr->zone_dataset_name)) != Z_OK) 6473 return (err); 6474 return (Z_OK); 6475 } 6476 6477 int 6478 zonecfg_add_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 6479 { 6480 int err; 6481 6482 if (tabptr == NULL) 6483 return (Z_INVAL); 6484 6485 if ((err = operation_prep(handle)) != Z_OK) 6486 return (err); 6487 6488 if ((err = zonecfg_add_ds_core(handle, tabptr)) != Z_OK) 6489 return (err); 6490 6491 return (Z_OK); 6492 } 6493 6494 static int 6495 zonecfg_delete_ds_core(zone_dochandle_t handle, struct zone_dstab *tabptr) 6496 { 6497 xmlNodePtr cur = handle->zone_dh_cur; 6498 6499 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6500 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 6501 continue; 6502 6503 if (match_prop(cur, DTD_ATTR_NAME, 6504 tabptr->zone_dataset_name)) { 6505 xmlUnlinkNode(cur); 6506 xmlFreeNode(cur); 6507 return (Z_OK); 6508 } 6509 } 6510 return (Z_NO_RESOURCE_ID); 6511 } 6512 6513 int 6514 zonecfg_delete_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 6515 { 6516 int err; 6517 6518 if (tabptr == NULL) 6519 return (Z_INVAL); 6520 6521 if ((err = operation_prep(handle)) != Z_OK) 6522 return (err); 6523 6524 if ((err = zonecfg_delete_ds_core(handle, tabptr)) != Z_OK) 6525 return (err); 6526 6527 return (Z_OK); 6528 } 6529 6530 int 6531 zonecfg_modify_ds( 6532 zone_dochandle_t handle, 6533 struct zone_dstab *oldtabptr, 6534 struct zone_dstab *newtabptr) 6535 { 6536 int err; 6537 6538 if (oldtabptr == NULL || newtabptr == NULL) 6539 return (Z_INVAL); 6540 6541 if ((err = operation_prep(handle)) != Z_OK) 6542 return (err); 6543 6544 if ((err = zonecfg_delete_ds_core(handle, oldtabptr)) != Z_OK) 6545 return (err); 6546 6547 if ((err = zonecfg_add_ds_core(handle, newtabptr)) != Z_OK) 6548 return (err); 6549 6550 return (Z_OK); 6551 } 6552 6553 int 6554 zonecfg_lookup_ds(zone_dochandle_t handle, struct zone_dstab *tabptr) 6555 { 6556 xmlNodePtr cur, firstmatch; 6557 int err; 6558 char dataset[MAXNAMELEN]; 6559 6560 if (tabptr == NULL) 6561 return (Z_INVAL); 6562 6563 if ((err = operation_prep(handle)) != Z_OK) 6564 return (err); 6565 6566 cur = handle->zone_dh_cur; 6567 firstmatch = NULL; 6568 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6569 if (xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 6570 continue; 6571 if (strlen(tabptr->zone_dataset_name) > 0) { 6572 if ((fetchprop(cur, DTD_ATTR_NAME, dataset, 6573 sizeof (dataset)) == Z_OK) && 6574 (strcmp(tabptr->zone_dataset_name, 6575 dataset) == 0)) { 6576 if (firstmatch == NULL) 6577 firstmatch = cur; 6578 else 6579 return (Z_INSUFFICIENT_SPEC); 6580 } 6581 } 6582 } 6583 if (firstmatch == NULL) 6584 return (Z_NO_RESOURCE_ID); 6585 6586 cur = firstmatch; 6587 6588 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name, 6589 sizeof (tabptr->zone_dataset_name))) != Z_OK) 6590 return (err); 6591 6592 return (Z_OK); 6593 } 6594 6595 int 6596 zonecfg_setdsent(zone_dochandle_t handle) 6597 { 6598 return (zonecfg_setent(handle)); 6599 } 6600 6601 int 6602 zonecfg_getdsent(zone_dochandle_t handle, struct zone_dstab *tabptr) 6603 { 6604 xmlNodePtr cur; 6605 int err; 6606 6607 if (handle == NULL) 6608 return (Z_INVAL); 6609 6610 if ((cur = handle->zone_dh_cur) == NULL) 6611 return (Z_NO_ENTRY); 6612 6613 for (; cur != NULL; cur = cur->next) 6614 if (!xmlStrcmp(cur->name, DTD_ELEM_DATASET)) 6615 break; 6616 if (cur == NULL) { 6617 handle->zone_dh_cur = handle->zone_dh_top; 6618 return (Z_NO_ENTRY); 6619 } 6620 6621 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_dataset_name, 6622 sizeof (tabptr->zone_dataset_name))) != Z_OK) { 6623 handle->zone_dh_cur = handle->zone_dh_top; 6624 return (err); 6625 } 6626 6627 handle->zone_dh_cur = cur->next; 6628 return (Z_OK); 6629 } 6630 6631 int 6632 zonecfg_enddsent(zone_dochandle_t handle) 6633 { 6634 return (zonecfg_endent(handle)); 6635 } 6636 6637 /* 6638 * Support for aliased rctls; that is, rctls that have simplified names in 6639 * zonecfg. For example, max-lwps is an alias for a well defined zone.max-lwps 6640 * rctl. If there are multiple existing values for one of these rctls or if 6641 * there is a single value that does not match the well defined template (i.e. 6642 * it has a different action) then we cannot treat the rctl as having an alias 6643 * so we return Z_ALIAS_DISALLOW. That means that the rctl cannot be 6644 * managed in zonecfg via an alias and that the standard rctl syntax must be 6645 * used. 6646 * 6647 * The possible return values are: 6648 * Z_NO_PROPERTY_ID - invalid alias name 6649 * Z_ALIAS_DISALLOW - pre-existing, incompatible rctl definition 6650 * Z_NO_ENTRY - no rctl is configured for this alias 6651 * Z_OK - we got a valid rctl for the specified alias 6652 */ 6653 int 6654 zonecfg_get_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t *rval) 6655 { 6656 boolean_t found = B_FALSE; 6657 boolean_t found_val = B_FALSE; 6658 xmlNodePtr cur, val; 6659 char savedname[MAXNAMELEN]; 6660 struct zone_rctlvaltab rctl; 6661 int i; 6662 int err; 6663 6664 for (i = 0; aliases[i].shortname != NULL; i++) 6665 if (strcmp(name, aliases[i].shortname) == 0) 6666 break; 6667 6668 if (aliases[i].shortname == NULL) 6669 return (Z_NO_PROPERTY_ID); 6670 6671 if ((err = operation_prep(handle)) != Z_OK) 6672 return (err); 6673 6674 cur = handle->zone_dh_cur; 6675 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6676 if (xmlStrcmp(cur->name, DTD_ELEM_RCTL) != 0) 6677 continue; 6678 if ((fetchprop(cur, DTD_ATTR_NAME, savedname, 6679 sizeof (savedname)) == Z_OK) && 6680 (strcmp(savedname, aliases[i].realname) == 0)) { 6681 6682 /* 6683 * If we already saw one of these, we can't have an 6684 * alias since we just found another. 6685 */ 6686 if (found) 6687 return (Z_ALIAS_DISALLOW); 6688 found = B_TRUE; 6689 6690 for (val = cur->xmlChildrenNode; val != NULL; 6691 val = val->next) { 6692 /* 6693 * If we already have one value, we can't have 6694 * an alias since we just found another. 6695 */ 6696 if (found_val) 6697 return (Z_ALIAS_DISALLOW); 6698 found_val = B_TRUE; 6699 6700 if ((fetchprop(val, DTD_ATTR_PRIV, 6701 rctl.zone_rctlval_priv, 6702 sizeof (rctl.zone_rctlval_priv)) != Z_OK)) 6703 break; 6704 if ((fetchprop(val, DTD_ATTR_LIMIT, 6705 rctl.zone_rctlval_limit, 6706 sizeof (rctl.zone_rctlval_limit)) != Z_OK)) 6707 break; 6708 if ((fetchprop(val, DTD_ATTR_ACTION, 6709 rctl.zone_rctlval_action, 6710 sizeof (rctl.zone_rctlval_action)) != Z_OK)) 6711 break; 6712 } 6713 6714 /* check priv and action match the expected vals */ 6715 if (strcmp(rctl.zone_rctlval_priv, 6716 aliases[i].priv) != 0 || 6717 strcmp(rctl.zone_rctlval_action, 6718 aliases[i].action) != 0) 6719 return (Z_ALIAS_DISALLOW); 6720 } 6721 } 6722 6723 if (found) { 6724 *rval = strtoull(rctl.zone_rctlval_limit, NULL, 10); 6725 return (Z_OK); 6726 } 6727 6728 return (Z_NO_ENTRY); 6729 } 6730 6731 int 6732 zonecfg_rm_aliased_rctl(zone_dochandle_t handle, char *name) 6733 { 6734 int i; 6735 uint64_t val; 6736 struct zone_rctltab rctltab; 6737 6738 /* 6739 * First check that we have a valid aliased rctl to remove. 6740 * This will catch an rctl entry with non-standard values or 6741 * multiple rctl values for this name. We need to ignore those 6742 * rctl entries. 6743 */ 6744 if (zonecfg_get_aliased_rctl(handle, name, &val) != Z_OK) 6745 return (Z_OK); 6746 6747 for (i = 0; aliases[i].shortname != NULL; i++) 6748 if (strcmp(name, aliases[i].shortname) == 0) 6749 break; 6750 6751 if (aliases[i].shortname == NULL) 6752 return (Z_NO_RESOURCE_ID); 6753 6754 (void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname, 6755 sizeof (rctltab.zone_rctl_name)); 6756 6757 return (zonecfg_delete_rctl(handle, &rctltab)); 6758 } 6759 6760 boolean_t 6761 zonecfg_aliased_rctl_ok(zone_dochandle_t handle, char *name) 6762 { 6763 uint64_t tmp_val; 6764 6765 switch (zonecfg_get_aliased_rctl(handle, name, &tmp_val)) { 6766 case Z_OK: 6767 /*FALLTHRU*/ 6768 case Z_NO_ENTRY: 6769 return (B_TRUE); 6770 default: 6771 return (B_FALSE); 6772 } 6773 } 6774 6775 int 6776 zonecfg_set_aliased_rctl(zone_dochandle_t handle, char *name, uint64_t val) 6777 { 6778 int i; 6779 int err; 6780 struct zone_rctltab rctltab; 6781 struct zone_rctlvaltab *rctlvaltab; 6782 char buf[128]; 6783 6784 if (!zonecfg_aliased_rctl_ok(handle, name)) 6785 return (Z_ALIAS_DISALLOW); 6786 6787 for (i = 0; aliases[i].shortname != NULL; i++) 6788 if (strcmp(name, aliases[i].shortname) == 0) 6789 break; 6790 6791 if (aliases[i].shortname == NULL) 6792 return (Z_NO_RESOURCE_ID); 6793 6794 /* remove any pre-existing definition for this rctl */ 6795 (void) zonecfg_rm_aliased_rctl(handle, name); 6796 6797 (void) strlcpy(rctltab.zone_rctl_name, aliases[i].realname, 6798 sizeof (rctltab.zone_rctl_name)); 6799 6800 rctltab.zone_rctl_valptr = NULL; 6801 6802 if ((rctlvaltab = calloc(1, sizeof (struct zone_rctlvaltab))) == NULL) 6803 return (Z_NOMEM); 6804 6805 (void) snprintf(buf, sizeof (buf), "%llu", (long long)val); 6806 6807 (void) strlcpy(rctlvaltab->zone_rctlval_priv, aliases[i].priv, 6808 sizeof (rctlvaltab->zone_rctlval_priv)); 6809 (void) strlcpy(rctlvaltab->zone_rctlval_limit, buf, 6810 sizeof (rctlvaltab->zone_rctlval_limit)); 6811 (void) strlcpy(rctlvaltab->zone_rctlval_action, aliases[i].action, 6812 sizeof (rctlvaltab->zone_rctlval_action)); 6813 6814 rctlvaltab->zone_rctlval_next = NULL; 6815 6816 if ((err = zonecfg_add_rctl_value(&rctltab, rctlvaltab)) != Z_OK) 6817 return (err); 6818 6819 return (zonecfg_add_rctl(handle, &rctltab)); 6820 } 6821 6822 static int 6823 delete_tmp_pool(zone_dochandle_t handle) 6824 { 6825 int err; 6826 xmlNodePtr cur = handle->zone_dh_cur; 6827 6828 if ((err = operation_prep(handle)) != Z_OK) 6829 return (err); 6830 6831 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6832 if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) { 6833 xmlUnlinkNode(cur); 6834 xmlFreeNode(cur); 6835 return (Z_OK); 6836 } 6837 } 6838 6839 return (Z_NO_RESOURCE_ID); 6840 } 6841 6842 static int 6843 modify_tmp_pool(zone_dochandle_t handle, char *pool_importance) 6844 { 6845 int err; 6846 xmlNodePtr cur = handle->zone_dh_cur; 6847 xmlNodePtr newnode; 6848 6849 err = delete_tmp_pool(handle); 6850 if (err != Z_OK && err != Z_NO_RESOURCE_ID) 6851 return (err); 6852 6853 if (*pool_importance != '\0') { 6854 if ((err = operation_prep(handle)) != Z_OK) 6855 return (err); 6856 6857 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_TMPPOOL, NULL); 6858 if ((err = newprop(newnode, DTD_ATTR_IMPORTANCE, 6859 pool_importance)) != Z_OK) 6860 return (err); 6861 } 6862 6863 return (Z_OK); 6864 } 6865 6866 static int 6867 add_pset_core(zone_dochandle_t handle, struct zone_psettab *tabptr) 6868 { 6869 xmlNodePtr newnode, cur = handle->zone_dh_cur; 6870 int err; 6871 6872 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_PSET, NULL); 6873 if ((err = newprop(newnode, DTD_ATTR_NCPU_MIN, 6874 tabptr->zone_ncpu_min)) != Z_OK) 6875 return (err); 6876 if ((err = newprop(newnode, DTD_ATTR_NCPU_MAX, 6877 tabptr->zone_ncpu_max)) != Z_OK) 6878 return (err); 6879 6880 if ((err = modify_tmp_pool(handle, tabptr->zone_importance)) != Z_OK) 6881 return (err); 6882 6883 return (Z_OK); 6884 } 6885 6886 int 6887 zonecfg_add_pset(zone_dochandle_t handle, struct zone_psettab *tabptr) 6888 { 6889 int err; 6890 6891 if (tabptr == NULL) 6892 return (Z_INVAL); 6893 6894 if ((err = operation_prep(handle)) != Z_OK) 6895 return (err); 6896 6897 if ((err = add_pset_core(handle, tabptr)) != Z_OK) 6898 return (err); 6899 6900 return (Z_OK); 6901 } 6902 6903 int 6904 zonecfg_delete_pset(zone_dochandle_t handle) 6905 { 6906 int err; 6907 int res = Z_NO_RESOURCE_ID; 6908 xmlNodePtr cur = handle->zone_dh_cur; 6909 6910 if ((err = operation_prep(handle)) != Z_OK) 6911 return (err); 6912 6913 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6914 if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) { 6915 xmlUnlinkNode(cur); 6916 xmlFreeNode(cur); 6917 res = Z_OK; 6918 break; 6919 } 6920 } 6921 6922 /* 6923 * Once we have msets, we should check that a mset 6924 * do not exist before we delete the tmp_pool data. 6925 */ 6926 err = delete_tmp_pool(handle); 6927 if (err != Z_OK && err != Z_NO_RESOURCE_ID) 6928 return (err); 6929 6930 return (res); 6931 } 6932 6933 int 6934 zonecfg_modify_pset(zone_dochandle_t handle, struct zone_psettab *tabptr) 6935 { 6936 int err; 6937 6938 if (tabptr == NULL) 6939 return (Z_INVAL); 6940 6941 if ((err = zonecfg_delete_pset(handle)) != Z_OK) 6942 return (err); 6943 6944 if ((err = add_pset_core(handle, tabptr)) != Z_OK) 6945 return (err); 6946 6947 return (Z_OK); 6948 } 6949 6950 int 6951 zonecfg_lookup_pset(zone_dochandle_t handle, struct zone_psettab *tabptr) 6952 { 6953 xmlNodePtr cur; 6954 int err; 6955 int res = Z_NO_ENTRY; 6956 6957 if (tabptr == NULL) 6958 return (Z_INVAL); 6959 6960 if ((err = operation_prep(handle)) != Z_OK) 6961 return (err); 6962 6963 /* this is an optional component */ 6964 tabptr->zone_importance[0] = '\0'; 6965 6966 cur = handle->zone_dh_cur; 6967 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 6968 if (xmlStrcmp(cur->name, DTD_ELEM_PSET) == 0) { 6969 if ((err = fetchprop(cur, DTD_ATTR_NCPU_MIN, 6970 tabptr->zone_ncpu_min, 6971 sizeof (tabptr->zone_ncpu_min))) != Z_OK) { 6972 handle->zone_dh_cur = handle->zone_dh_top; 6973 return (err); 6974 } 6975 6976 if ((err = fetchprop(cur, DTD_ATTR_NCPU_MAX, 6977 tabptr->zone_ncpu_max, 6978 sizeof (tabptr->zone_ncpu_max))) != Z_OK) { 6979 handle->zone_dh_cur = handle->zone_dh_top; 6980 return (err); 6981 } 6982 6983 res = Z_OK; 6984 6985 } else if (xmlStrcmp(cur->name, DTD_ELEM_TMPPOOL) == 0) { 6986 if ((err = fetchprop(cur, DTD_ATTR_IMPORTANCE, 6987 tabptr->zone_importance, 6988 sizeof (tabptr->zone_importance))) != Z_OK) { 6989 handle->zone_dh_cur = handle->zone_dh_top; 6990 return (err); 6991 } 6992 } 6993 } 6994 6995 return (res); 6996 } 6997 6998 int 6999 zonecfg_getpsetent(zone_dochandle_t handle, struct zone_psettab *tabptr) 7000 { 7001 int err; 7002 7003 if ((err = zonecfg_setent(handle)) != Z_OK) 7004 return (err); 7005 7006 err = zonecfg_lookup_pset(handle, tabptr); 7007 7008 (void) zonecfg_endent(handle); 7009 7010 return (err); 7011 } 7012 7013 static int 7014 add_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 7015 { 7016 xmlNodePtr newnode, cur = handle->zone_dh_cur; 7017 int err; 7018 7019 newnode = xmlNewTextChild(cur, NULL, DTD_ELEM_MCAP, NULL); 7020 if ((err = newprop(newnode, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap)) 7021 != Z_OK) 7022 return (err); 7023 7024 return (Z_OK); 7025 } 7026 7027 int 7028 zonecfg_delete_mcap(zone_dochandle_t handle) 7029 { 7030 int err; 7031 xmlNodePtr cur = handle->zone_dh_cur; 7032 7033 if ((err = operation_prep(handle)) != Z_OK) 7034 return (err); 7035 7036 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 7037 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0) 7038 continue; 7039 7040 xmlUnlinkNode(cur); 7041 xmlFreeNode(cur); 7042 return (Z_OK); 7043 } 7044 return (Z_NO_RESOURCE_ID); 7045 } 7046 7047 int 7048 zonecfg_modify_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 7049 { 7050 int err; 7051 7052 if (tabptr == NULL) 7053 return (Z_INVAL); 7054 7055 err = zonecfg_delete_mcap(handle); 7056 /* it is ok if there is no mcap entry */ 7057 if (err != Z_OK && err != Z_NO_RESOURCE_ID) 7058 return (err); 7059 7060 if ((err = add_mcap(handle, tabptr)) != Z_OK) 7061 return (err); 7062 7063 return (Z_OK); 7064 } 7065 7066 int 7067 zonecfg_lookup_mcap(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 7068 { 7069 xmlNodePtr cur; 7070 int err; 7071 7072 if (tabptr == NULL) 7073 return (Z_INVAL); 7074 7075 if ((err = operation_prep(handle)) != Z_OK) 7076 return (err); 7077 7078 cur = handle->zone_dh_cur; 7079 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 7080 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) != 0) 7081 continue; 7082 if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, 7083 tabptr->zone_physmem_cap, 7084 sizeof (tabptr->zone_physmem_cap))) != Z_OK) { 7085 handle->zone_dh_cur = handle->zone_dh_top; 7086 return (err); 7087 } 7088 7089 return (Z_OK); 7090 } 7091 7092 return (Z_NO_ENTRY); 7093 } 7094 7095 static int 7096 getmcapent_core(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 7097 { 7098 xmlNodePtr cur; 7099 int err; 7100 7101 if (handle == NULL) 7102 return (Z_INVAL); 7103 7104 if ((cur = handle->zone_dh_cur) == NULL) 7105 return (Z_NO_ENTRY); 7106 7107 for (; cur != NULL; cur = cur->next) 7108 if (xmlStrcmp(cur->name, DTD_ELEM_MCAP) == 0) 7109 break; 7110 if (cur == NULL) { 7111 handle->zone_dh_cur = handle->zone_dh_top; 7112 return (Z_NO_ENTRY); 7113 } 7114 7115 if ((err = fetchprop(cur, DTD_ATTR_PHYSCAP, tabptr->zone_physmem_cap, 7116 sizeof (tabptr->zone_physmem_cap))) != Z_OK) { 7117 handle->zone_dh_cur = handle->zone_dh_top; 7118 return (err); 7119 } 7120 7121 handle->zone_dh_cur = cur->next; 7122 return (Z_OK); 7123 } 7124 7125 int 7126 zonecfg_getmcapent(zone_dochandle_t handle, struct zone_mcaptab *tabptr) 7127 { 7128 int err; 7129 7130 if ((err = zonecfg_setent(handle)) != Z_OK) 7131 return (err); 7132 7133 err = getmcapent_core(handle, tabptr); 7134 7135 (void) zonecfg_endent(handle); 7136 7137 return (err); 7138 } 7139 7140 /* 7141 * Get the full tree of pkg/patch metadata in a set of nested AVL trees. 7142 * pkgs_avl is an AVL tree of pkgs. Each pkg element contains a 7143 * zpe_patches_avl member which holds an AVL tree of patches for that pkg. 7144 * The patch elements have the same zpe_patches_avl member, each of which can 7145 * hold an AVL tree of patches that are obsoleted by the patch. 7146 * 7147 * The zone xml data contains DTD_ELEM_PACKAGE elements, followed by 7148 * DTD_ELEM_PATCH elements. The DTD_ELEM_PATCH patch element applies to the 7149 * DTD_ELEM_PACKAGE that precedes it. The DTD_ELEM_PATCH element may have 7150 * child DTD_ELEM_OBSOLETES nodes associated with it. The DTD_ELEM_PACKAGE 7151 * really should have had the DTD_ELEM_PATCH elements as children but it 7152 * was not defined that way initially so we are stuck with the DTD definition 7153 * now. However, we can safely assume the ordering for compatibility. 7154 */ 7155 int 7156 zonecfg_getpkgdata(zone_dochandle_t handle, uu_avl_pool_t *pkg_pool, 7157 uu_avl_t *pkgs_avl) 7158 { 7159 xmlNodePtr cur; 7160 int res; 7161 zone_pkg_entry_t *pkg; 7162 char name[MAXNAMELEN]; 7163 char version[ZONE_PKG_VERSMAX]; 7164 7165 if (handle == NULL) 7166 return (Z_INVAL); 7167 7168 if ((res = zonecfg_setent(handle)) != Z_OK) 7169 return (res); 7170 7171 if ((cur = handle->zone_dh_cur) == NULL) { 7172 res = Z_NO_ENTRY; 7173 goto done; 7174 } 7175 7176 for (; cur != NULL; cur = cur->next) { 7177 if (xmlStrcmp(cur->name, DTD_ELEM_PACKAGE) == 0) { 7178 uu_avl_index_t where; 7179 7180 if ((res = fetchprop(cur, DTD_ATTR_NAME, name, 7181 sizeof (name))) != Z_OK) 7182 goto done; 7183 7184 if ((res = fetchprop(cur, DTD_ATTR_VERSION, version, 7185 sizeof (version))) != Z_OK) 7186 goto done; 7187 7188 if ((pkg = (zone_pkg_entry_t *) 7189 malloc(sizeof (zone_pkg_entry_t))) == NULL) { 7190 res = Z_NOMEM; 7191 goto done; 7192 } 7193 7194 if ((pkg->zpe_name = strdup(name)) == NULL) { 7195 free(pkg); 7196 res = Z_NOMEM; 7197 goto done; 7198 } 7199 7200 if ((pkg->zpe_vers = strdup(version)) == NULL) { 7201 free(pkg->zpe_name); 7202 free(pkg); 7203 res = Z_NOMEM; 7204 goto done; 7205 } 7206 7207 pkg->zpe_patches_avl = NULL; 7208 7209 uu_avl_node_init(pkg, &pkg->zpe_entry, pkg_pool); 7210 if (uu_avl_find(pkgs_avl, pkg, NULL, &where) != NULL) { 7211 free(pkg->zpe_name); 7212 free(pkg->zpe_vers); 7213 free(pkg); 7214 } else { 7215 uu_avl_insert(pkgs_avl, pkg, where); 7216 } 7217 7218 } else if (xmlStrcmp(cur->name, DTD_ELEM_PATCH) == 0) { 7219 zone_pkg_entry_t *patch; 7220 uu_avl_index_t where; 7221 char *p; 7222 char *dashp = NULL; 7223 xmlNodePtr child; 7224 7225 if ((res = fetchprop(cur, DTD_ATTR_ID, name, 7226 sizeof (name))) != Z_OK) 7227 goto done; 7228 7229 if ((patch = (zone_pkg_entry_t *) 7230 malloc(sizeof (zone_pkg_entry_t))) == NULL) { 7231 res = Z_NOMEM; 7232 goto done; 7233 } 7234 7235 if ((p = strchr(name, '-')) != NULL) { 7236 dashp = p; 7237 *p++ = '\0'; 7238 } else { 7239 p = ""; 7240 } 7241 7242 if ((patch->zpe_name = strdup(name)) == NULL) { 7243 free(patch); 7244 res = Z_NOMEM; 7245 goto done; 7246 } 7247 7248 if ((patch->zpe_vers = strdup(p)) == NULL) { 7249 free(patch->zpe_name); 7250 free(patch); 7251 res = Z_NOMEM; 7252 goto done; 7253 } 7254 7255 if (dashp != NULL) 7256 *dashp = '-'; 7257 7258 patch->zpe_patches_avl = NULL; 7259 7260 if (pkg->zpe_patches_avl == NULL) { 7261 pkg->zpe_patches_avl = uu_avl_create(pkg_pool, 7262 NULL, UU_DEFAULT); 7263 if (pkg->zpe_patches_avl == NULL) { 7264 free(patch->zpe_name); 7265 free(patch->zpe_vers); 7266 free(patch); 7267 res = Z_NOMEM; 7268 goto done; 7269 } 7270 } 7271 7272 uu_avl_node_init(patch, &patch->zpe_entry, pkg_pool); 7273 if (uu_avl_find(pkg->zpe_patches_avl, patch, NULL, 7274 &where) != NULL) { 7275 free(patch->zpe_name); 7276 free(patch->zpe_vers); 7277 free(patch); 7278 } else { 7279 uu_avl_insert(pkg->zpe_patches_avl, patch, 7280 where); 7281 } 7282 7283 /* Add any patches this patch obsoletes. */ 7284 for (child = cur->xmlChildrenNode; child != NULL; 7285 child = child->next) { 7286 zone_pkg_entry_t *obs; 7287 7288 if (xmlStrcmp(child->name, DTD_ELEM_OBSOLETES) 7289 != 0) 7290 continue; 7291 7292 if ((res = fetchprop(child, DTD_ATTR_ID, 7293 name, sizeof (name))) != Z_OK) 7294 goto done; 7295 7296 if ((obs = (zone_pkg_entry_t *)malloc( 7297 sizeof (zone_pkg_entry_t))) == NULL) { 7298 res = Z_NOMEM; 7299 goto done; 7300 } 7301 7302 if ((obs->zpe_name = strdup(name)) == NULL) { 7303 free(obs); 7304 res = Z_NOMEM; 7305 goto done; 7306 } 7307 /* 7308 * The version doesn't matter for obsoleted 7309 * patches. 7310 */ 7311 obs->zpe_vers = NULL; 7312 obs->zpe_patches_avl = NULL; 7313 7314 /* 7315 * If this is the first obsolete patch, add an 7316 * AVL tree to the parent patch element. 7317 */ 7318 if (patch->zpe_patches_avl == NULL) { 7319 patch->zpe_patches_avl = 7320 uu_avl_create(pkg_pool, NULL, 7321 UU_DEFAULT); 7322 if (patch->zpe_patches_avl == NULL) { 7323 free(obs->zpe_name); 7324 free(obs); 7325 res = Z_NOMEM; 7326 goto done; 7327 } 7328 } 7329 7330 /* Insert obsolete patch into the AVL tree. */ 7331 uu_avl_node_init(obs, &obs->zpe_entry, 7332 pkg_pool); 7333 if (uu_avl_find(patch->zpe_patches_avl, obs, 7334 NULL, &where) != NULL) { 7335 free(obs->zpe_name); 7336 free(obs); 7337 } else { 7338 uu_avl_insert(patch->zpe_patches_avl, 7339 obs, where); 7340 } 7341 } 7342 } 7343 } 7344 7345 done: 7346 (void) zonecfg_endent(handle); 7347 return (res); 7348 } 7349 7350 int 7351 zonecfg_setdevperment(zone_dochandle_t handle) 7352 { 7353 return (zonecfg_setent(handle)); 7354 } 7355 7356 int 7357 zonecfg_getdevperment(zone_dochandle_t handle, struct zone_devpermtab *tabptr) 7358 { 7359 xmlNodePtr cur; 7360 int err; 7361 char buf[128]; 7362 7363 tabptr->zone_devperm_acl = NULL; 7364 7365 if (handle == NULL) 7366 return (Z_INVAL); 7367 7368 if ((cur = handle->zone_dh_cur) == NULL) 7369 return (Z_NO_ENTRY); 7370 7371 for (; cur != NULL; cur = cur->next) 7372 if (!xmlStrcmp(cur->name, DTD_ELEM_DEV_PERM)) 7373 break; 7374 if (cur == NULL) { 7375 handle->zone_dh_cur = handle->zone_dh_top; 7376 return (Z_NO_ENTRY); 7377 } 7378 7379 if ((err = fetchprop(cur, DTD_ATTR_NAME, tabptr->zone_devperm_name, 7380 sizeof (tabptr->zone_devperm_name))) != Z_OK) { 7381 handle->zone_dh_cur = handle->zone_dh_top; 7382 return (err); 7383 } 7384 7385 if ((err = fetchprop(cur, DTD_ATTR_UID, buf, sizeof (buf))) != Z_OK) { 7386 handle->zone_dh_cur = handle->zone_dh_top; 7387 return (err); 7388 } 7389 tabptr->zone_devperm_uid = (uid_t)atol(buf); 7390 7391 if ((err = fetchprop(cur, DTD_ATTR_GID, buf, sizeof (buf))) != Z_OK) { 7392 handle->zone_dh_cur = handle->zone_dh_top; 7393 return (err); 7394 } 7395 tabptr->zone_devperm_gid = (gid_t)atol(buf); 7396 7397 if ((err = fetchprop(cur, DTD_ATTR_MODE, buf, sizeof (buf))) != Z_OK) { 7398 handle->zone_dh_cur = handle->zone_dh_top; 7399 return (err); 7400 } 7401 tabptr->zone_devperm_mode = (mode_t)strtol(buf, (char **)NULL, 8); 7402 7403 if ((err = fetch_alloc_prop(cur, DTD_ATTR_ACL, 7404 &(tabptr->zone_devperm_acl))) != Z_OK) { 7405 handle->zone_dh_cur = handle->zone_dh_top; 7406 return (err); 7407 } 7408 7409 handle->zone_dh_cur = cur->next; 7410 return (Z_OK); 7411 } 7412 7413 int 7414 zonecfg_enddevperment(zone_dochandle_t handle) 7415 { 7416 return (zonecfg_endent(handle)); 7417 } 7418 7419 /* PRINTFLIKE1 */ 7420 static void 7421 zerror(const char *zone_name, const char *fmt, ...) 7422 { 7423 va_list alist; 7424 7425 va_start(alist, fmt); 7426 (void) fprintf(stderr, "zone '%s': ", zone_name); 7427 (void) vfprintf(stderr, fmt, alist); 7428 (void) fprintf(stderr, "\n"); 7429 va_end(alist); 7430 } 7431 7432 static void 7433 zperror(const char *str) 7434 { 7435 (void) fprintf(stderr, "%s: %s\n", str, strerror(errno)); 7436 } 7437 7438 /* 7439 * The following three routines implement a simple locking mechanism to 7440 * ensure that only one instance of zoneadm at a time is able to manipulate 7441 * a given zone. The lock is built on top of an fcntl(2) lock of 7442 * [<altroot>]/var/run/zones/<zonename>.zoneadm.lock. If a zoneadm instance 7443 * can grab that lock, it is allowed to manipulate the zone. 7444 * 7445 * Since zoneadm may call external applications which in turn invoke 7446 * zoneadm again, we introduce the notion of "lock inheritance". Any 7447 * instance of zoneadm that has another instance in its ancestry is assumed 7448 * to be acting on behalf of the original zoneadm, and is thus allowed to 7449 * manipulate its zone. 7450 * 7451 * This inheritance is implemented via the _ZONEADM_LOCK_HELD environment 7452 * variable. When zoneadm is granted a lock on its zone, this environment 7453 * variable is set to 1. When it releases the lock, the variable is set to 7454 * 0. Since a child process inherits its parent's environment, checking 7455 * the state of this variable indicates whether or not any ancestor owns 7456 * the lock. 7457 */ 7458 void 7459 zonecfg_init_lock_file(const char *zone_name, char **lock_env) 7460 { 7461 *lock_env = getenv(LOCK_ENV_VAR); 7462 if (*lock_env == NULL) { 7463 if (putenv(zoneadm_lock_not_held) != 0) { 7464 zerror(zone_name, gettext("could not set env: %s"), 7465 strerror(errno)); 7466 exit(1); 7467 } 7468 } else { 7469 if (atoi(*lock_env) == 1) 7470 zone_lock_cnt = 1; 7471 } 7472 } 7473 7474 void 7475 zonecfg_release_lock_file(const char *zone_name, int lockfd) 7476 { 7477 /* 7478 * If we are cleaning up from a failed attempt to lock the zone for 7479 * the first time, we might have a zone_lock_cnt of 0. In that 7480 * error case, we don't want to do anything but close the lock 7481 * file. 7482 */ 7483 assert(zone_lock_cnt >= 0); 7484 if (zone_lock_cnt > 0) { 7485 assert(getenv(LOCK_ENV_VAR) != NULL); 7486 assert(atoi(getenv(LOCK_ENV_VAR)) == 1); 7487 if (--zone_lock_cnt > 0) { 7488 assert(lockfd == -1); 7489 return; 7490 } 7491 if (putenv(zoneadm_lock_not_held) != 0) { 7492 zerror(zone_name, gettext("could not set env: %s"), 7493 strerror(errno)); 7494 exit(1); 7495 } 7496 } 7497 assert(lockfd >= 0); 7498 (void) close(lockfd); 7499 } 7500 7501 int 7502 zonecfg_grab_lock_file(const char *zone_name, int *lockfd) 7503 { 7504 char pathbuf[PATH_MAX]; 7505 struct flock flock; 7506 7507 /* 7508 * If we already have the lock, we can skip this expensive song 7509 * and dance. 7510 */ 7511 assert(zone_lock_cnt >= 0); 7512 assert(getenv(LOCK_ENV_VAR) != NULL); 7513 if (zone_lock_cnt > 0) { 7514 assert(atoi(getenv(LOCK_ENV_VAR)) == 1); 7515 zone_lock_cnt++; 7516 *lockfd = -1; 7517 return (Z_OK); 7518 } 7519 assert(getenv(LOCK_ENV_VAR) != NULL); 7520 assert(atoi(getenv(LOCK_ENV_VAR)) == 0); 7521 7522 if (snprintf(pathbuf, sizeof (pathbuf), "%s%s", zonecfg_get_root(), 7523 ZONES_TMPDIR) >= sizeof (pathbuf)) { 7524 zerror(zone_name, gettext("alternate root path is too long")); 7525 return (-1); 7526 } 7527 if (mkdir(pathbuf, S_IRWXU) < 0 && errno != EEXIST) { 7528 zerror(zone_name, gettext("could not mkdir %s: %s"), pathbuf, 7529 strerror(errno)); 7530 return (-1); 7531 } 7532 (void) chmod(pathbuf, S_IRWXU); 7533 7534 /* 7535 * One of these lock files is created for each zone (when needed). 7536 * The lock files are not cleaned up (except on system reboot), 7537 * but since there is only one per zone, there is no resource 7538 * starvation issue. 7539 */ 7540 if (snprintf(pathbuf, sizeof (pathbuf), "%s%s/%s.zoneadm.lock", 7541 zonecfg_get_root(), ZONES_TMPDIR, zone_name) >= sizeof (pathbuf)) { 7542 zerror(zone_name, gettext("alternate root path is too long")); 7543 return (-1); 7544 } 7545 if ((*lockfd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) { 7546 zerror(zone_name, gettext("could not open %s: %s"), pathbuf, 7547 strerror(errno)); 7548 return (-1); 7549 } 7550 /* 7551 * Lock the file to synchronize with other zoneadmds 7552 */ 7553 flock.l_type = F_WRLCK; 7554 flock.l_whence = SEEK_SET; 7555 flock.l_start = (off_t)0; 7556 flock.l_len = (off_t)0; 7557 if ((fcntl(*lockfd, F_SETLKW, &flock) < 0) || 7558 (putenv(zoneadm_lock_held) != 0)) { 7559 zerror(zone_name, gettext("unable to lock %s: %s"), pathbuf, 7560 strerror(errno)); 7561 zonecfg_release_lock_file(zone_name, *lockfd); 7562 return (-1); 7563 } 7564 zone_lock_cnt = 1; 7565 return (Z_OK); 7566 } 7567 7568 boolean_t 7569 zonecfg_lock_file_held(int *lockfd) 7570 { 7571 if (*lockfd >= 0 || zone_lock_cnt > 0) 7572 return (B_TRUE); 7573 return (B_FALSE); 7574 } 7575 7576 static boolean_t 7577 get_doorname(const char *zone_name, char *buffer) 7578 { 7579 return (snprintf(buffer, PATH_MAX, "%s" ZONE_DOOR_PATH, 7580 zonecfg_get_root(), zone_name) < PATH_MAX); 7581 } 7582 7583 /* 7584 * system daemons are not audited. For the global zone, this occurs 7585 * "naturally" since init is started with the default audit 7586 * characteristics. Since zoneadmd is a system daemon and it starts 7587 * init for a zone, it is necessary to clear out the audit 7588 * characteristics inherited from whomever started zoneadmd. This is 7589 * indicated by the audit id, which is set from the ruid parameter of 7590 * adt_set_user(), below. 7591 */ 7592 7593 static void 7594 prepare_audit_context(const char *zone_name) 7595 { 7596 adt_session_data_t *ah; 7597 char *failure = gettext("audit failure: %s"); 7598 7599 if (adt_start_session(&ah, NULL, 0)) { 7600 zerror(zone_name, failure, strerror(errno)); 7601 return; 7602 } 7603 if (adt_set_user(ah, ADT_NO_AUDIT, ADT_NO_AUDIT, 7604 ADT_NO_AUDIT, ADT_NO_AUDIT, NULL, ADT_NEW)) { 7605 zerror(zone_name, failure, strerror(errno)); 7606 (void) adt_end_session(ah); 7607 return; 7608 } 7609 if (adt_set_proc(ah)) 7610 zerror(zone_name, failure, strerror(errno)); 7611 7612 (void) adt_end_session(ah); 7613 } 7614 7615 static int 7616 start_zoneadmd(const char *zone_name, boolean_t lock) 7617 { 7618 char doorpath[PATH_MAX]; 7619 pid_t child_pid; 7620 int error = -1; 7621 int doorfd, lockfd; 7622 struct door_info info; 7623 7624 if (!get_doorname(zone_name, doorpath)) 7625 return (-1); 7626 7627 if (lock) 7628 if (zonecfg_grab_lock_file(zone_name, &lockfd) != Z_OK) 7629 return (-1); 7630 7631 /* 7632 * Now that we have the lock, re-confirm that the daemon is 7633 * *not* up and working fine. If it is still down, we have a green 7634 * light to start it. 7635 */ 7636 if ((doorfd = open(doorpath, O_RDONLY)) < 0) { 7637 if (errno != ENOENT) { 7638 zperror(doorpath); 7639 goto out; 7640 } 7641 } else { 7642 if (door_info(doorfd, &info) == 0 && 7643 ((info.di_attributes & DOOR_REVOKED) == 0)) { 7644 error = Z_OK; 7645 (void) close(doorfd); 7646 goto out; 7647 } 7648 (void) close(doorfd); 7649 } 7650 7651 if ((child_pid = fork()) == -1) { 7652 zperror(gettext("could not fork")); 7653 goto out; 7654 } 7655 7656 if (child_pid == 0) { 7657 const char *argv[6], **ap; 7658 7659 /* child process */ 7660 prepare_audit_context(zone_name); 7661 7662 ap = argv; 7663 *ap++ = "zoneadmd"; 7664 *ap++ = "-z"; 7665 *ap++ = zone_name; 7666 if (zonecfg_in_alt_root()) { 7667 *ap++ = "-R"; 7668 *ap++ = zonecfg_get_root(); 7669 } 7670 *ap = NULL; 7671 7672 (void) execv("/usr/lib/zones/zoneadmd", (char * const *)argv); 7673 /* 7674 * TRANSLATION_NOTE 7675 * zoneadmd is a literal that should not be translated. 7676 */ 7677 zperror(gettext("could not exec zoneadmd")); 7678 _exit(1); 7679 } else { 7680 /* parent process */ 7681 pid_t retval; 7682 int pstatus = 0; 7683 7684 do { 7685 retval = waitpid(child_pid, &pstatus, 0); 7686 } while (retval != child_pid); 7687 if (WIFSIGNALED(pstatus) || (WIFEXITED(pstatus) && 7688 WEXITSTATUS(pstatus) != 0)) { 7689 zerror(zone_name, gettext("could not start %s"), 7690 "zoneadmd"); 7691 goto out; 7692 } 7693 } 7694 error = Z_OK; 7695 out: 7696 if (lock) 7697 zonecfg_release_lock_file(zone_name, lockfd); 7698 return (error); 7699 } 7700 7701 int 7702 zonecfg_ping_zoneadmd(const char *zone_name) 7703 { 7704 char doorpath[PATH_MAX]; 7705 int doorfd; 7706 struct door_info info; 7707 7708 if (!get_doorname(zone_name, doorpath)) 7709 return (-1); 7710 7711 if ((doorfd = open(doorpath, O_RDONLY)) < 0) { 7712 return (-1); 7713 } 7714 if (door_info(doorfd, &info) == 0 && 7715 ((info.di_attributes & DOOR_REVOKED) == 0)) { 7716 (void) close(doorfd); 7717 return (Z_OK); 7718 } 7719 (void) close(doorfd); 7720 return (-1); 7721 } 7722 7723 int 7724 zonecfg_call_zoneadmd(const char *zone_name, zone_cmd_arg_t *arg, char *locale, 7725 boolean_t lock) 7726 { 7727 char doorpath[PATH_MAX]; 7728 int doorfd, result; 7729 door_arg_t darg; 7730 7731 zoneid_t zoneid; 7732 uint64_t uniqid = 0; 7733 7734 zone_cmd_rval_t *rvalp; 7735 size_t rlen; 7736 char *cp, *errbuf; 7737 7738 rlen = getpagesize(); 7739 if ((rvalp = malloc(rlen)) == NULL) { 7740 zerror(zone_name, gettext("failed to allocate %lu bytes: %s"), 7741 rlen, strerror(errno)); 7742 return (-1); 7743 } 7744 7745 if ((zoneid = getzoneidbyname(zone_name)) != ZONE_ID_UNDEFINED) { 7746 (void) zone_getattr(zoneid, ZONE_ATTR_UNIQID, &uniqid, 7747 sizeof (uniqid)); 7748 } 7749 arg->uniqid = uniqid; 7750 (void) strlcpy(arg->locale, locale, sizeof (arg->locale)); 7751 if (!get_doorname(zone_name, doorpath)) { 7752 zerror(zone_name, gettext("alternate root path is too long")); 7753 free(rvalp); 7754 return (-1); 7755 } 7756 7757 /* 7758 * Loop trying to start zoneadmd; if something goes seriously 7759 * wrong we break out and fail. 7760 */ 7761 for (;;) { 7762 if (start_zoneadmd(zone_name, lock) != Z_OK) 7763 break; 7764 7765 if ((doorfd = open(doorpath, O_RDONLY)) < 0) { 7766 zperror(gettext("failed to open zone door")); 7767 break; 7768 } 7769 7770 darg.data_ptr = (char *)arg; 7771 darg.data_size = sizeof (*arg); 7772 darg.desc_ptr = NULL; 7773 darg.desc_num = 0; 7774 darg.rbuf = (char *)rvalp; 7775 darg.rsize = rlen; 7776 if (door_call(doorfd, &darg) != 0) { 7777 (void) close(doorfd); 7778 /* 7779 * We'll get EBADF if the door has been revoked. 7780 */ 7781 if (errno != EBADF) { 7782 zperror(gettext("door_call failed")); 7783 break; 7784 } 7785 continue; /* take another lap */ 7786 } 7787 (void) close(doorfd); 7788 7789 if (darg.data_size == 0) { 7790 /* Door server is going away; kick it again. */ 7791 continue; 7792 } 7793 7794 errbuf = rvalp->errbuf; 7795 while (*errbuf != '\0') { 7796 /* 7797 * Remove any newlines since zerror() 7798 * will append one automatically. 7799 */ 7800 cp = strchr(errbuf, '\n'); 7801 if (cp != NULL) 7802 *cp = '\0'; 7803 zerror(zone_name, "%s", errbuf); 7804 if (cp == NULL) 7805 break; 7806 errbuf = cp + 1; 7807 } 7808 result = rvalp->rval == 0 ? 0 : -1; 7809 free(rvalp); 7810 return (result); 7811 } 7812 7813 free(rvalp); 7814 return (-1); 7815 } 7816 7817 boolean_t 7818 zonecfg_valid_auths(const char *auths, const char *zonename) 7819 { 7820 char *right; 7821 char *tmpauths; 7822 char *lasts; 7823 char authname[MAXAUTHS]; 7824 boolean_t status = B_TRUE; 7825 7826 tmpauths = strdup(auths); 7827 if (tmpauths == NULL) { 7828 zerror(zonename, gettext("Out of memory")); 7829 return (B_FALSE); 7830 } 7831 right = strtok_r(tmpauths, ",", &lasts); 7832 while (right != NULL) { 7833 (void) snprintf(authname, MAXAUTHS, "%s%s", 7834 ZONE_AUTH_PREFIX, right); 7835 if (getauthnam(authname) == NULL) { 7836 status = B_FALSE; 7837 zerror(zonename, 7838 gettext("'%s' is not a valid authorization"), 7839 right); 7840 } 7841 right = strtok_r(NULL, ",", &lasts); 7842 } 7843 free(tmpauths); 7844 return (status); 7845 } 7846 7847 int 7848 zonecfg_delete_admins(zone_dochandle_t handle, char *zonename) 7849 { 7850 int err; 7851 struct zone_admintab admintab; 7852 boolean_t changed = B_FALSE; 7853 7854 if ((err = zonecfg_setadminent(handle)) != Z_OK) { 7855 return (err); 7856 } 7857 while (zonecfg_getadminent(handle, &admintab) == Z_OK) { 7858 err = zonecfg_delete_admin(handle, &admintab, 7859 zonename); 7860 if (err != Z_OK) { 7861 (void) zonecfg_endadminent(handle); 7862 return (err); 7863 } else { 7864 changed = B_TRUE; 7865 } 7866 if ((err = zonecfg_setadminent(handle)) != Z_OK) { 7867 return (err); 7868 } 7869 } 7870 (void) zonecfg_endadminent(handle); 7871 return (changed? Z_OK:Z_NO_ENTRY); 7872 } 7873 7874 /* 7875 * Checks if a long authorization applies to this zone. 7876 * If so, it returns true, after destructively stripping 7877 * the authorization of its prefix and zone suffix. 7878 */ 7879 static boolean_t 7880 is_zone_auth(char **auth, char *zonename, char *oldzonename) 7881 { 7882 char *suffix; 7883 size_t offset; 7884 7885 offset = strlen(ZONE_AUTH_PREFIX); 7886 if ((strncmp(*auth, ZONE_AUTH_PREFIX, offset) == 0) && 7887 ((suffix = strchr(*auth, '/')) != NULL)) { 7888 if (strcmp(suffix + 1, zonename) == 0) { 7889 *auth += offset; 7890 suffix[0] = '\0'; 7891 return (B_TRUE); 7892 } else if ((oldzonename != NULL) && 7893 (strcmp(suffix + 1, oldzonename) == 0)) { 7894 *auth += offset; 7895 suffix[0] = '\0'; 7896 return (B_TRUE); 7897 } 7898 } 7899 return (B_FALSE); 7900 } 7901 7902 /* 7903 * This function determines whether the zone-specific authorization 7904 * assignments in /etc/user_attr have been changed more recently 7905 * than the equivalent data stored in the zone's configuration file. 7906 * This should only happen if the zone-specific authorizations in 7907 * the user_attr file were modified using a tool other than zonecfg. 7908 * If the configuration file is out-of-date with respect to these 7909 * authorization assignments, it is updated to match those specified 7910 * in /etc/user_attr. 7911 */ 7912 7913 int 7914 zonecfg_update_userauths(zone_dochandle_t handle, char *zonename) 7915 { 7916 userattr_t *ua_ptr; 7917 char *authlist; 7918 char *lasts; 7919 FILE *uaf; 7920 struct zone_admintab admintab; 7921 struct stat config_st, ua_st; 7922 char config_file[MAXPATHLEN]; 7923 boolean_t changed = B_FALSE; 7924 int err; 7925 7926 if ((uaf = fopen(USERATTR_FILENAME, "r")) == NULL) { 7927 zerror(zonename, gettext("could not open file %s: %s"), 7928 USERATTR_FILENAME, strerror(errno)); 7929 if (errno == EACCES) 7930 return (Z_ACCES); 7931 if (errno == ENOENT) 7932 return (Z_NO_ZONE); 7933 return (Z_MISC_FS); 7934 } 7935 if ((err = fstat(fileno(uaf), &ua_st)) != 0) { 7936 zerror(zonename, gettext("could not stat file %s: %s"), 7937 USERATTR_FILENAME, strerror(errno)); 7938 (void) fclose(uaf); 7939 return (Z_MISC_FS); 7940 } 7941 if (!config_file_path(zonename, config_file)) { 7942 (void) fclose(uaf); 7943 return (Z_MISC_FS); 7944 } 7945 7946 if ((err = stat(config_file, &config_st)) != 0) { 7947 zerror(zonename, gettext("could not stat file %s: %s"), 7948 config_file, strerror(errno)); 7949 (void) fclose(uaf); 7950 return (Z_MISC_FS); 7951 } 7952 if (config_st.st_mtime >= ua_st.st_mtime) { 7953 (void) fclose(uaf); 7954 return (Z_NO_ENTRY); 7955 } 7956 if ((err = zonecfg_delete_admins(handle, zonename)) == Z_OK) { 7957 changed = B_TRUE; 7958 } else if (err != Z_NO_ENTRY) { 7959 (void) fclose(uaf); 7960 return (err); 7961 } 7962 while ((ua_ptr = fgetuserattr(uaf)) != NULL) { 7963 if (ua_ptr->name[0] == '#') { 7964 continue; 7965 } 7966 authlist = kva_match(ua_ptr->attr, USERATTR_AUTHS_KW); 7967 if (authlist != NULL) { 7968 char *cur_auth; 7969 boolean_t first; 7970 7971 first = B_TRUE; 7972 bzero(&admintab.zone_admin_auths, MAXAUTHS); 7973 cur_auth = strtok_r(authlist, ",", &lasts); 7974 while (cur_auth != NULL) { 7975 if (is_zone_auth(&cur_auth, zonename, 7976 NULL)) { 7977 /* 7978 * Add auths for this zone 7979 */ 7980 if (first) { 7981 first = B_FALSE; 7982 } else { 7983 (void) strlcat( 7984 admintab.zone_admin_auths, 7985 ",", MAXAUTHS); 7986 } 7987 (void) strlcat( 7988 admintab.zone_admin_auths, 7989 cur_auth, MAXAUTHS); 7990 } 7991 cur_auth = strtok_r(NULL, ",", &lasts); 7992 } 7993 if (!first) { 7994 /* 7995 * Add this right to config file 7996 */ 7997 (void) strlcpy(admintab.zone_admin_user, 7998 ua_ptr->name, 7999 sizeof (admintab.zone_admin_user)); 8000 err = zonecfg_add_admin(handle, 8001 &admintab, zonename); 8002 if (err != Z_OK) { 8003 (void) fclose(uaf); 8004 return (err); 8005 } else { 8006 changed = B_TRUE; 8007 } 8008 } 8009 } 8010 } /* end-of-while-loop */ 8011 (void) fclose(uaf); 8012 return (changed? Z_OK: Z_NO_ENTRY); 8013 } 8014 8015 static void 8016 update_profiles(char *rbac_profs, boolean_t add) 8017 { 8018 char new_profs[MAXPROFS]; 8019 char *cur_prof; 8020 boolean_t first = B_TRUE; 8021 boolean_t found = B_FALSE; 8022 char *lasts; 8023 8024 cur_prof = strtok_r(rbac_profs, ",", &lasts); 8025 while (cur_prof != NULL) { 8026 if (strcmp(cur_prof, ZONE_MGMT_PROF) == 0) { 8027 found = B_TRUE; 8028 if (!add) { 8029 cur_prof = strtok_r(NULL, ",", &lasts); 8030 continue; 8031 } 8032 } 8033 if (first) { 8034 first = B_FALSE; 8035 } else { 8036 (void) strlcat(new_profs, ",", 8037 MAXPROFS); 8038 } 8039 (void) strlcat(new_profs, cur_prof, 8040 MAXPROFS); 8041 cur_prof = strtok_r(NULL, ",", &lasts); 8042 } 8043 /* 8044 * Now prepend the Zone Management profile at the beginning 8045 * of the list if it is needed, and append the rest. 8046 * Return the updated list in the original buffer. 8047 */ 8048 if (add && !found) { 8049 first = B_FALSE; 8050 (void) strlcpy(rbac_profs, ZONE_MGMT_PROF, MAXPROFS); 8051 } else { 8052 first = B_TRUE; 8053 rbac_profs[0] = '\0'; 8054 } 8055 if (strlen(new_profs) > 0) { 8056 if (!first) 8057 (void) strlcat(rbac_profs, ",", MAXPROFS); 8058 (void) strlcat(rbac_profs, new_profs, MAXPROFS); 8059 } 8060 } 8061 8062 #define MAX_CMD_LEN 1024 8063 8064 static int 8065 do_subproc(char *zonename, char *cmdbuf) 8066 { 8067 char inbuf[MAX_CMD_LEN]; 8068 FILE *file; 8069 int status; 8070 8071 file = popen(cmdbuf, "r"); 8072 if (file == NULL) { 8073 zerror(zonename, gettext("Could not launch: %s"), cmdbuf); 8074 return (-1); 8075 } 8076 8077 while (fgets(inbuf, sizeof (inbuf), file) != NULL) 8078 (void) fprintf(stderr, "%s", inbuf); 8079 status = pclose(file); 8080 8081 if (WIFSIGNALED(status)) { 8082 zerror(zonename, gettext("%s unexpectedly terminated " 8083 "due to signal %d"), 8084 cmdbuf, WTERMSIG(status)); 8085 return (-1); 8086 } 8087 assert(WIFEXITED(status)); 8088 return (WEXITSTATUS(status)); 8089 } 8090 8091 /* 8092 * This function updates the local /etc/user_attr file to 8093 * correspond to the admin settings that are currently being 8094 * committed. The updates are done via usermod and/or rolemod 8095 * depending on the type of the specified user. It is also 8096 * invoked to remove entries from user_attr corresponding to 8097 * removed admin assignments, using an empty auths string. 8098 * 8099 * Because the removed entries are no longer included in the 8100 * cofiguration that is being committed, a linked list of 8101 * removed admin entries is maintained to keep track of such 8102 * transactions. The head of the list is stored in the zone_dh_userauths 8103 * element of the handle strcture. 8104 */ 8105 static int 8106 zonecfg_authorize_user_impl(zone_dochandle_t handle, char *user, 8107 char *auths, char *zonename) 8108 { 8109 char *right; 8110 char old_auths[MAXAUTHS]; 8111 char new_auths[MAXAUTHS]; 8112 char rbac_profs[MAXPROFS]; 8113 char *lasts; 8114 userattr_t *u; 8115 boolean_t first = B_TRUE; 8116 boolean_t is_zone_admin = B_FALSE; 8117 char user_cmd[] = "/usr/sbin/usermod"; 8118 char role_cmd[] = "/usr/sbin/rolemod"; 8119 char *auths_cmd = user_cmd; /* either usermod or rolemod */ 8120 char *new_auth_start; /* string containing the new auths */ 8121 int new_auth_cnt = 0; /* delta of changed authorizations */ 8122 8123 /* 8124 * First get the existing authorizations for this user 8125 */ 8126 8127 bzero(&old_auths, sizeof (old_auths)); 8128 bzero(&new_auths, sizeof (new_auths)); 8129 bzero(&rbac_profs, sizeof (rbac_profs)); 8130 if ((u = getusernam(user)) != NULL) { 8131 char *current_auths; 8132 char *current_profs; 8133 char *type; 8134 8135 type = kva_match(u->attr, USERATTR_TYPE_KW); 8136 if (type != NULL) { 8137 if (strcmp(type, USERATTR_TYPE_NONADMIN_KW) == 0) 8138 auths_cmd = role_cmd; 8139 } 8140 8141 current_auths = kva_match(u->attr, USERATTR_AUTHS_KW); 8142 if (current_auths != NULL) { 8143 char *cur_auth; 8144 char *delete_name; 8145 size_t offset; 8146 8147 offset = strlen(ZONE_AUTH_PREFIX); 8148 8149 (void) strlcpy(old_auths, current_auths, MAXAUTHS); 8150 cur_auth = strtok_r(current_auths, ",", &lasts); 8151 8152 /* 8153 * Next, remove any existing authorizations 8154 * for this zone, and determine if the 8155 * user still needs the Zone Management Profile. 8156 */ 8157 if (is_renaming(handle)) 8158 delete_name = handle->zone_dh_delete_name; 8159 else 8160 delete_name = NULL; 8161 while (cur_auth != NULL) { 8162 if (!is_zone_auth(&cur_auth, zonename, 8163 delete_name)) { 8164 if (first) { 8165 first = B_FALSE; 8166 } else { 8167 (void) strlcat(new_auths, ",", 8168 MAXAUTHS); 8169 } 8170 (void) strlcat(new_auths, cur_auth, 8171 MAXAUTHS); 8172 /* 8173 * If the user has authorizations 8174 * for other zones, then set a 8175 * flag indicate that the Zone 8176 * Management profile should be 8177 * preserved in user_attr. 8178 */ 8179 if (strncmp(cur_auth, 8180 ZONE_AUTH_PREFIX, offset) == 0) 8181 is_zone_admin = B_TRUE; 8182 } else { 8183 new_auth_cnt++; 8184 } 8185 cur_auth = strtok_r(NULL, ",", &lasts); 8186 } 8187 } 8188 current_profs = kva_match(u->attr, USERATTR_PROFILES_KW); 8189 if (current_profs != NULL) { 8190 (void) strlcpy(rbac_profs, current_profs, MAXPROFS); 8191 } 8192 free_userattr(u); 8193 } 8194 /* 8195 * The following is done to avoid revisiting the 8196 * user_attr entry for this user 8197 */ 8198 (void) zonecfg_remove_userauths(handle, user, "", B_FALSE); 8199 8200 /* 8201 * Convert each right into a properly formatted authorization 8202 */ 8203 new_auth_start = new_auths + strlen(new_auths); 8204 if (!first) 8205 new_auth_start++; 8206 right = strtok_r(auths, ",", &lasts); 8207 while (right != NULL) { 8208 char auth[MAXAUTHS]; 8209 8210 (void) snprintf(auth, MAXAUTHS, "%s%s/%s", 8211 ZONE_AUTH_PREFIX, right, zonename); 8212 if (first) { 8213 first = B_FALSE; 8214 } else { 8215 (void) strlcat(new_auths, ",", MAXAUTHS); 8216 } 8217 (void) strlcat(new_auths, auth, MAXAUTHS); 8218 is_zone_admin = B_TRUE; 8219 new_auth_cnt--; 8220 right = strtok_r(NULL, ",", &lasts); 8221 } 8222 8223 /* 8224 * Need to update the authorizations in user_attr unless 8225 * the number of old and new authorizations is unchanged 8226 * and the new auths are a substrings of the old auths. 8227 * 8228 * If the user's previous authorizations have changed 8229 * execute the usermod progam to update them in user_attr. 8230 */ 8231 if ((new_auth_cnt != 0) || 8232 (strstr(old_auths, new_auth_start) == NULL)) { 8233 char *cmdbuf; 8234 size_t cmd_len; 8235 8236 update_profiles(rbac_profs, is_zone_admin); 8237 cmd_len = snprintf(NULL, 0, "%s -A \"%s\" -P \"%s\" %s", 8238 auths_cmd, new_auths, rbac_profs, user) + 1; 8239 if ((cmdbuf = malloc(cmd_len)) == NULL) { 8240 return (Z_NOMEM); 8241 } 8242 (void) snprintf(cmdbuf, cmd_len, "%s -A \"%s\" -P \"%s\" %s", 8243 auths_cmd, new_auths, rbac_profs, user); 8244 if (do_subproc(zonename, cmdbuf) != 0) { 8245 free(cmdbuf); 8246 return (Z_SYSTEM); 8247 } 8248 free(cmdbuf); 8249 } 8250 8251 return (Z_OK); 8252 } 8253 8254 int 8255 zonecfg_authorize_users(zone_dochandle_t handle, char *zonename) 8256 { 8257 xmlNodePtr cur; 8258 int err; 8259 char user[MAXUSERNAME]; 8260 char auths[MAXAUTHS]; 8261 8262 if ((err = operation_prep(handle)) != Z_OK) 8263 return (err); 8264 8265 cur = handle->zone_dh_cur; 8266 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 8267 if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN)) 8268 continue; 8269 if (fetchprop(cur, DTD_ATTR_USER, user, 8270 sizeof (user)) != Z_OK) 8271 continue; 8272 if (fetchprop(cur, DTD_ATTR_AUTHS, auths, 8273 sizeof (auths)) != Z_OK) 8274 continue; 8275 if (zonecfg_authorize_user_impl(handle, user, auths, zonename) 8276 != Z_OK) 8277 return (Z_SYSTEM); 8278 } 8279 (void) zonecfg_remove_userauths(handle, "", "", B_TRUE); 8280 8281 return (Z_OK); 8282 } 8283 8284 int 8285 zonecfg_deauthorize_user(zone_dochandle_t handle, char *user, char *zonename) 8286 { 8287 return (zonecfg_authorize_user_impl(handle, user, "", zonename)); 8288 } 8289 8290 int 8291 zonecfg_deauthorize_users(zone_dochandle_t handle, char *zonename) 8292 { 8293 xmlNodePtr cur; 8294 int err; 8295 char user[MAXUSERNAME]; 8296 8297 if ((err = operation_prep(handle)) != Z_OK) 8298 return (err); 8299 8300 cur = handle->zone_dh_cur; 8301 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) { 8302 if (xmlStrcmp(cur->name, DTD_ELEM_ADMIN)) 8303 continue; 8304 if (fetchprop(cur, DTD_ATTR_USER, user, 8305 sizeof (user)) != Z_OK) 8306 continue; 8307 if ((err = zonecfg_deauthorize_user(handle, user, 8308 zonename)) != Z_OK) 8309 return (err); 8310 } 8311 return (Z_OK); 8312 } 8313 8314 int 8315 zonecfg_insert_userauths(zone_dochandle_t handle, char *user, char *zonename) 8316 { 8317 zone_userauths_t *new, **prev, *next; 8318 8319 prev = &handle->zone_dh_userauths; 8320 next = *prev; 8321 while (next) { 8322 if ((strncmp(next->user, user, MAXUSERNAME) == 0) && 8323 (strncmp(next->zonename, zonename, 8324 ZONENAME_MAX) == 0)) { 8325 /* 8326 * user is already in list 8327 * which isn't supposed to happen! 8328 */ 8329 return (Z_OK); 8330 } 8331 prev = &next->next; 8332 next = *prev; 8333 } 8334 new = (zone_userauths_t *)malloc(sizeof (zone_userauths_t)); 8335 if (new == NULL) 8336 return (Z_NOMEM); 8337 8338 (void) strlcpy(new->user, user, sizeof (new->user)); 8339 (void) strlcpy(new->zonename, zonename, sizeof (new->zonename)); 8340 new->next = NULL; 8341 *prev = new; 8342 return (Z_OK); 8343 } 8344 8345 int 8346 zonecfg_remove_userauths(zone_dochandle_t handle, char *user, char *zonename, 8347 boolean_t deauthorize) 8348 { 8349 zone_userauths_t *new, **prev, *next; 8350 8351 prev = &handle->zone_dh_userauths; 8352 next = *prev; 8353 8354 while (next) { 8355 if ((strlen(user) == 0 || 8356 strncmp(next->user, user, MAXUSERNAME) == 0) && 8357 (strlen(zonename) == 0 || 8358 (strncmp(next->zonename, zonename, ZONENAME_MAX) == 0))) { 8359 new = next; 8360 *prev = next->next; 8361 next = *prev; 8362 if (deauthorize) 8363 (void) zonecfg_deauthorize_user(handle, 8364 new->user, new->zonename); 8365 free(new); 8366 continue; 8367 } 8368 prev = &next->next; 8369 next = *prev; 8370 } 8371 return (Z_OK); 8372 } 8373