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