int zone_get_id(const char *str, zoneid_t *zip) { zoneid_t zoneid; char *cp; /* * The first time we are called, attempt to dlopen() libzonecfg.so.1 * and get a pointer to the real zone_get_id(). * If we fail, set our pointer to -1 so we won't try again. */ if (real_zone_get_id == NULL) { /* * There's no harm in doing this more than once, even * concurrently. We will get the same result each time, * and the dynamic linker will single-thread the dlopen() * with its own internal lock. The worst that can happen * is that the handle gets a reference count greater than * one, which doesn't matter since we never dlclose() * the handle if we successfully find the symbol; the * library just stays in the address space until exit(). */ void *dlhandle = dlopen("libzonecfg.so.1", RTLD_LAZY); void *sym = (void *)(-1); if (dlhandle != NULL && (sym = dlsym(dlhandle, "zone_get_id")) == NULL) { sym = (void *)(-1); (void) dlclose(dlhandle); } real_zone_get_id = (zone_get_id_t)sym; } /* * If we've successfully loaded it, call the real zone_get_id(). * Otherwise, perform our stripped-down version of the code. */ if (real_zone_get_id != (zone_get_id_t)(-1)) return (real_zone_get_id(str, zip)); /* first try looking for active zone by id */ errno = 0; zoneid = (zoneid_t)strtol(str, &cp, 0); if (errno == 0 && cp != str && *cp == '\0' && getzonenamebyid(zoneid, NULL, 0) != -1) { *zip = zoneid; return (0); } /* then look for active zone by name */ if ((zoneid = getzoneidbyname(str)) != -1) { *zip = zoneid; return (0); } /* not an active zone, return error */ return (-1); }
/* * Lookup ids for each zone name; this is done once each time /proc * is scanned to avoid calling getzoneidbyname for each process. */ void convert_zone(zonetbl_t *tbl) { long i; zoneid_t id; char *name; for (i = 0; i < tbl->z_nent; i++) { name = tbl->z_list[i].z_name; if (name != NULL) { if ((id = getzoneidbyname(name)) != -1) tbl->z_list[i].z_id = id; } } }
/* * Print all of the MLPs for the given zone. */ static int print_mlp(const char *zonename) { tsol_mlpent_t tsme; if ((tsme.tsme_zoneid = getzoneidbyname(zonename)) == -1) { (void) fprintf(stderr, gettext("tninfo: zone '%s' unknown\n"), zonename); return (1); } tsme.tsme_flags = 0; if (iterate_mlps(&tsme, gettext("private")) == -1) return (1); tsme.tsme_flags = TSOL_MEF_SHARED; if (iterate_mlps(&tsme, gettext("shared")) == -1) return (1); return (0); }
int main(int argc, char *argv[]) { int ii; ipdadm_cmd_t *cmd; g_pname = basename(argv[0]); if (argc < 2) return (usage(stderr)); argc--; argv++; g_zid = getzoneid(); if (strcmp("-z", argv[0]) == 0) { argc--; argv++; if (argc < 1) { (void) fprintf(stderr, "%s: -z requires an argument\n", g_pname); return (usage(stderr)); } if (g_zid != GLOBAL_ZONEID) { (void) fprintf(stderr, "%s: -z option only permitted " "in global zone\n", g_pname); return (usage(stderr)); } g_zid = getzoneidbyname(argv[0]); if (g_zid == -1) { (void) fprintf(stderr, "%s: %s: invalid zone\n", g_pname, argv[0]); return (E_ERROR); } argc--; argv++; } if (getzonenamebyid(g_zid, g_zonename, sizeof (g_zonename)) < 0) { (void) fprintf(stderr, "%s: failed to get zonename: %s\n", g_pname, strerror(errno)); return (E_ERROR); } if (argc < 1) return (usage(stderr)); for (ii = 0; ii < IPDADM_NCMDS; ii++) { cmd = &ipdadm_cmds[ii]; if (strcmp(argv[0], cmd->idc_name) == 0) { argv++; argc--; assert(cmd->idc_func != NULL); return (cmd->idc_func(argc, argv)); } } (void) fprintf(stderr, "%s: %s: unknown command\n", g_pname, argv[0]); return (usage(stderr)); }
int _zexec(const char *a_zoneName, const char *a_path, char *a_argv[]) { zoneid_t zoneid; zone_state_t st; char **new_env = { NULL }; priv_set_t *privset; /* entry assertions */ assert(a_zoneName != NULL); assert(*a_zoneName != '\0'); assert(a_path != NULL); assert(*a_path != '\0'); /* establish locale settings */ (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); /* can only be invoked from within the global zone */ if (getzoneid() != GLOBAL_ZONEID) { _z_program_error(ERR_ZEXEC_NOT_IN_GZ, a_zoneName); return (-1); } if (strcmp(a_zoneName, GLOBAL_ZONENAME) == 0) { _z_program_error(ERR_ZEXEC_GZUSED, a_zoneName); return (-1); } /* get the state of the specified zone */ if (zone_get_state((char *)a_zoneName, &st) != Z_OK) { _z_program_error(ERR_ZEXEC_BADZONE, a_zoneName); return (-1); } if (st < ZONE_STATE_INSTALLED) { _z_program_error(ERR_ZEXEC_BADSTATE, a_zoneName, zone_state_str(st)); return (-1); } if (st != ZONE_STATE_RUNNING && st != ZONE_STATE_MOUNTED) { _z_program_error(ERR_ZEXEC_NOTRUNNING, a_zoneName, zone_state_str(st)); return (-1); } /* * In both console and non-console cases, we require all privs. * In the console case, because we may need to startup zoneadmd. * In the non-console case in order to do zone_enter(2), zonept() * and other tasks. * * Future work: this solution is temporary. Ultimately, we need to * move to a flexible system which allows the global admin to * designate that a particular user can zlogin (and probably zlogin * -C) to a particular zone. This all-root business we have now is * quite sketchy. */ if ((privset = priv_allocset()) == NULL) { _z_program_error(ERR_ZEXEC_PRIV_ALLOCSET, a_zoneName, strerror(errno)); return (-1); } if (getppriv(PRIV_EFFECTIVE, privset) != 0) { _z_program_error(ERR_ZEXEC_GETPPRIV, a_zoneName, strerror(errno)); priv_freeset(privset); return (-1); } if (priv_isfullset(privset) == B_FALSE) { _z_program_error(ERR_ZEXEC_PRIVS, a_zoneName); priv_freeset(privset); return (-1); } priv_freeset(privset); if ((zoneid = getzoneidbyname(a_zoneName)) == -1) { _z_program_error(ERR_ZEXEC_NOZONEID, a_zoneName, strerror(errno)); return (-1); } if ((new_env = _zexec_prep_env()) == NULL) { _z_program_error(ERR_ZEXEC_ASSEMBLE, a_zoneName); return (-1); } /* * In case any of stdin, stdout or stderr are streams, * anchor them to prevent malicious I_POPs. * * Future work: use pipes to entirely eliminate FD leakage * into the zone. */ (void) ioctl(STDIN_FILENO, I_ANCHOR); (void) ioctl(STDOUT_FILENO, I_ANCHOR); (void) ioctl(STDERR_FILENO, I_ANCHOR); if (zone_enter(zoneid) == -1) { int lerrno = errno; _z_program_error(ERR_ZEXEC_ZONEENTER, a_zoneName, strerror(errno)); if (lerrno == EFAULT) { _z_program_error(ERR_ZEXEC_EFAULT, a_zoneName); } free(new_env); return (-1); } (void) execve(a_path, &a_argv[0], new_env); _z_program_error(ERR_ZEXEC_EXECFAILURE, a_zoneName, strerror(errno)); return (-1); }
} static void zsock_ctx_set_errno(zsock_create_ctx_t *ccp, const char *syscall, int err) { if (ccp->zcc_syscall == NULL) ccp->zcc_syscall = syscall; ccp->zcc_errno = err; } static void * zsocket_create(void *op __UNUSED, void *ctx) { zsock_create_ctx_t *ccp = ctx; zoneid_t zoneid = getzoneidbyname(ccp->zcc_zone); int sock_fd = -1; int attempts = 1; if (zoneid < 0) { zsock_ctx_set_errno(ccp, "getzoneidbyname", errno); return (NULL); } do { /* This call suffers from EINTR, so just retry */ sock_fd = zsocket(zoneid, ccp->zcc_path); } while (attempts++ < 3 && sock_fd < 0); ccp->zcc_fd = sock_fd;
int main(int argc, char *argv[]) { FILE *f; char *ptr, *start; struct passwd *pwd; char *term_name; int c; int aflag = 0; int errflg = 0; int zflg = 0; int Zflg = 0; char *zonename = NULL; zoneid_t *zoneidlist = NULL; uint_t nzids_saved, nzids = 0; (void) setlocale(LC_ALL, ""); while ((c = getopt(argc, argv, "g:az:Z")) != EOF) switch (c) { case 'a': aflag++; break; case 'g': if (gflag) { (void) fprintf(stderr, "Only one group allowed\n"); return (1); } if ((pgrp = getgrnam(grpname = optarg)) == NULL) { (void) fprintf(stderr, "Unknown group %s\n", grpname); return (1); } gflag++; break; case 'z': zflg++; zonename = optarg; if (getzoneidbyname(zonename) == -1) { (void) fprintf(stderr, "Specified zone %s " "is invalid", zonename); return (1); } break; case 'Z': Zflg++; break; case '?': errflg++; break; } if (errflg) { (void) fprintf(stderr, "Usage: wall [-a] [-g group] [-z zone] [-Z] [files...]\n"); return (1); } if (zflg && Zflg) { (void) fprintf(stderr, "Cannot use -z with -Z\n"); return (1); } if (optind < argc) infile = argv[optind]; if (uname(&utsn) == -1) { (void) fprintf(stderr, "wall: uname() failed, %s\n", strerror(errno)); return (2); } (void) strcpy(systm, utsn.nodename); /* * Get the name of the terminal wall is running from. */ if ((term_name = ttyname(fileno(stderr))) != NULL) { /* * skip the leading "/dev/" in term_name */ (void) strncpy(line, &term_name[5], sizeof (line) - 1); } if (who[0] == '?') { if (pwd = getpwuid(getuid())) (void) strncpy(&who[0], pwd->pw_name, sizeof (who)); } f = stdin; if (infile) { f = fopen(infile, "r"); if (f == NULL) { (void) fprintf(stderr, "Cannot open %s\n", infile); return (1); } } start = &mesg[0]; ptr = start; while ((ptr - start) < 3000) { size_t n; if (fgets(ptr, &mesg[sizeof (mesg)] - ptr, f) == NULL) break; if ((n = strlen(ptr)) == 0) break; ptr += n; } (void) fclose(f); /* * If the request is from the rwall daemon then use the caller's * name and host. We determine this if all of the following is true: * 1) First 5 characters are "From " * 2) Next non-white characters are of the form "name@host:" */ if (strcmp(line, "???") == 0) { char rwho[MAXNAMLEN+1]; char rsystm[MAXNAMLEN+1]; char *cp; if (strncmp(mesg, "From ", 5) == 0) { cp = &mesg[5]; cp = copy_str_till(rwho, cp, '@', MAXNAMLEN + 1); if (rwho[0] != '\0') { cp = copy_str_till(rsystm, ++cp, ':', MAXNAMLEN + 1); if (rsystm[0] != '\0') { (void) strcpy(systm, rsystm); (void) strncpy(rwho, who, sizeof (who)); (void) strcpy(line, "rpc.rwalld"); } } } } (void) time(&tloc); (void) strftime(time_buf, sizeof (time_buf), DATE_FMT, localtime(&tloc)); if (zflg != 0) { if ((zoneidlist = malloc(sizeof (zoneid_t))) == NULL || (*zoneidlist = getzoneidbyname(zonename)) == -1) return (errno); nzids = 1; } else if (Zflg != 0) { if (zone_list(NULL, &nzids) != 0) return (errno); again: nzids *= 2; if ((zoneidlist = malloc(nzids * sizeof (zoneid_t))) == NULL) exit(errno); nzids_saved = nzids; if (zone_list(zoneidlist, &nzids) != 0) { (void) free(zoneidlist); return (errno); } if (nzids > nzids_saved) { free(zoneidlist); goto again; } } if (zflg || Zflg) { for (; nzids > 0; --nzids) sendmes_tozone(zoneidlist[nzids-1], aflag); free(zoneidlist); } else sendmes_tozone(getzoneid(), aflag); return (0); }