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