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