int main(int argc, char **argv) { struct jailparam params[MAXPARAMS]; char ifname[IFNAMSIZ]; struct ifreq ifreq; vi_cmd_t newcmd, cmd; int recurse = 0; int verbose = 0; int jid, i, s, namelen; int vst_size, vst_last; vstat_t *vst; char *str; char ch; invocname = argv[0]; newcmd = cmd = VI_SWITCHTO; /* Default if no modifiers specified. */ while ((ch = getopt(argc, argv, "cdijlmrv")) != -1) { switch (ch) { case 'c': newcmd = VI_CREATE; break; case 'm': newcmd = VI_MODIFY; break; case 'd': newcmd = VI_DESTROY; break; case 'l': newcmd = VI_GET; break; case 'i': newcmd = VI_IFMOVE; break; case 'r': recurse = 1; break; case 'v': verbose++; break; case 'j': verbose = 2; break; default: usage(); } if (cmd == VI_SWITCHTO || cmd == newcmd) cmd = newcmd; else usage(); } argc -= optind; argv += optind; if ((cmd != VI_GET && (argc == 0 || recurse != 0 || verbose != 0)) || (cmd == VI_IFMOVE && (argc < 2 || argc > 3)) || (cmd == VI_MODIFY && argc < 2) || argc >= MAXPARAMS) usage(); switch (cmd) { case VI_GET: vst_last = 0; vst_size = VST_SIZE_STEP; if ((vst = malloc(vst_size * sizeof(*vst))) == NULL) break; if (argc == 1) namelen = strlen(argv[0]); else namelen = 0; jid = 0; while ((jid = getjail(&vst[vst_last], jid, verbose)) > 0) { /* Skip jails which do not own vnets. */ if (vst[vst_last].vnet != 1) continue; /* Skip non-matching vnames / hierarchies. */ if (namelen && ((strlen(vst[vst_last].name) < namelen || strncmp(vst[vst_last].name, argv[0], namelen) != 0) || (strlen(vst[vst_last].name) > namelen && vst[vst_last].name[namelen] != '.'))) continue; /* Skip any sub-trees if -r not requested. */ if (!recurse && (strlen(vst[vst_last].name) < namelen || strchr(&vst[vst_last].name[namelen], '.') != NULL)) continue; /* Grow vst table if necessary. */ if (++vst_last == vst_size) { vst_size += VST_SIZE_STEP; vst = realloc(vst, vst_size * sizeof(*vst)); if (vst == NULL) break; } } if (vst == NULL) break; /* Sort: the key is the 1st field in *vst, i.e. vimage name. */ qsort(vst, vst_last, sizeof(*vst), (void *) strcmp); for (i = 0; i < vst_last; i++) { if (!verbose) { printf("%s\n", vst[i].name); continue; } printf("%s:\n", vst[i].name); printf(" Path: %s\n", vst[i].path); printf(" Hostname: %s\n", vst[i].hostname); printf(" Domainname: %s\n", vst[i].domainname); printf(" Children: %d\n", vst[i].childcnt); if (verbose < 2) continue; printf(" Children limit: %d\n", vst[i].childmax); printf(" CPUsetID: %d\n", vst[i].cpuset); printf(" JID: %d\n", vst[i].jid); printf(" PJID: %d\n", vst[i].parentjid); printf(" Raw sockets allowed: %d\n", vst[i].rawsock); printf(" All AF allowed: %d\n", vst[i].socket_af); printf(" Mount allowed: %d\n", vst[i].mount); } free(vst); exit(0); case VI_IFMOVE: if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) break; if ((jid = jail_getid(argv[0])) < 0) break; ifreq.ifr_jid = jid; strncpy(ifreq.ifr_name, argv[1], sizeof(ifreq.ifr_name)); if (ioctl(s, SIOCSIFVNET, (caddr_t)&ifreq) < 0) break; close(s); if (argc == 3) snprintf(ifname, sizeof(ifname), "%s", argv[2]); else snprintf(ifname, sizeof(ifname), "eth0"); ifreq.ifr_data = ifname; /* Do we need to rename the ifnet? */ if (strcmp(ifreq.ifr_name, ifname) != 0) { /* Switch to the context of the target vimage. */ if (jail_attach(jid) < 0) break; if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) break; for (namelen = 0; isalpha(ifname[namelen]); namelen++); i = 0; /* Search for a free ifunit in target vnet. Unsafe. */ while (ioctl(s, SIOCSIFNAME, (caddr_t)&ifreq) < 0) { snprintf(&ifname[namelen], sizeof(ifname) - namelen, "%d", i); /* Emergency brake. */ if (i++ == IF_MAXUNIT) break; } } if (i < IF_MAXUNIT) printf("%s@%s\n", ifname, argv[0]); else printf("%s@%s\n", ifreq.ifr_name, argv[0]); exit(0); case VI_CREATE: if (jail_setv(JAIL_CREATE, "name", argv[0], "vnet", NULL, "host", NULL, "persist", NULL, "allow.raw_sockets", "true", "allow.socket_af", "true", "allow.mount", "true", NULL) < 0) break; if (argc == 1) exit(0); /* Not done yet, proceed to apply non-default parameters. */ case VI_MODIFY: jailparam_init(¶ms[0], "name"); jailparam_import(¶ms[0], argv[0]); for (i = 1; i < argc; i++) { for (str = argv[i]; *str != '=' && *str != 0; str++) { /* Do nothing - search for '=' delimeter. */ } if (*str == 0) break; *str++ = 0; if (*str == 0) break; jailparam_init(¶ms[i], argv[i]); jailparam_import(¶ms[i], str); } if (i != argc) break; if (jailparam_set(params, i, JAIL_UPDATE) < 0) break; exit(0); case VI_DESTROY: if ((jid = jail_getid(argv[0])) < 0) break; if (jail_remove(jid) < 0) break; exit(0); case VI_SWITCHTO: if ((jid = jail_getid(argv[0])) < 0) break; if (jail_attach(jid) < 0) break; if (argc == 1) { printf("Switched to vimage %s\n", argv[0]); if ((str = getenv("SHELL")) == NULL) execlp("/bin/sh", invocname, NULL); else execlp(str, invocname, NULL); } else execvp(argv[1], &argv[1]); break; default: /* Should be unreachable. */ break; } if (jail_errmsg[0]) fprintf(stderr, "Error: %s\n", jail_errmsg); else perror("Error"); exit(1); }
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; #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]); #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]); }