diff --git a/usr.sbin/jail/Makefile b/usr.sbin/jail/Makefile index de35dcf248fc..52d237b3339a 100644 --- a/usr.sbin/jail/Makefile +++ b/usr.sbin/jail/Makefile @@ -1,14 +1,17 @@ # $FreeBSD$ .include PROG= jail MAN= jail.8 DPADD= ${LIBJAIL} ${LIBUTIL} LDADD= -ljail -lutil .if ${MK_INET6_SUPPORT} != "no" CFLAGS+= -DINET6 .endif +.if ${MK_INET_SUPPORT} != "no" +CFLAGS+= -DINET +.endif .include diff --git a/usr.sbin/jail/jail.c b/usr.sbin/jail/jail.c index 0722bfd22397..fc4f71c92320 100644 --- a/usr.sbin/jail/jail.c +++ b/usr.sbin/jail/jail.c @@ -1,561 +1,569 @@ /*- * Copyright (c) 1999 Poul-Henning Kamp. * Copyright (c) 2009 James Gritton * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static struct jailparam *params; static char **param_values; static int nparams; -static char *ip4_addr; #ifdef INET6 +static int ip6_ok; static char *ip6_addr; #endif +#ifdef INET +static int ip4_ok; +static char *ip4_addr; +#endif +#if defined(INET6) || defined(INET) static void add_ip_addr(char **addrp, char *newaddr); +#endif #ifdef INET6 static void add_ip_addr46(char *newaddr); #endif static void add_ip_addrinfo(int ai_flags, char *value); static void quoted_print(FILE *fp, char *str); static void set_param(const char *name, char *value); static void usage(void); static const char *perm_sysctl[][3] = { { "security.jail.set_hostname_allowed", "allow.noset_hostname", "allow.set_hostname" }, { "security.jail.sysvipc_allowed", "allow.nosysvipc", "allow.sysvipc" }, { "security.jail.allow_raw_sockets", "allow.noraw_sockets", "allow.raw_sockets" }, { "security.jail.chflags_allowed", "allow.nochflags", "allow.chflags" }, { "security.jail.mount_allowed", "allow.nomount", "allow.mount" }, { "security.jail.socket_unixiproute_only", "allow.socket_af", "allow.nosocket_af" }, }; extern char **environ; #define GET_USER_INFO do { \ pwd = getpwnam(username); \ if (pwd == NULL) { \ if (errno) \ err(1, "getpwnam: %s", username); \ else \ errx(1, "%s: no such user", username); \ } \ lcap = login_getpwclass(pwd); \ if (lcap == NULL) \ err(1, "getpwclass: %s", username); \ ngroups = ngroups_max; \ if (getgrouplist(username, pwd->pw_gid, groups, &ngroups) != 0) \ err(1, "getgrouplist: %s", username); \ } while (0) int main(int argc, char **argv) { login_cap_t *lcap = NULL; struct passwd *pwd = NULL; gid_t *groups; size_t sysvallen; int ch, cmdarg, i, jail_set_flags, jid, ngroups, sysval; int hflag, iflag, Jflag, lflag, rflag, uflag, Uflag; long ngroups_max; unsigned pi; char *jailname, *securelevel, *username, *JidFile; char enforce_statfs[4]; static char *cleanenv; const char *shell, *p = NULL; FILE *fp; hflag = iflag = Jflag = lflag = rflag = uflag = Uflag = jail_set_flags = 0; cmdarg = jid = -1; jailname = securelevel = username = JidFile = cleanenv = NULL; fp = NULL; ngroups_max = sysconf(_SC_NGROUPS_MAX) + 1; if ((groups = malloc(sizeof(gid_t) * ngroups_max)) == NULL) err(1, "malloc"); while ((ch = getopt(argc, argv, "cdhilmn:r:s:u:U:J:")) != -1) { switch (ch) { case 'd': jail_set_flags |= JAIL_DYING; break; case 'h': hflag = 1; break; case 'i': iflag = 1; break; case 'J': JidFile = optarg; Jflag = 1; break; case 'n': jailname = optarg; break; case 's': securelevel = optarg; break; case 'u': username = optarg; uflag = 1; break; case 'U': username = optarg; Uflag = 1; break; case 'l': lflag = 1; break; case 'c': jail_set_flags |= JAIL_CREATE; break; case 'm': jail_set_flags |= JAIL_UPDATE; break; case 'r': jid = jail_getid(optarg); if (jid < 0) errx(1, "%s", jail_errmsg); rflag = 1; break; default: usage(); } } argc -= optind; argv += optind; if (rflag) { if (argc > 0 || iflag || Jflag || lflag || uflag || Uflag) usage(); if (jail_remove(jid) < 0) err(1, "jail_remove"); exit (0); } if (argc == 0) usage(); if (uflag && Uflag) usage(); if (lflag && username == NULL) usage(); if (uflag) GET_USER_INFO; +#ifdef INET6 + ip6_ok = feature_present("inet6"); +#endif +#ifdef INET + ip4_ok = feature_present("inet"); +#endif + if (jailname) set_param("name", jailname); if (securelevel) set_param("securelevel", securelevel); if (jail_set_flags) { for (i = 0; i < argc; i++) { if (!strncmp(argv[i], "command=", 8)) { cmdarg = i; argv[cmdarg] += 8; jail_set_flags |= JAIL_ATTACH; break; } if (hflag) { +#ifdef INET if (!strncmp(argv[i], "ip4.addr=", 9)) { add_ip_addr(&ip4_addr, argv[i] + 9); break; } +#endif #ifdef INET6 if (!strncmp(argv[i], "ip6.addr=", 9)) { add_ip_addr(&ip6_addr, argv[i] + 9); break; } #endif if (!strncmp(argv[i], "host.hostname=", 14)) add_ip_addrinfo(0, argv[i] + 14); } set_param(NULL, argv[i]); } } else { if (argc < 4 || argv[0][0] != '/') errx(1, "%s\n%s", "no -c or -m, so this must be an old-style command.", "But it doesn't look like one."); set_param("path", argv[0]); set_param("host.hostname", argv[1]); if (hflag) add_ip_addrinfo(0, argv[1]); +#if defined(INET6) || defined(INET) if (argv[2][0] != '\0') #ifdef INET6 add_ip_addr46(argv[2]); #else add_ip_addr(&ip4_addr, argv[2]); +#endif #endif cmdarg = 3; /* Emulate the defaults from security.jail.* sysctls */ sysvallen = sizeof(sysval); if (sysctlbyname("security.jail.jailed", &sysval, &sysvallen, NULL, 0) == 0 && sysval == 0) { for (pi = 0; pi < sizeof(perm_sysctl) / sizeof(perm_sysctl[0]); pi++) { sysvallen = sizeof(sysval); if (sysctlbyname(perm_sysctl[pi][0], &sysval, &sysvallen, NULL, 0) == 0) set_param(perm_sysctl[pi] [sysval ? 2 : 1], NULL); } sysvallen = sizeof(sysval); if (sysctlbyname("security.jail.enforce_statfs", &sysval, &sysvallen, NULL, 0) == 0) { snprintf(enforce_statfs, sizeof(enforce_statfs), "%d", sysval); set_param("enforce_statfs", enforce_statfs); } } } +#ifdef INET if (ip4_addr != NULL) set_param("ip4.addr", ip4_addr); +#endif #ifdef INET6 if (ip6_addr != NULL) set_param("ip6.addr", ip6_addr); #endif if (Jflag) { fp = fopen(JidFile, "w"); if (fp == NULL) errx(1, "Could not create JidFile: %s", JidFile); } jid = jailparam_set(params, nparams, jail_set_flags ? jail_set_flags : JAIL_CREATE | JAIL_ATTACH); if (jid < 0) errx(1, "%s", jail_errmsg); if (iflag) { printf("%d\n", jid); fflush(stdout); } if (Jflag) { if (jail_set_flags) { fprintf(fp, "jid=%d", jid); for (i = 0; i < nparams; i++) if (strcmp(params[i].jp_name, "jid")) { fprintf(fp, " %s", (char *)params[i].jp_name); if (param_values[i]) { putc('=', fp); quoted_print(fp, param_values[i]); } } fprintf(fp, "\n"); } else { for (i = 0; i < nparams; i++) if (!strcmp(params[i].jp_name, "path")) break; -#ifdef INET6 +#if defined(INET6) && defined(INET) fprintf(fp, "%d\t%s\t%s\t%s%s%s\t%s\n", jid, i < nparams ? (char *)params[i].jp_value : argv[0], argv[1], ip4_addr ? ip4_addr : "", ip4_addr && ip4_addr[0] && ip6_addr && ip6_addr[0] ? "," : "", ip6_addr ? ip6_addr : "", argv[3]); -#else +#elif defined(INET6) + fprintf(fp, "%d\t%s\t%s\t%s\t%s\n", + jid, i < nparams + ? (char *)params[i].jp_value : argv[0], + argv[1], ip6_addr ? ip6_addr : "", argv[3]); +#elif defined(INET) fprintf(fp, "%d\t%s\t%s\t%s\t%s\n", jid, i < nparams ? (char *)params[i].jp_value : argv[0], argv[1], ip4_addr ? ip4_addr : "", argv[3]); #endif } (void)fclose(fp); } if (cmdarg < 0) exit(0); if (username != NULL) { if (Uflag) GET_USER_INFO; if (lflag) { p = getenv("TERM"); environ = &cleanenv; } if (setgroups(ngroups, groups) != 0) err(1, "setgroups"); if (setgid(pwd->pw_gid) != 0) err(1, "setgid"); if (setusercontext(lcap, pwd, pwd->pw_uid, LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN) != 0) err(1, "setusercontext"); login_close(lcap); } if (lflag) { if (*pwd->pw_shell) shell = pwd->pw_shell; else shell = _PATH_BSHELL; if (chdir(pwd->pw_dir) < 0) errx(1, "no home directory"); setenv("HOME", pwd->pw_dir, 1); setenv("SHELL", shell, 1); setenv("USER", pwd->pw_name, 1); if (p) setenv("TERM", p, 1); } execvp(argv[cmdarg], argv + cmdarg); err(1, "execvp: %s", argv[cmdarg]); } +#if defined(INET6) || defined(INET) static void add_ip_addr(char **addrp, char *value) { int addrlen; char *addr; if (!*addrp) { *addrp = strdup(value); if (!*addrp) err(1, "malloc"); } else if (value[0]) { addrlen = strlen(*addrp) + strlen(value) + 2; addr = malloc(addrlen); if (!addr) err(1, "malloc"); snprintf(addr, addrlen, "%s,%s", *addrp, value); free(*addrp); *addrp = addr; } } +#endif #ifdef INET6 static void add_ip_addr46(char *value) { char *p, *np; for (p = value;; p = np + 1) { np = strchr(p, ','); if (np) *np = '\0'; add_ip_addrinfo(AI_NUMERICHOST, p); if (!np) break; } } #endif static void add_ip_addrinfo(int ai_flags, char *value) { struct addrinfo hints, *ai0, *ai; - struct in_addr addr4; - size_t size; - int error, ip4ok; - int mib[4]; + int error; +#ifdef INET char avalue4[INET_ADDRSTRLEN]; + struct in_addr addr4; +#endif #ifdef INET6 - struct in6_addr addr6; - int ip6ok; char avalue6[INET6_ADDRSTRLEN]; + struct in6_addr addr6; #endif /* Look up the hostname (or get the address) */ memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_STREAM; -#ifdef INET6 +#if defined(INET6) && defined(INET) hints.ai_family = PF_UNSPEC; -#else +#elif defined(INET6) + hints.ai_family = PF_INET6; +#elif defined(INET) hints.ai_family = PF_INET; #endif hints.ai_flags = ai_flags; error = getaddrinfo(value, NULL, &hints, &ai0); if (error != 0) errx(1, "hostname %s: %s", value, gai_strerror(error)); - /* - * Silently ignore unsupported address families from DNS lookups. - * But if this is a numeric address, let the kernel give the error. - */ - if (ai_flags & AI_NUMERICHOST) - ip4ok = -#ifdef INET6 - ip6ok = -#endif - 1; - else { - size = 4; - ip4ok = (sysctlnametomib("security.jail.param.ip4", mib, - &size) == 0); -#ifdef INET6 - size = 4; - ip6ok = (sysctlnametomib("security.jail.param.ip6", mib, - &size) == 0); -#endif - } - /* Convert the addresses to ASCII so set_param can convert them back. */ for (ai = ai0; ai; ai = ai->ai_next) switch (ai->ai_family) { +#ifdef INET case AF_INET: - if (!ip4ok) + if (!ip4_ok && (ai_flags & AI_NUMERICHOST) == 0) break; memcpy(&addr4, &((struct sockaddr_in *) (void *)ai->ai_addr)->sin_addr, sizeof(addr4)); if (inet_ntop(AF_INET, &addr4, avalue4, INET_ADDRSTRLEN) == NULL) err(1, "inet_ntop"); add_ip_addr(&ip4_addr, avalue4); break; +#endif #ifdef INET6 case AF_INET6: - if (!ip6ok) + if (!ip6_ok && (ai_flags & AI_NUMERICHOST) == 0) break; memcpy(&addr6, &((struct sockaddr_in6 *) (void *)ai->ai_addr)->sin6_addr, sizeof(addr6)); if (inet_ntop(AF_INET6, &addr6, avalue6, INET6_ADDRSTRLEN) == NULL) err(1, "inet_ntop"); add_ip_addr(&ip6_addr, avalue6); break; #endif } freeaddrinfo(ai0); } static void quoted_print(FILE *fp, char *str) { int c, qc; char *p = str; /* An empty string needs quoting. */ if (!*p) { fputs("\"\"", fp); 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) putc(qc, fp); while ((c = *p++)) { if (c == '\\' || c == qc) putc('\\', fp); putc(c, fp); } if (qc) putc(qc, fp); } static void set_param(const char *name, char *value) { struct jailparam *param; int i; static int paramlistsize; /* Separate the name from the value, if not done already. */ if (name == NULL) { name = value; if ((value = strchr(value, '='))) *value++ = '\0'; } /* jail_set won't chdir along with its chroot, so do it here. */ if (!strcmp(name, "path") && chdir(value) < 0) err(1, "chdir: %s", value); /* Check for repeat parameters */ for (i = 0; i < nparams; i++) if (!strcmp(name, params[i].jp_name)) { jailparam_free(params + i, 1); memcpy(params + i, params + i + 1, (--nparams - i) * sizeof(struct jailparam)); break; } /* Make sure there is room for the new param record. */ if (!nparams) { paramlistsize = 32; params = malloc(paramlistsize * sizeof(*params)); param_values = malloc(paramlistsize * sizeof(*param_values)); if (params == NULL || param_values == NULL) err(1, "malloc"); } else if (nparams >= paramlistsize) { paramlistsize *= 2; params = realloc(params, paramlistsize * sizeof(*params)); param_values = realloc(param_values, paramlistsize * sizeof(*param_values)); if (params == NULL) err(1, "realloc"); } /* Look up the paramter. */ param_values[nparams] = value; param = params + nparams++; if (jailparam_init(param, name) < 0 || jailparam_import(param, value) < 0) errx(1, "%s", jail_errmsg); } static void usage(void) { (void)fprintf(stderr, "usage: jail [-d] [-h] [-i] [-J jid_file] " "[-l -u username | -U username]\n" " [-c | -m] param=value ... [command=command ...]\n" " jail [-r jail]\n"); exit(1); } diff --git a/usr.sbin/jls/Makefile b/usr.sbin/jls/Makefile index e1157afbca14..b297cc46d653 100644 --- a/usr.sbin/jls/Makefile +++ b/usr.sbin/jls/Makefile @@ -1,8 +1,17 @@ # $FreeBSD$ +.include + PROG= jls MAN= jls.8 DPADD= ${LIBJAIL} LDADD= -ljail +.if ${MK_INET6_SUPPORT} != "no" +CFLAGS+= -DINET6 +.endif +.if ${MK_INET_SUPPORT} != "no" +CFLAGS+= -DINET +.endif + .include diff --git a/usr.sbin/jls/jls.c b/usr.sbin/jls/jls.c index 2c1655b771e8..14aa6af652e6 100644 --- a/usr.sbin/jls/jls.c +++ b/usr.sbin/jls/jls.c @@ -1,462 +1,500 @@ /*- * Copyright (c) 2003 Mike Barcroft * Copyright (c) 2008 Bjoern A. Zeeb * Copyright (c) 2009 James Gritton * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * 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. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define JP_USER 0x01000000 #define JP_OPT 0x02000000 #define PRINT_DEFAULT 0x01 #define PRINT_HEADER 0x02 #define PRINT_NAMEVAL 0x04 #define PRINT_QUOTED 0x08 #define PRINT_SKIP 0x10 #define PRINT_VERBOSE 0x20 static struct jailparam *params; static int *param_parent; static int nparams; +#ifdef INET6 +static int ip6_ok; +#endif +#ifdef INET +static int ip4_ok; +#endif static int add_param(const char *name, void *value, size_t valuelen, struct jailparam *source, unsigned flags); 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 main(int argc, char **argv) { char *dot, *ep, *jname; 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 (!jid || *ep) { jid = 0; jname = optarg; } break; case 'h': pflags = (pflags & ~(PRINT_SKIP | PRINT_VERBOSE)) | 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_HEADER | PRINT_NAMEVAL | PRINT_SKIP)) | PRINT_VERBOSE; break; default: errx(1, "usage: jls [-dhnqv] [-j jail] [param ...]"); } +#ifdef INET6 + ip6_ok = feature_present("inet6"); +#endif +#ifdef INET + ip4_ok = feature_present("inet"); +#endif + /* Add the parameters to print. */ if (optind == argc) { if (pflags & (PRINT_HEADER | PRINT_NAMEVAL)) add_param("all", NULL, (size_t)0, NULL, JP_USER); else if (pflags & PRINT_VERBOSE) { add_param("jid", NULL, (size_t)0, NULL, JP_USER); add_param("host.hostname", NULL, (size_t)0, NULL, JP_USER); add_param("path", NULL, (size_t)0, NULL, JP_USER); add_param("name", NULL, (size_t)0, NULL, JP_USER); add_param("dying", NULL, (size_t)0, NULL, JP_USER); add_param("cpuset.id", NULL, (size_t)0, NULL, JP_USER); - add_param("ip4.addr", NULL, (size_t)0, NULL, JP_USER); - add_param("ip6.addr", NULL, (size_t)0, NULL, - JP_USER | JP_OPT); +#ifdef INET + if (ip4_ok) + add_param("ip4.addr", NULL, (size_t)0, NULL, + JP_USER); +#endif +#ifdef INET6 + if (ip6_ok) + add_param("ip6.addr", NULL, (size_t)0, NULL, + JP_USER | JP_OPT); +#endif } else { pflags |= PRINT_DEFAULT; add_param("jid", NULL, (size_t)0, NULL, JP_USER); - add_param("ip4.addr", NULL, (size_t)0, NULL, JP_USER); +#ifdef INET + if (ip4_ok) + add_param("ip4.addr", NULL, (size_t)0, NULL, + JP_USER); +#endif add_param("host.hostname", NULL, (size_t)0, NULL, JP_USER); add_param("path", NULL, (size_t)0, NULL, JP_USER); } } else while (optind < argc) add_param(argv[optind++], NULL, (size_t)0, NULL, JP_USER); if (pflags & PRINT_SKIP) { /* Check for parameters with jailsys parents. */ for (i = 0; i < nparams; i++) { if ((params[i].jp_flags & JP_USER) && (dot = strchr(params[i].jp_name, '.'))) { *dot = 0; param_parent[i] = add_param(params[i].jp_name, NULL, (size_t)0, NULL, JP_OPT); *dot = '.'; } } } /* Add the index key parameters. */ if (jid != 0) add_param("jid", &jid, sizeof(jid), NULL, 0); else if (jname != NULL) add_param("name", jname, strlen(jname), NULL, 0); else add_param("lastjid", &lastjid, sizeof(lastjid), NULL, 0); /* 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].jp_flags & JP_USER) { if (spc) putchar(' '); else spc = 1; fputs(params[i].jp_name, stdout); } putchar('\n'); } /* Fetch the jail(s) and print the paramters. */ if (jid != 0 || jname != NULL) { if (print_jail(pflags, jflags) < 0) errx(1, "%s", jail_errmsg); } else { for (lastjid = 0; (lastjid = print_jail(pflags, jflags)) >= 0; ) ; if (errno != 0 && errno != ENOENT) errx(1, "%s", jail_errmsg); } return (0); } static int add_param(const char *name, void *value, size_t valuelen, struct jailparam *source, unsigned flags) { struct jailparam *param, *tparams; int i, tnparams; static int paramlistsize; /* The pseudo-parameter "all" scans the list of available parameters. */ if (!strcmp(name, "all")) { tnparams = jailparam_all(&tparams); if (tnparams < 0) errx(1, "%s", jail_errmsg); qsort(tparams, (size_t)tnparams, sizeof(struct jailparam), sort_param); for (i = 0; i < tnparams; i++) add_param(tparams[i].jp_name, NULL, (size_t)0, tparams + i, flags); free(tparams); return -1; } /* Check for repeat parameters. */ for (i = 0; i < nparams; i++) if (!strcmp(name, params[i].jp_name)) { if (value != NULL && jailparam_import_raw(params + i, value, valuelen) < 0) errx(1, "%s", jail_errmsg); params[i].jp_flags |= flags; if (source != NULL) jailparam_free(source, 1); return i; } /* Make sure there is room for the new param record. */ if (!nparams) { paramlistsize = 32; params = malloc(paramlistsize * sizeof(*params)); param_parent = malloc(paramlistsize * sizeof(*param_parent)); if (params == NULL || param_parent == NULL) err(1, "malloc"); } else if (nparams >= paramlistsize) { paramlistsize *= 2; params = realloc(params, paramlistsize * sizeof(*params)); param_parent = realloc(param_parent, paramlistsize * sizeof(*param_parent)); if (params == NULL || param_parent == NULL) err(1, "realloc"); } /* Look up the parameter. */ param_parent[nparams] = -1; param = params + nparams++; if (source != NULL) { *param = *source; param->jp_flags |= flags; return param - params; } if (jailparam_init(param, name) < 0) errx(1, "%s", jail_errmsg); param->jp_flags = flags; if ((value != NULL ? jailparam_import_raw(param, value, valuelen) : jailparam_import(param, value)) < 0) { if (flags & JP_OPT) { nparams--; return (-1); } errx(1, "%s", jail_errmsg); } return param - params; } static int sort_param(const void *a, const void *b) { const struct jailparam *parama, *paramb; char *ap, *bp; /* Put top-level parameters first. */ parama = a; paramb = b; ap = strchr(parama->jp_name, '.'); bp = strchr(paramb->jp_name, '.'); if (ap && !bp) return (1); if (bp && !ap) return (-1); return (strcmp(parama->jp_name, paramb->jp_name)); } static char * noname(const char *name) { char *nname, *p; 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; } static char * nononame(const char *name) { char *nname, *p; 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; char **param_values; - int i, ai, jid, count, spc; + int i, ai, jid, count, n, spc; char ipbuf[INET6_ADDRSTRLEN]; jid = jailparam_get(params, nparams, jflags); if (jid < 0) return jid; if (pflags & PRINT_VERBOSE) { printf("%6d %-29.29s %.74s\n" "%6s %-29.29s %.74s\n" "%6s %-6d\n", *(int *)params[0].jp_value, (char *)params[1].jp_value, (char *)params[2].jp_value, "", (char *)params[3].jp_value, *(int *)params[4].jp_value ? "DYING" : "ACTIVE", "", *(int *)params[5].jp_value); - count = params[6].jp_valuelen / sizeof(struct in_addr); - for (ai = 0; ai < count; ai++) - if (inet_ntop(AF_INET, - &((struct in_addr *)params[6].jp_value)[ai], - ipbuf, sizeof(ipbuf)) == NULL) - err(1, "inet_ntop"); - else - printf("%6s %-15.15s\n", "", ipbuf); - if (!strcmp(params[7].jp_name, "ip6.addr")) { - count = params[7].jp_valuelen / sizeof(struct in6_addr); + n = 6; +#ifdef INET + if (ip4_ok && !strcmp(params[n].jp_name, "ip.addr")) { + count = params[n].jp_valuelen / sizeof(struct in_addr); + for (ai = 0; ai < count; ai++) + if (inet_ntop(AF_INET, + &((struct in_addr *)params[n].jp_value)[ai], + ipbuf, sizeof(ipbuf)) == NULL) + err(1, "inet_ntop"); + else + printf("%6s %-15.15s\n", "", ipbuf); + n++; + } +#endif +#ifdef INET6 + if (ip6_ok && !strcmp(params[n].jp_name, "ip6.addr")) { + count = params[n].jp_valuelen / sizeof(struct in6_addr); for (ai = 0; ai < count; ai++) if (inet_ntop(AF_INET6, - &((struct in6_addr *)params[7].jp_value)[ai], + &((struct in6_addr *) + params[n].jp_value)[ai], ipbuf, sizeof(ipbuf)) == NULL) err(1, "inet_ntop"); else printf("%6s %s\n", "", ipbuf); + n++; } +#endif } else if (pflags & PRINT_DEFAULT) printf("%6d %-15.15s %-29.29s %.74s\n", *(int *)params[0].jp_value, - params[1].jp_valuelen == 0 ? "-" +#ifdef INET + (!ip4_ok || params[1].jp_valuelen == 0) ? "-" : inet_ntoa(*(struct in_addr *)params[1].jp_value), - (char *)params[2].jp_value, - (char *)params[3].jp_value); +#else + "-" +#endif + (char *)params[2-!ip4_ok].jp_value, + (char *)params[3-!ip4_ok].jp_value); else { param_values = alloca(nparams * sizeof(*param_values)); for (i = 0; i < nparams; i++) { if (!(params[i].jp_flags & JP_USER)) continue; param_values[i] = jailparam_export(params + i); if (param_values[i] == NULL) errx(1, "%s", jail_errmsg); } for (i = spc = 0; i < nparams; i++) { if (!(params[i].jp_flags & JP_USER)) continue; if ((pflags & PRINT_SKIP) && ((!(params[i].jp_ctltype & (CTLFLAG_WR | CTLFLAG_TUN))) || (param_parent[i] >= 0 && *(int *)params[param_parent[i]].jp_value != JAIL_SYS_NEW))) continue; if (spc) putchar(' '); else spc = 1; if (pflags & PRINT_NAMEVAL) { /* * Generally "name=value", but for booleans * either "name" or "noname". */ if (params[i].jp_flags & (JP_BOOL | JP_NOBOOL)) { if (*(int *)params[i].jp_value) printf("%s", params[i].jp_name); else { nname = (params[i].jp_flags & JP_NOBOOL) ? nononame(params[i].jp_name) : noname(params[i].jp_name); printf("%s", nname); free(nname); } continue; } printf("%s=", params[i].jp_name); } if (params[i].jp_valuelen == 0) { if (pflags & PRINT_QUOTED) printf("\"\""); else if (!(pflags & PRINT_NAMEVAL)) putchar('-'); } else quoted_print(param_values[i]); } putchar('\n'); for (i = 0; i < nparams; i++) if (params[i].jp_flags & JP_USER) free(param_values[i]); } return (jid); } static void quoted_print(char *str) { int c, qc; char *p = str; /* 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 ((c = *p++)) { if (c == '\\' || c == qc) putchar('\\'); putchar(c); } if (qc) putchar(qc); }