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