diff options
author | jamie <jamie@FreeBSD.org> | 2009-05-27 14:30:26 +0000 |
---|---|---|
committer | jamie <jamie@FreeBSD.org> | 2009-05-27 14:30:26 +0000 |
commit | 8dbff96dac0a8009a4169eedbbe59be58a480889 (patch) | |
tree | 4a406964696e0ebb946248969d86b305f81eab7b /usr.sbin/jls | |
parent | a013e0afcbb44052a86a7977277d669d8883b7e7 (diff) | |
download | FreeBSD-src-8dbff96dac0a8009a4169eedbbe59be58a480889.zip FreeBSD-src-8dbff96dac0a8009a4169eedbbe59be58a480889.tar.gz |
Add support for the arbitrary named jail parameters used by jail_set(2)
and jail_get(2). Jail(8) can now create jails using a "name=value"
format instead of just specifying a limited set of fixed parameters; it
can also modify parameters of existing jails. Jls(8) can display all
parameters of jails, or a specified set of parameters. The available
parameters are gathered from the kernel, and not hard-coded into these
programs.
Small patches on killall(1) and jexec(8) to support jail names with
jail_get(2).
Approved by: bz (mentor)
Diffstat (limited to 'usr.sbin/jls')
-rw-r--r-- | usr.sbin/jls/Makefile | 2 | ||||
-rw-r--r-- | usr.sbin/jls/jls.8 | 84 | ||||
-rw-r--r-- | usr.sbin/jls/jls.c | 878 |
3 files changed, 750 insertions, 214 deletions
diff --git a/usr.sbin/jls/Makefile b/usr.sbin/jls/Makefile index 01294bd..3968946 100644 --- a/usr.sbin/jls/Makefile +++ b/usr.sbin/jls/Makefile @@ -4,6 +4,4 @@ PROG= jls MAN= jls.8 WARNS?= 6 -CFLAGS+= -DSUPPORT_OLD_XPRISON - .include <bsd.prog.mk> diff --git a/usr.sbin/jls/jls.8 b/usr.sbin/jls/jls.8 index aff9848..c0eed8d 100644 --- a/usr.sbin/jls/jls.8 +++ b/usr.sbin/jls/jls.8 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 29, 2008 +.Dd May 27, 2009 .Dt JLS 8 .Os .Sh NAME @@ -33,38 +33,68 @@ .Nd "list jails" .Sh SYNOPSIS .Nm -.Op Fl av +.Op Fl dhnqsv +.Op Fl j Ar jail +.Op Ar parameter ... .Sh DESCRIPTION The .Nm -utility lists all jails. -By default only active jails are listed. +utility lists all active jails, or the specified jail. +Each jail is represented by one row which contains space-separated values of +the listed +.Ar parameters , +including the pseudo-parameter +.Va all +which will show all available jail parameters. +A list of available parameters can be retrieved via +.Dq Nm sysctl Fl d Va security.jail.param . +See +.Xr jail 8 +for a description of some core parameters. .Pp -The options are as follows: -.Bl -tag -width ".Fl a" -.It Fl a -Show jails in all states, not only active ones. -.It Fl v -Show more verbose information. -This also lists cpusets, jail state, multi-IP, etc. instead of the -classic single-IP jail output. -.El +If no +.Ar parameters +are given, the following four columns will be printed: +jail identifier (jid), IP address (ip4.addr), hostname (host.hostname), +and path (path). .Pp -Each jail is represented by rows which, depending on -.Fl v , -contain the following columns: -.Bl -item -offset indent -compact -.It -jail identifier (JID), hostname and path -.It -jail state and name -.It -jail cpuset -.It -followed by one IP adddress per line. +The following options are available: +.Bl -tag -width indent +.It Fl d +List +.Va dying +as well as active jails. +.It Fl h +Print a header line containing the parameters listed. +If no parameters are given on the command line, the default output always +contains a header. +.It Fl n +Print parameters in +.Dq name=value +format, where each parameter is preceded by its name. +This option is ignored for the default four-column output. +.It Fl q +Put quotes around parameters if they contain spaces or quotes, or are +the empty string. +.It Fl c +Print parameters suitable for passing to +.Xr jail 8 , +skipping read-only and unused parameters. +Implies +.Fl nq . +.It Fl v +Print a multiple-line summary per jail, with the following parameters: +jail identifier (jid), hostname (host.hostname), path (path), +jail name (name), jail state (dying), cpuset ID (cpuset), +IP address(es) (ip4.addr and ip6.addr). +.It Fl j Ar jail +The jid or name of the +.Ar jail +to list. +Without this option, all active jails will be listed. .El .Sh SEE ALSO -.Xr jail 2 , +.Xr jail_get 2 , .Xr jail 8 , .Xr jexec 8 .Sh HISTORY @@ -72,3 +102,5 @@ The .Nm utility was added in .Fx 5.1 . +Extensible jail parameters were introduced in +.Fx 8.0 . diff --git a/usr.sbin/jls/jls.c b/usr.sbin/jls/jls.c index 95f17d4..cc8dabd 100644 --- a/usr.sbin/jls/jls.c +++ b/usr.sbin/jls/jls.c @@ -1,6 +1,7 @@ /*- * Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org> * Copyright (c) 2008 Bjoern A. Zeeb <bz@FreeBSD.org> + * Copyright (c) 2009 James Gritton <jamie@FreeBSD.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,18 +24,20 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + #include <sys/param.h> -#include <sys/types.h> #include <sys/jail.h> +#include <sys/socket.h> #include <sys/sysctl.h> +#include <sys/uio.h> -#include <sys/socket.h> -#include <netinet/in.h> #include <arpa/inet.h> +#include <netinet/in.h> + #include <err.h> #include <errno.h> #include <limits.h> @@ -43,215 +46,718 @@ #include <string.h> #include <unistd.h> -#define FLAG_A 0x00001 -#define FLAG_V 0x00002 +#define SJPARAM "security.jail.param" +#define ARRAY_SLOP 5 + +#define CTLTYPE_BOOL (CTLTYPE + 1) +#define CTLTYPE_NOBOOL (CTLTYPE + 2) +#define CTLTYPE_IPADDR (CTLTYPE + 3) +#define CTLTYPE_IP6ADDR (CTLTYPE + 4) + +#define PARAM_KEY 0x01 +#define PARAM_USER 0x02 +#define PARAM_ARRAY 0x04 +#define PARAM_OPT 0x08 +#define PARAM_WR 0x10 + +#define PRINT_DEFAULT 0x01 +#define PRINT_HEADER 0x02 +#define PRINT_NAMEVAL 0x04 +#define PRINT_QUOTED 0x08 +#define PRINT_SKIP 0x10 +#define PRINT_VERBOSE 0x20 + +struct param { + char *name; + void *value; + size_t size; + int type; + unsigned flags; + int noparent; +}; + +struct iovec2 { + struct iovec name; + struct iovec value; +}; + +static struct param *params; +static int nparams; +static char errmsg[256]; + +static int add_param(const char *name, void *value, unsigned flags); +static int get_param(const char *name, struct param *param); +static int sort_param(const void *a, const void *b); +static char *noname(const char *name); +static char *nononame(const char *name); +static int print_jail(int pflags, int jflags); +static void quoted_print(char *str, int len); -#ifdef SUPPORT_OLD_XPRISON -static -char *print_xprison_v1(void *p, char *end, unsigned flags) +int +main(int argc, char **argv) { - struct xprison_v1 *xp; - struct in_addr in; - - if ((char *)p + sizeof(struct xprison_v1) > end) - errx(1, "Invalid length for jail"); - - xp = (struct xprison_v1 *)p; - if (flags & FLAG_V) { - printf("%6d %-29.29s %.74s\n", - xp->pr_id, xp->pr_host, xp->pr_path); - /* We are not printing an empty line here for state and name. */ - /* We are not printing an empty line here for cpusetid. */ - /* IPv4 address. */ - in.s_addr = htonl(xp->pr_ip); - printf("%6s %-15.15s\n", "", inet_ntoa(in)); + char *dot, *ep, *jname, *nname; + int c, i, jflags, jid, lastjid, pflags, spc; + + jname = NULL; + pflags = jflags = jid = 0; + while ((c = getopt(argc, argv, "adj:hnqsv")) >= 0) + switch (c) { + case 'a': + case 'd': + jflags |= JAIL_DYING; + break; + case 'j': + jid = strtoul(optarg, &ep, 10); + if (!*optarg || *ep) + jname = optarg; + break; + case 'h': + pflags = (pflags & ~PRINT_SKIP) | PRINT_HEADER; + break; + case 'n': + pflags = (pflags & ~PRINT_VERBOSE) | PRINT_NAMEVAL; + break; + case 'q': + pflags |= PRINT_QUOTED; + break; + case 's': + pflags = (pflags & ~(PRINT_HEADER | PRINT_VERBOSE)) | + PRINT_NAMEVAL | PRINT_QUOTED | PRINT_SKIP; + break; + case 'v': + pflags = (pflags & ~(PRINT_NAMEVAL | PRINT_SKIP)) | + PRINT_VERBOSE; + break; + default: + errx(1, "usage: jls [-dhnqv] [-j jail] [param ...]"); + } + + /* Add the parameters to print. */ + if (optind == argc) { + if (pflags & PRINT_VERBOSE) { + add_param("jid", NULL, PARAM_USER); + add_param("host.hostname", NULL, PARAM_USER); + add_param("path", NULL, PARAM_USER); + add_param("name", NULL, PARAM_USER); + add_param("dying", NULL, PARAM_USER); + add_param("cpuset", NULL, PARAM_USER); + add_param("ip4.addr", NULL, PARAM_USER); + add_param("ip6.addr", NULL, PARAM_USER | PARAM_OPT); + } else { + pflags = (pflags & + ~(PRINT_NAMEVAL | PRINT_SKIP | PRINT_VERBOSE)) | + PRINT_DEFAULT; + add_param("jid", NULL, PARAM_USER); + add_param("ip4.addr", NULL, PARAM_USER); + add_param("host.hostname", NULL, PARAM_USER); + add_param("path", NULL, PARAM_USER); + } + } else + while (optind < argc) + add_param(argv[optind++], NULL, PARAM_USER); + + if (pflags & PRINT_SKIP) { + /* Check for parameters with boolean parents. */ + for (i = 0; i < nparams; i++) { + if ((params[i].flags & PARAM_USER) && + (dot = strchr(params[i].name, '.'))) { + *dot = 0; + nname = noname(params[i].name); + *dot = '.'; + params[i].noparent = + add_param(nname, NULL, PARAM_OPT); + free(nname); + } + } + } + + /* Add the index key and errmsg parameters. */ + if (jid != 0) + add_param("jid", &jid, PARAM_KEY); + else if (jname != NULL) + add_param("name", jname, PARAM_KEY); + else + add_param("lastjid", &lastjid, PARAM_KEY); + add_param("errmsg", errmsg, PARAM_KEY); + + /* Print a header line if requested. */ + if (pflags & PRINT_VERBOSE) + printf(" JID Hostname Path\n" + " Name State\n" + " CPUSetID\n" + " IP Address(es)\n"); + else if (pflags & PRINT_DEFAULT) + printf(" JID IP Address " + "Hostname Path\n"); + else if (pflags & PRINT_HEADER) { + for (i = spc = 0; i < nparams; i++) + if (params[i].flags & PARAM_USER) { + if (spc) + putchar(' '); + else + spc = 1; + fputs(params[i].name, stdout); + } + putchar('\n'); + } + + /* Fetch the jail(s) and print the paramters. */ + if (jid != 0 || jname != NULL) { + if (print_jail(pflags, jflags) < 0) { + if (errmsg[0]) + errx(1, "%s", errmsg); + err(1, "jail_get"); + } } else { - printf("%6d %-15.15s %-29.29s %.74s\n", - xp->pr_id, inet_ntoa(in), xp->pr_host, xp->pr_path); + for (lastjid = 0; + (lastjid = print_jail(pflags, jflags)) >= 0; ) + ; + if (errno != 0 && errno != ENOENT) { + if (errmsg[0]) + errx(1, "%s", errmsg); + err(1, "jail_get"); + } } - return ((char *)(xp + 1)); + return (0); } -#endif -static -char *print_xprison_v3(void *p, char *end, unsigned flags) +static int +add_param(const char *name, void *value, unsigned flags) { - struct xprison *xp; - struct in_addr *iap, in; - struct in6_addr *ia6p; - char buf[INET6_ADDRSTRLEN]; - const char *state; - char *q; - uint32_t i; - - if ((char *)p + sizeof(struct xprison) > end) - errx(1, "Invalid length for jail"); - xp = (struct xprison *)p; - - if (xp->pr_state < 0 || xp->pr_state >= (int) - ((sizeof(prison_states) / sizeof(struct prison_state)))) - state = "(bogus)"; - else - state = prison_states[xp->pr_state].state_name; - - /* See if we should print non-ACTIVE jails. No? */ - if ((flags & FLAG_A) == 0 && strcmp(state, "ALIVE")) { - q = (char *)(xp + 1); - q += (xp->pr_ip4s * sizeof(struct in_addr)); - if (q > end) - errx(1, "Invalid length for jail"); - q += (xp->pr_ip6s * sizeof(struct in6_addr)); - if (q > end) - errx(1, "Invalid length for jail"); - return (q); + struct param *param; + char *nname; + size_t mlen1, mlen2, buflen; + int mib1[CTL_MAXNAME], mib2[CTL_MAXNAME - 2]; + int i, tnparams; + char buf[MAXPATHLEN]; + + static int paramlistsize; + + /* The pseudo-parameter "all" scans the list of available parameters. */ + if (!strcmp(name, "all")) { + tnparams = nparams; + mib1[0] = 0; + mib1[1] = 2; + mlen1 = CTL_MAXNAME - 2; + if (sysctlnametomib(SJPARAM, mib1 + 2, &mlen1) < 0) + err(1, "sysctlnametomib(" SJPARAM ")"); + for (;;) { + /* Get the next parameter. */ + mlen2 = sizeof(mib2); + if (sysctl(mib1, mlen1 + 2, mib2, &mlen2, NULL, 0) < 0) + err(1, "sysctl(0.2)"); + if (mib2[0] != mib1[2] || mib2[1] != mib1[3] || + mib2[2] != mib1[4]) + break; + /* Convert it to an ascii name. */ + memcpy(mib1 + 2, mib2, mlen2); + mlen1 = mlen2 / sizeof(int); + mib1[1] = 1; + buflen = sizeof(buf); + if (sysctl(mib1, mlen1 + 2, buf, &buflen, NULL, 0) < 0) + err(1, "sysctl(0.1)"); + add_param(buf + sizeof(SJPARAM), NULL, flags); + /* + * Convert nobool parameters to bool if their + * counterpart is a node, ortherwise discard them. + */ + param = ¶ms[nparams - 1]; + if (param->type == CTLTYPE_NOBOOL) { + nname = nononame(param->name); + if (get_param(nname, param) >= 0 && + param->type != CTLTYPE_NODE) { + free(nname); + nparams--; + } else { + free(param->name); + param->name = nname; + param->type = CTLTYPE_BOOL; + param->size = sizeof(int); + param->value = NULL; + } + } + mib1[1] = 2; + } + + qsort(params + tnparams, (size_t)(nparams - tnparams), + sizeof(struct param), sort_param); + return -1; + } + + /* Check for repeat parameters. */ + for (i = 0; i < nparams; i++) + if (!strcmp(name, params[i].name)) { + params[i].value = value; + params[i].flags |= flags; + return i; + } + + /* Make sure there is room for the new param record. */ + if (!nparams) { + paramlistsize = 32; + params = malloc(paramlistsize * sizeof(*params)); + if (params == NULL) + err(1, "malloc"); + } else if (nparams >= paramlistsize) { + paramlistsize *= 2; + params = realloc(params, paramlistsize * sizeof(*params)); + if (params == NULL) + err(1, "realloc"); + } + + /* Look up the parameter. */ + param = params + nparams++; + memset(param, 0, sizeof *param); + param->name = strdup(name); + if (param->name == NULL) + err(1, "strdup"); + param->flags = flags; + param->noparent = -1; + /* We have to know about pseudo-parameters without asking. */ + if (!strcmp(param->name, "lastjid")) { + param->type = CTLTYPE_INT; + param->size = sizeof(int); + goto got_type; + } + if (!strcmp(param->name, "errmsg")) { + param->type = CTLTYPE_STRING; + param->size = sizeof(errmsg); + goto got_type; + } + if (get_param(name, param) < 0) { + if (errno != ENOENT) + err(1, "sysctl(0.3.%s)", name); + /* See if this the "no" part of an existing boolean. */ + if ((nname = nononame(name))) { + i = get_param(nname, param); + free(nname); + if (i >= 0 && param->type == CTLTYPE_BOOL) { + param->type = CTLTYPE_NOBOOL; + goto got_type; + } + } + if (flags & PARAM_OPT) { + nparams--; + return -1; + } + errx(1, "unknown parameter: %s", name); + } + if (param->type == CTLTYPE_NODE) { + /* + * A node isn't normally a parameter, but may be a boolean + * if its "no" counterpart exists. + */ + nname = noname(name); + i = get_param(nname, param); + free(nname); + if (i >= 0 && param->type == CTLTYPE_NOBOOL) { + param->type = CTLTYPE_BOOL; + goto got_type; + } + errx(1, "unknown parameter: %s", name); } - if (flags & FLAG_V) - printf("%6d %-29.29s %.74s\n", - xp->pr_id, xp->pr_host, xp->pr_path); - - /* Jail state and name. */ - if (flags & FLAG_V) - printf("%6s %-29.29s %.74s\n", - "", (xp->pr_name[0] != '\0') ? xp->pr_name : "", state); - - /* cpusetid. */ - if (flags & FLAG_V) - printf("%6s %-6d\n", - "", xp->pr_cpusetid); - - q = (char *)(xp + 1); - /* IPv4 addresses. */ - iap = (struct in_addr *)(void *)q; - q += (xp->pr_ip4s * sizeof(struct in_addr)); - if (q > end) - errx(1, "Invalid length for jail"); - in.s_addr = 0; - for (i = 0; i < xp->pr_ip4s; i++) { - if (i == 0 || flags & FLAG_V) - in.s_addr = iap[i].s_addr; - if (flags & FLAG_V) - printf("%6s %-15.15s\n", "", inet_ntoa(in)); + got_type: + param->value = value; + return param - params; +} + +static int +get_param(const char *name, struct param *param) +{ + char *p; + size_t buflen, mlen; + int mib[CTL_MAXNAME]; + struct { + int i; + char s[MAXPATHLEN]; + } buf; + + /* Look up the MIB. */ + mib[0] = 0; + mib[1] = 3; + snprintf(buf.s, sizeof(buf.s), SJPARAM ".%s", name); + mlen = sizeof(mib) - 2 * sizeof(int); + if (sysctl(mib, 2, mib + 2, &mlen, buf.s, strlen(buf.s)) < 0) + return (-1); + /* Get the type and size. */ + mib[1] = 4; + buflen = sizeof(buf); + if (sysctl(mib, (mlen / sizeof(int)) + 2, &buf, &buflen, NULL, 0) < 0) + err(1, "sysctl(0.4.%s)", name); + param->type = buf.i & CTLTYPE; + if (buf.i & (CTLFLAG_WR | CTLFLAG_TUN)) + param->flags |= PARAM_WR; + p = strchr(buf.s, '\0'); + if (p - 2 >= buf.s && !strcmp(p - 2, ",a")) { + p[-2] = 0; + param->flags |= PARAM_ARRAY; } - /* IPv6 addresses. */ - ia6p = (struct in6_addr *)(void *)q; - q += (xp->pr_ip6s * sizeof(struct in6_addr)); - if (q > end) - errx(1, "Invalid length for jail"); - for (i = 0; i < xp->pr_ip6s; i++) { - if (flags & FLAG_V) { - inet_ntop(AF_INET6, &ia6p[i], buf, sizeof(buf)); - printf("%6s %s\n", "", buf); + switch (param->type) { + case CTLTYPE_INT: + /* An integer parameter might be a boolean. */ + if (buf.s[0] == 'B') + param->type = buf.s[1] == 'N' + ? CTLTYPE_NOBOOL : CTLTYPE_BOOL; + case CTLTYPE_UINT: + param->size = sizeof(int); + break; + case CTLTYPE_LONG: + case CTLTYPE_ULONG: + param->size = sizeof(long); + break; + case CTLTYPE_STRUCT: + if (!strcmp(buf.s, "S,in_addr")) { + param->type = CTLTYPE_IPADDR; + param->size = sizeof(struct in_addr); + } else if (!strcmp(buf.s, "S,in6_addr")) { + param->type = CTLTYPE_IP6ADDR; + param->size = sizeof(struct in6_addr); } + break; + case CTLTYPE_STRING: + buf.s[0] = 0; + sysctl(mib + 2, mlen / sizeof(int), buf.s, &buflen, NULL, 0); + param->size = strtoul(buf.s, NULL, 10); + if (param->size == 0) + param->size = BUFSIZ; } + return (0); +} - /* If requested print the old style single line version. */ - if (!(flags & FLAG_V)) - printf("%6d %-15.15s %-29.29s %.74s\n", - xp->pr_id, (in.s_addr) ? inet_ntoa(in) : "", - xp->pr_host, xp->pr_path); +static int +sort_param(const void *a, const void *b) +{ + const struct param *parama, *paramb; + char *ap, *bp; - return (q); + /* Put top-level parameters first. */ + parama = a; + paramb = b; + ap = strchr(parama->name, '.'); + bp = strchr(paramb->name, '.'); + if (ap && !bp) + return (1); + if (bp && !ap) + return (-1); + return (strcmp(parama->name, paramb->name)); } -static void -usage(void) +static char * +noname(const char *name) { + char *nname, *p; - (void)fprintf(stderr, "usage: jls [-av]\n"); - exit(1); + nname = malloc(strlen(name) + 3); + if (nname == NULL) + err(1, "malloc"); + p = strrchr(name, '.'); + if (p != NULL) + sprintf(nname, "%.*s.no%s", (int)(p - name), name, p + 1); + else + sprintf(nname, "no%s", name); + return nname; } -int -main(int argc, char *argv[]) -{ - int ch, version; - unsigned flags; - size_t i, j, len; - void *p, *q; +static char * +nononame(const char *name) +{ + char *nname, *p; - flags = 0; - while ((ch = getopt(argc, argv, "av")) != -1) { - switch (ch) { - case 'a': - flags |= FLAG_A; - break; - case 'v': - flags |= FLAG_V; - break; - default: - usage(); + p = strrchr(name, '.'); + if (strncmp(p ? p + 1 : name, "no", 2)) + return NULL; + nname = malloc(strlen(name) - 1); + if (nname == NULL) + err(1, "malloc"); + if (p != NULL) + sprintf(nname, "%.*s.%s", (int)(p - name), name, p + 3); + else + strcpy(nname, name + 2); + return nname; +} + +static int +print_jail(int pflags, int jflags) +{ + char *nname; + int i, ai, jid, count, sanity, spc; + char ipbuf[INET6_ADDRSTRLEN]; + + static struct iovec2 *iov, *aiov; + static int narray, nkey; + + /* Set up the parameter list(s) the first time around. */ + if (iov == NULL) { + iov = malloc(nparams * sizeof(struct iovec2)); + if (iov == NULL) + err(1, "malloc"); + for (i = narray = 0; i < nparams; i++) { + iov[i].name.iov_base = params[i].name; + iov[i].name.iov_len = strlen(params[i].name) + 1; + iov[i].value.iov_base = params[i].value; + iov[i].value.iov_len = + params[i].type == CTLTYPE_STRING && + params[i].value != NULL && + ((char *)params[i].value)[0] != '\0' + ? strlen(params[i].value) + 1 : params[i].size; + if (params[i].flags & (PARAM_KEY | PARAM_ARRAY)) { + narray++; + if (params[i].flags & PARAM_KEY) + nkey++; + } + } + if (narray > nkey) { + aiov = malloc(narray * sizeof(struct iovec2)); + if (aiov == NULL) + err(1, "malloc"); + for (i = ai = 0; i < nparams; i++) + if (params[i].flags & + (PARAM_KEY | PARAM_ARRAY)) + aiov[ai++] = iov[i]; } } - argc -= optind; - argv += optind; - - if (sysctlbyname("security.jail.list", NULL, &len, NULL, 0) == -1) - err(1, "sysctlbyname(): security.jail.list"); - - j = len; - for (i = 0; i < 4; i++) { - if (len <= 0) - exit(0); - p = q = malloc(len); - if (p == NULL) - err(1, "malloc()"); - - if (sysctlbyname("security.jail.list", q, &len, NULL, 0) == -1) { - if (errno == ENOMEM) { - free(p); - p = NULL; - len += j; - continue; + /* If there are array parameters, find their sizes. */ + if (aiov != NULL) { + for (ai = 0; ai < narray; ai++) + if (aiov[ai].value.iov_base == NULL) + aiov[ai].value.iov_len = 0; + if (jail_get((struct iovec *)aiov, 2 * narray, jflags) < 0) + return (-1); + } + /* Allocate storage for all parameters. */ + for (i = ai = 0; i < nparams; i++) { + if (params[i].flags & (PARAM_KEY | PARAM_ARRAY)) { + if (params[i].flags & PARAM_ARRAY) { + iov[i].value.iov_len = aiov[ai].value.iov_len + + ARRAY_SLOP * params[i].size; + iov[i].value.iov_base = + malloc(iov[i].value.iov_len); } - err(1, "sysctlbyname(): security.jail.list"); - } - break; + ai++; + } else + iov[i].value.iov_base = malloc(params[i].size); + if (iov[i].value.iov_base == NULL) + err(1, "malloc"); + if (params[i].value == NULL) + memset(iov[i].value.iov_base, 0, iov[i].value.iov_len); } - if (p == NULL) - err(1, "sysctlbyname(): security.jail.list"); - if (len < sizeof(int)) - errx(1, "This is no prison. Kernel and userland out of sync?"); - version = *(int *)p; - if (version > XPRISON_VERSION) - errx(1, "Sci-Fi prison. Kernel/userland out of sync?"); - - if (flags & FLAG_V) { - printf(" JID Hostname Path\n"); - printf(" Name State\n"); - printf(" CPUSetID\n"); - printf(" IP Address(es)\n"); - } else { - printf(" JID IP Address Hostname" - " Path\n"); + /* + * Get the actual prison. If there are array elements, retry a few + * times in case the size changed from under us. + */ + if ((jid = jail_get((struct iovec *)iov, 2 * nparams, jflags)) < 0) { + if (errno != EINVAL || aiov == NULL || errmsg[0]) + return (-1); + for (sanity = 0;; sanity++) { + if (sanity == 10) + return (-1); + for (ai = 0; ai < narray; ai++) + if (params[i].flags & PARAM_ARRAY) + aiov[ai].value.iov_len = 0; + if (jail_get((struct iovec *)iov, 2 * narray, jflags) < + 0) + return (-1); + for (i = ai = 0; i < nparams; i++) { + if (!(params[i].flags & + (PARAM_KEY | PARAM_ARRAY))) + continue; + if (params[i].flags & PARAM_ARRAY) { + iov[i].value.iov_len = + aiov[ai].value.iov_len + + ARRAY_SLOP * params[i].size; + iov[i].value.iov_base = + realloc(iov[i].value.iov_base, + iov[i].value.iov_len); + if (iov[i].value.iov_base == NULL) + err(1, "malloc"); + } + ai++; + } + } } - for (; q != NULL && (char *)q + sizeof(int) < (char *)p + len;) { - version = *(int *)q; - if (version > XPRISON_VERSION) - errx(1, "Sci-Fi prison. Kernel/userland out of sync?"); - switch (version) { -#ifdef SUPPORT_OLD_XPRISON - case 1: - q = print_xprison_v1(q, (char *)p + len, flags); - break; - case 2: - errx(1, "Version 2 was used by multi-IPv4 jail " - "implementations that never made it into the " - "official kernel."); - /* NOTREACHED */ - break; -#endif - case 3: - q = print_xprison_v3(q, (char *)p + len, flags); - break; - default: - errx(1, "Prison unknown. Kernel/userland out of sync?"); - /* NOTREACHED */ - break; + if (pflags & PRINT_VERBOSE) { + printf("%6d %-29.29s %.74s\n" + "%6s %-29.29s %.74s\n" + "%6s %-6d\n", + *(int *)iov[0].value.iov_base, + (char *)iov[1].value.iov_base, + (char *)iov[2].value.iov_base, + "", + (char *)iov[3].value.iov_base, + *(int *)iov[4].value.iov_base ? "DYING" : "ACTIVE", + "", + *(int *)iov[5].value.iov_base); + count = iov[6].value.iov_len / sizeof(struct in_addr); + for (ai = 0; ai < count; ai++) + if (inet_ntop(AF_INET, + &((struct in_addr *)iov[6].value.iov_base)[ai], + ipbuf, sizeof(ipbuf)) == NULL) + err(1, "inet_ntop"); + else + printf("%6s %-15.15s\n", "", ipbuf); + if (!strcmp(params[7].name, "ip6.addr")) { + count = iov[7].value.iov_len / sizeof(struct in6_addr); + for (ai = 0; ai < count; ai++) + if (inet_ntop(AF_INET6, &((struct in_addr *) + iov[7].value.iov_base)[ai], + ipbuf, sizeof(ipbuf)) == NULL) + err(1, "inet_ntop"); + else + printf("%6s %-15.15s\n", "", ipbuf); } + } else if (pflags & PRINT_DEFAULT) + printf("%6d %-15.15s %-29.29s %.74s\n", + *(int *)iov[0].value.iov_base, + iov[1].value.iov_len == 0 ? "-" + : inet_ntoa(*(struct in_addr *)iov[1].value.iov_base), + (char *)iov[2].value.iov_base, + (char *)iov[3].value.iov_base); + else { + for (i = spc = 0; i < nparams; i++) { + if (!(params[i].flags & PARAM_USER)) + continue; + if ((pflags & PRINT_SKIP) && + ((!(params[i].flags & PARAM_WR)) || + (params[i].noparent >= 0 && + *(int *)iov[params[i].noparent].value.iov_base))) + continue; + if (spc) + putchar(' '); + else + spc = 1; + if (pflags & PRINT_NAMEVAL) { + /* + * Generally "name=value", but for booleans + * either "name" or "noname". + */ + switch (params[i].type) { + case CTLTYPE_BOOL: + if (*(int *)iov[i].value.iov_base) + printf("%s", params[i].name); + else { + nname = noname(params[i].name); + printf("%s", nname); + free(nname); + } + break; + case CTLTYPE_NOBOOL: + if (*(int *)iov[i].value.iov_base) + printf("%s", params[i].name); + else { + nname = + nononame(params[i].name); + printf("%s", nname); + free(nname); + } + break; + default: + printf("%s=", params[i].name); + } + } + count = params[i].flags & PARAM_ARRAY + ? iov[i].value.iov_len / params[i].size : 1; + if (count == 0) { + if (pflags & PRINT_QUOTED) + printf("\"\""); + else if (!(pflags & PRINT_NAMEVAL)) + putchar('-'); + } + for (ai = 0; ai < count; ai++) { + if (ai > 0) + putchar(','); + switch (params[i].type) { + case CTLTYPE_INT: + printf("%d", ((int *) + iov[i].value.iov_base)[ai]); + break; + case CTLTYPE_UINT: + printf("%u", ((int *) + iov[i].value.iov_base)[ai]); + break; + case CTLTYPE_IPADDR: + if (inet_ntop(AF_INET, + &((struct in_addr *) + iov[i].value.iov_base)[ai], + ipbuf, sizeof(ipbuf)) == NULL) + err(1, "inet_ntop"); + else + printf("%s", ipbuf); + break; + case CTLTYPE_IP6ADDR: + if (inet_ntop(AF_INET6, + &((struct in6_addr *) + iov[i].value.iov_base)[ai], + ipbuf, sizeof(ipbuf)) == NULL) + err(1, "inet_ntop"); + else + printf("%s", ipbuf); + break; + case CTLTYPE_LONG: + printf("%ld", ((long *) + iov[i].value.iov_base)[ai]); + case CTLTYPE_ULONG: + printf("%lu", ((long *) + iov[i].value.iov_base)[ai]); + break; + case CTLTYPE_STRING: + if (pflags & PRINT_QUOTED) + quoted_print((char *) + iov[i].value.iov_base, + params[i].size); + else + printf("%.*s", + (int)params[i].size, + (char *) + iov[i].value.iov_base); + break; + case CTLTYPE_BOOL: + case CTLTYPE_NOBOOL: + if (!(pflags & PRINT_NAMEVAL)) + printf(((int *) + iov[i].value.iov_base)[ai] + ? "true" : "false"); + } + } + } + putchar('\n'); } + for (i = 0; i < nparams; i++) + if (params[i].value == NULL) + free(iov[i].value.iov_base); + return (jid); +} + +static void +quoted_print(char *str, int len) +{ + int c, qc; + char *p = str; + char *ep = str + len; - free(p); - exit(0); + /* An empty string needs quoting. */ + if (!*p) { + fputs("\"\"", stdout); + return; + } + + /* + * The value will be surrounded by quotes if it contains spaces + * or quotes. + */ + qc = strchr(p, '\'') ? '"' + : strchr(p, '"') ? '\'' + : strchr(p, ' ') || strchr(p, '\t') ? '"' + : 0; + if (qc) + putchar(qc); + while (p < ep && (c = *p++)) { + if (c == '\\' || c == qc) + putchar('\\'); + putchar(c); + } + if (qc) + putchar(qc); } |