jail.c revision 192896
1191668Sjamie/*- 2191668Sjamie * Copyright (c) 1999 Poul-Henning Kamp. 3192896Sjamie * Copyright (c) 2009 James Gritton 4191668Sjamie * All rights reserved. 5191668Sjamie * 6191668Sjamie * Redistribution and use in source and binary forms, with or without 7191668Sjamie * modification, are permitted provided that the following conditions 8191668Sjamie * are met: 9191668Sjamie * 1. Redistributions of source code must retain the above copyright 10191668Sjamie * notice, this list of conditions and the following disclaimer. 11191668Sjamie * 2. Redistributions in binary form must reproduce the above copyright 12191668Sjamie * notice, this list of conditions and the following disclaimer in the 13191668Sjamie * documentation and/or other materials provided with the distribution. 14191668Sjamie * 15191668Sjamie * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16191668Sjamie * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17191668Sjamie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18191668Sjamie * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19191668Sjamie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20191668Sjamie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21191668Sjamie * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22191668Sjamie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23191668Sjamie * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24191668Sjamie * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25191668Sjamie * SUCH DAMAGE. 2646432Sphk */ 2746432Sphk 28117280Scharnier#include <sys/cdefs.h> 29117280Scharnier__FBSDID("$FreeBSD: head/usr.sbin/jail/jail.c 192896 2009-05-27 14:30:26Z jamie $"); 30117280Scharnier 31112705Smaxim#include <sys/param.h> 3246155Sphk#include <sys/jail.h> 33185435Sbz#include <sys/socket.h> 34158428Smatteo#include <sys/sysctl.h> 35192896Sjamie#include <sys/uio.h> 3678723Sdd 37192896Sjamie#include <arpa/inet.h> 3846155Sphk#include <netinet/in.h> 3946155Sphk 40192896Sjamie#include <ctype.h> 4178723Sdd#include <err.h> 42129848Smaxim#include <errno.h> 43112705Smaxim#include <grp.h> 44112705Smaxim#include <login_cap.h> 45192896Sjamie#include <netdb.h> 46133743Smaxim#include <paths.h> 47112705Smaxim#include <pwd.h> 4878723Sdd#include <stdio.h> 4978723Sdd#include <stdlib.h> 5078723Sdd#include <string.h> 5178723Sdd#include <unistd.h> 5278723Sdd 53192896Sjamie#define SJPARAM "security.jail.param" 54192896Sjamie#define ERRMSG_SIZE 256 55192896Sjamie 56192896Sjamiestruct param { 57192896Sjamie struct iovec name; 58192896Sjamie struct iovec value; 59192896Sjamie}; 60192896Sjamie 61192896Sjamiestatic struct param *params; 62192896Sjamiestatic char **param_values; 63192896Sjamiestatic int nparams; 64192896Sjamie 65192896Sjamiestatic char *ip4_addr; 66185435Sbz#ifdef INET6 67192896Sjamiestatic char *ip6_addr; 68185435Sbz#endif 69185435Sbz 70192896Sjamiestatic void add_ip_addr(char **addrp, char *newaddr); 71185435Sbz#ifdef INET6 72192896Sjamiestatic void add_ip_addr46(char *newaddr); 73185435Sbz#endif 74192896Sjamiestatic void add_ip_addrinfo(int ai_flags, char *value); 75192896Sjamiestatic void quoted_print(FILE *fp, char *str); 76192896Sjamiestatic void set_param(const char *name, char *value); 77192896Sjamiestatic void usage(void); 78185435Sbz 79192896Sjamieextern char **environ; 80192896Sjamie 81129848Smaxim#define GET_USER_INFO do { \ 82129848Smaxim pwd = getpwnam(username); \ 83129848Smaxim if (pwd == NULL) { \ 84129848Smaxim if (errno) \ 85129848Smaxim err(1, "getpwnam: %s", username); \ 86129848Smaxim else \ 87129848Smaxim errx(1, "%s: no such user", username); \ 88129848Smaxim } \ 89129848Smaxim lcap = login_getpwclass(pwd); \ 90129848Smaxim if (lcap == NULL) \ 91129848Smaxim err(1, "getpwclass: %s", username); \ 92129848Smaxim ngroups = NGROUPS; \ 93129848Smaxim if (getgrouplist(username, pwd->pw_gid, groups, &ngroups) != 0) \ 94129848Smaxim err(1, "getgrouplist: %s", username); \ 95129848Smaxim} while (0) 96129848Smaxim 9746155Sphkint 9846155Sphkmain(int argc, char **argv) 9946155Sphk{ 100137808Sdelphij login_cap_t *lcap = NULL; 101192896Sjamie struct iovec rparams[2]; 102137808Sdelphij struct passwd *pwd = NULL; 103136051Sstefanf gid_t groups[NGROUPS]; 104192896Sjamie int ch, cmdarg, i, jail_set_flags, jid, ngroups; 105192896Sjamie int hflag, iflag, Jflag, lflag, rflag, uflag, Uflag; 106192896Sjamie char *ep, *jailname, *securelevel, *username, *JidFile; 107192896Sjamie char errmsg[ERRMSG_SIZE]; 108133743Smaxim static char *cleanenv; 109137807Sdelphij const char *shell, *p = NULL; 110153056Sphilip FILE *fp; 11146155Sphk 112192896Sjamie hflag = iflag = Jflag = lflag = rflag = uflag = Uflag = 113192896Sjamie jail_set_flags = 0; 114192896Sjamie cmdarg = jid = -1; 115192896Sjamie jailname = securelevel = username = JidFile = cleanenv = NULL; 116153056Sphilip fp = NULL; 117112705Smaxim 118192896Sjamie while ((ch = getopt(argc, argv, "cdhilmn:r:s:u:U:J:")) != -1) { 119112705Smaxim switch (ch) { 120192896Sjamie case 'd': 121192896Sjamie jail_set_flags |= JAIL_DYING; 122192896Sjamie break; 123185435Sbz case 'h': 124185435Sbz hflag = 1; 125185435Sbz break; 126113277Smike case 'i': 127113277Smike iflag = 1; 128113277Smike break; 129153056Sphilip case 'J': 130153056Sphilip JidFile = optarg; 131153056Sphilip Jflag = 1; 132153056Sphilip break; 133185435Sbz case 'n': 134185435Sbz jailname = optarg; 135185435Sbz break; 136158428Smatteo case 's': 137192896Sjamie securelevel = optarg; 138158428Smatteo break; 139112705Smaxim case 'u': 140112705Smaxim username = optarg; 141129848Smaxim uflag = 1; 142112705Smaxim break; 143129848Smaxim case 'U': 144129848Smaxim username = optarg; 145129848Smaxim Uflag = 1; 146129848Smaxim break; 147133743Smaxim case 'l': 148133743Smaxim lflag = 1; 149133743Smaxim break; 150192896Sjamie case 'c': 151192896Sjamie jail_set_flags |= JAIL_CREATE; 152192896Sjamie break; 153192896Sjamie case 'm': 154192896Sjamie jail_set_flags |= JAIL_UPDATE; 155192896Sjamie break; 156192896Sjamie case 'r': 157192896Sjamie jid = strtoul(optarg, &ep, 10); 158192896Sjamie if (!*optarg || *ep) { 159192896Sjamie *(const void **)&rparams[0].iov_base = "name"; 160192896Sjamie rparams[0].iov_len = sizeof("name"); 161192896Sjamie rparams[1].iov_base = optarg; 162192896Sjamie rparams[1].iov_len = strlen(optarg) + 1; 163192896Sjamie jid = jail_get(rparams, 2, 0); 164192896Sjamie if (jid < 0) 165192896Sjamie errx(1, "unknown jail: %s", optarg); 166192896Sjamie } 167192896Sjamie rflag = 1; 168192896Sjamie break; 169112705Smaxim default: 170112705Smaxim usage(); 171112705Smaxim } 172113277Smike } 173112705Smaxim argc -= optind; 174112705Smaxim argv += optind; 175192896Sjamie if (rflag) { 176192896Sjamie if (argc > 0 || iflag || Jflag || lflag || uflag || Uflag) 177192896Sjamie usage(); 178192896Sjamie if (jail_remove(jid) < 0) 179192896Sjamie err(1, "jail_remove"); 180192896Sjamie exit (0); 181192896Sjamie } 182192896Sjamie if (argc == 0) 183112705Smaxim usage(); 184129848Smaxim if (uflag && Uflag) 185129848Smaxim usage(); 186133743Smaxim if (lflag && username == NULL) 187133743Smaxim usage(); 188129848Smaxim if (uflag) 189129848Smaxim GET_USER_INFO; 190185435Sbz 191192896Sjamie /* 192192896Sjamie * If the first argument (path) starts with a slash, and the third 193192896Sjamie * argument (IP address) starts with a digit, it is likely to be 194192896Sjamie * an old-style fixed-parameter command line. 195192896Sjamie */ 196192896Sjamie if (jailname) 197192896Sjamie set_param("name", jailname); 198192896Sjamie if (securelevel) 199192896Sjamie set_param("securelevel", securelevel); 200192896Sjamie if (jail_set_flags) { 201192896Sjamie for (i = 0; i < argc; i++) { 202192896Sjamie if (!strncmp(argv[i], "command=", 8)) { 203192896Sjamie cmdarg = i; 204192896Sjamie argv[cmdarg] += 8; 205192896Sjamie jail_set_flags |= JAIL_ATTACH; 206192896Sjamie break; 207192896Sjamie } 208192896Sjamie if (hflag) { 209192896Sjamie if (!strncmp(argv[i], "ip4.addr=", 9)) { 210192896Sjamie add_ip_addr(&ip4_addr, argv[i] + 9); 211192896Sjamie break; 212192896Sjamie } 213192896Sjamie#ifdef INET6 214192896Sjamie if (!strncmp(argv[i], "ip6.addr=", 9)) { 215192896Sjamie add_ip_addr(&ip6_addr, argv[i] + 9); 216192896Sjamie break; 217192896Sjamie } 218192896Sjamie#endif 219192896Sjamie if (!strncmp(argv[i], "host.hostname=", 14)) 220192896Sjamie add_ip_addrinfo(0, argv[i] + 14); 221192896Sjamie } 222192896Sjamie set_param(NULL, argv[i]); 223192896Sjamie } 224192896Sjamie } else { 225192896Sjamie if (argc < 4 || argv[0][0] != '/') 226192896Sjamie errx(1, "%s\n%s", 227192896Sjamie "no -c or -m, so this must be an old-style command.", 228192896Sjamie "But it doesn't look like one."); 229192896Sjamie set_param("path", argv[0]); 230192896Sjamie set_param("host.hostname", argv[1]); 231192896Sjamie if (hflag) 232192896Sjamie add_ip_addrinfo(0, argv[1]); 233192896Sjamie#ifdef INET6 234192896Sjamie add_ip_addr46(argv[2]); 235192896Sjamie#else 236192896Sjamie add_ip_addr(&ip4_addr, argv[2]); 237192896Sjamie#endif 238192896Sjamie cmdarg = 3; 239185435Sbz } 240192896Sjamie if (ip4_addr != NULL) 241192896Sjamie set_param("ip4.addr", ip4_addr); 242185435Sbz#ifdef INET6 243192896Sjamie if (ip6_addr != NULL) 244192896Sjamie set_param("ip6.addr", ip6_addr); 245192896Sjamie#endif 246192896Sjamie errmsg[0] = 0; 247192896Sjamie set_param("errmsg", errmsg); 248185435Sbz 249153056Sphilip if (Jflag) { 250153056Sphilip fp = fopen(JidFile, "w"); 251153056Sphilip if (fp == NULL) 252153056Sphilip errx(1, "Could not create JidFile: %s", JidFile); 253153056Sphilip } 254192896Sjamie jid = jail_set(¶ms->name, 2 * nparams, 255192896Sjamie jail_set_flags ? jail_set_flags : JAIL_CREATE | JAIL_ATTACH); 256192896Sjamie if (jid < 0) { 257192896Sjamie if (errmsg[0] != '\0') 258192896Sjamie errx(1, "%s", errmsg); 259192896Sjamie err(1, "jail_set"); 260192896Sjamie } 261113804Smike if (iflag) { 262192896Sjamie printf("%d\n", jid); 263113804Smike fflush(stdout); 264113804Smike } 265153056Sphilip if (Jflag) { 266192896Sjamie if (jail_set_flags) { 267192896Sjamie fprintf(fp, "jid=%d", jid); 268192896Sjamie for (i = 0; i < nparams; i++) 269192896Sjamie if (strcmp(params[i].name.iov_base, "jid") && 270192896Sjamie strcmp(params[i].name.iov_base, "errmsg")) { 271192896Sjamie fprintf(fp, " %s", 272192896Sjamie (char *)params[i].name.iov_base); 273192896Sjamie if (param_values[i]) { 274192896Sjamie putc('=', fp); 275192896Sjamie quoted_print(fp, 276192896Sjamie param_values[i]); 277192896Sjamie } 278192896Sjamie } 279192896Sjamie fprintf(fp, "\n"); 280192896Sjamie } else { 281192896Sjamie for (i = 0; i < nparams; i++) 282192896Sjamie if (!strcmp(params[i].name.iov_base, "path")) 283192896Sjamie break; 284192896Sjamie#ifdef INET6 285192896Sjamie fprintf(fp, "%d\t%s\t%s\t%s%s%s\t%s\n", 286192896Sjamie jid, i < nparams 287192896Sjamie ? (char *)params[i].value.iov_base : argv[0], 288192896Sjamie argv[1], ip4_addr ? ip4_addr : "", 289192896Sjamie ip4_addr && ip4_addr[0] && ip6_addr && ip6_addr[0] 290192896Sjamie ? "," : "", ip6_addr ? ip6_addr : "", argv[3]); 291192896Sjamie#else 292153056Sphilip fprintf(fp, "%d\t%s\t%s\t%s\t%s\n", 293192896Sjamie jid, i < nparams 294192896Sjamie ? (char *)params[i].value.iov_base : argv[0], 295192896Sjamie argv[1], ip4_addr ? ip4_addr : "", argv[3]); 296192896Sjamie#endif 297153056Sphilip } 298192896Sjamie (void)fclose(fp); 299153056Sphilip } 300192896Sjamie if (cmdarg < 0) 301192896Sjamie exit(0); 302112705Smaxim if (username != NULL) { 303129848Smaxim if (Uflag) 304129848Smaxim GET_USER_INFO; 305133743Smaxim if (lflag) { 306133743Smaxim p = getenv("TERM"); 307133743Smaxim environ = &cleanenv; 308133743Smaxim } 309112972Smaxim if (setgroups(ngroups, groups) != 0) 310112972Smaxim err(1, "setgroups"); 311112972Smaxim if (setgid(pwd->pw_gid) != 0) 312112972Smaxim err(1, "setgid"); 313112972Smaxim if (setusercontext(lcap, pwd, pwd->pw_uid, 314157790Smaxim LOGIN_SETALL & ~LOGIN_SETGROUP & ~LOGIN_SETLOGIN) != 0) 315112972Smaxim err(1, "setusercontext"); 316113206Smaxim login_close(lcap); 317112705Smaxim } 318133743Smaxim if (lflag) { 319133743Smaxim if (*pwd->pw_shell) 320133743Smaxim shell = pwd->pw_shell; 321133743Smaxim else 322133743Smaxim shell = _PATH_BSHELL; 323133743Smaxim if (chdir(pwd->pw_dir) < 0) 324133743Smaxim errx(1, "no home directory"); 325133743Smaxim setenv("HOME", pwd->pw_dir, 1); 326133743Smaxim setenv("SHELL", shell, 1); 327133743Smaxim setenv("USER", pwd->pw_name, 1); 328133743Smaxim if (p) 329133743Smaxim setenv("TERM", p, 1); 330133743Smaxim } 331192896Sjamie execvp(argv[cmdarg], argv + cmdarg); 332192896Sjamie err(1, "execvp: %s", argv[cmdarg]); 33346155Sphk} 334112705Smaxim 335112705Smaximstatic void 336192896Sjamieadd_ip_addr(char **addrp, char *value) 337112705Smaxim{ 338192896Sjamie int addrlen; 339192896Sjamie char *addr; 340112705Smaxim 341192896Sjamie if (!*addrp) { 342192896Sjamie *addrp = strdup(value); 343192896Sjamie if (!*addrp) 344192896Sjamie err(1, "malloc"); 345192896Sjamie } else if (value[0]) { 346192896Sjamie addrlen = strlen(*addrp) + strlen(value) + 2; 347192896Sjamie addr = malloc(addrlen); 348192896Sjamie if (!addr) 349192896Sjamie err(1, "malloc"); 350192896Sjamie snprintf(addr, addrlen, "%s,%s", *addrp, value); 351192896Sjamie free(*addrp); 352192896Sjamie *addrp = addr; 353192896Sjamie } 354112705Smaxim} 355185435Sbz 356192896Sjamie#ifdef INET6 357192896Sjamiestatic void 358192896Sjamieadd_ip_addr46(char *value) 359185435Sbz{ 360192896Sjamie char *p, *np; 361192896Sjamie 362192896Sjamie if (!value[0]) { 363192896Sjamie add_ip_addr(&ip4_addr, value); 364192896Sjamie add_ip_addr(&ip6_addr, value); 365192896Sjamie return; 366192896Sjamie } 367192896Sjamie for (p = value;; p = np + 1) 368192896Sjamie { 369192896Sjamie np = strchr(p, ','); 370192896Sjamie if (np) 371192896Sjamie *np = '\0'; 372192896Sjamie add_ip_addrinfo(AI_NUMERICHOST, p); 373192896Sjamie if (!np) 374192896Sjamie break; 375192896Sjamie } 376192896Sjamie} 377192896Sjamie#endif 378192896Sjamie 379192896Sjamiestatic void 380192896Sjamieadd_ip_addrinfo(int ai_flags, char *value) 381192896Sjamie{ 382192896Sjamie struct addrinfo hints, *ai0, *ai; 383192896Sjamie struct in_addr addr4; 384185435Sbz int error; 385192896Sjamie char avalue4[INET_ADDRSTRLEN]; 386185435Sbz#ifdef INET6 387192896Sjamie struct in6_addr addr6; 388192896Sjamie char avalue6[INET6_ADDRSTRLEN]; 389185435Sbz#endif 390185435Sbz 391192896Sjamie /* Look up the hostname (or get the address) */ 392192896Sjamie memset(&hints, 0, sizeof(hints)); 393192896Sjamie hints.ai_socktype = SOCK_STREAM; 394192896Sjamie#ifdef INET6 395192896Sjamie hints.ai_family = PF_UNSPEC; 396192896Sjamie#else 397192896Sjamie hints.ai_family = PF_INET; 398192896Sjamie#endif 399192896Sjamie hints.ai_flags = ai_flags; 400192896Sjamie error = getaddrinfo(value, NULL, &hints, &ai0); 401192896Sjamie if (error != 0) 402192896Sjamie errx(1, "hostname %s: %s", value, gai_strerror(error)); 403192896Sjamie 404192896Sjamie /* Convert the addresses to ASCII so set_param can convert them back. */ 405192896Sjamie for (ai = ai0; ai; ai = ai->ai_next) 406192896Sjamie switch (ai->ai_family) { 407185435Sbz case AF_INET: 408192896Sjamie memcpy(&addr4, &((struct sockaddr_in *) 409192896Sjamie (void *)ai->ai_addr)->sin_addr, sizeof(addr4)); 410192896Sjamie if (inet_ntop(AF_INET, &addr4, avalue4, 411192896Sjamie INET_ADDRSTRLEN) == NULL) 412192896Sjamie err(1, "inet_ntop"); 413192896Sjamie add_ip_addr(&ip4_addr, avalue4); 414185435Sbz break; 415185435Sbz#ifdef INET6 416185435Sbz case AF_INET6: 417192896Sjamie memcpy(&addr6, &((struct sockaddr_in6 *) 418192896Sjamie (void *)ai->ai_addr)->sin6_addr, sizeof(addr6)); 419192896Sjamie if (inet_ntop(AF_INET6, &addr6, avalue6, 420192896Sjamie INET6_ADDRSTRLEN) == NULL) 421192896Sjamie err(1, "inet_ntop"); 422192896Sjamie add_ip_addr(&ip6_addr, avalue6); 423185435Sbz break; 424185435Sbz#endif 425185435Sbz } 426192896Sjamie freeaddrinfo(ai0); 427185435Sbz} 428185435Sbz 429192896Sjamiestatic void 430192896Sjamiequoted_print(FILE *fp, char *str) 431185435Sbz{ 432192896Sjamie int c, qc; 433192896Sjamie char *p = str; 434185435Sbz 435192896Sjamie /* An empty string needs quoting. */ 436192896Sjamie if (!*p) { 437192896Sjamie fputs("\"\"", fp); 438192896Sjamie return; 439192896Sjamie } 440185435Sbz 441192896Sjamie /* 442192896Sjamie * The value will be surrounded by quotes if it contains spaces 443192896Sjamie * or quotes. 444192896Sjamie */ 445192896Sjamie qc = strchr(p, '\'') ? '"' 446192896Sjamie : strchr(p, '"') ? '\'' 447192896Sjamie : strchr(p, ' ') || strchr(p, '\t') ? '"' 448192896Sjamie : 0; 449192896Sjamie if (qc) 450192896Sjamie putc(qc, fp); 451192896Sjamie while ((c = *p++)) { 452192896Sjamie if (c == '\\' || c == qc) 453192896Sjamie putc('\\', fp); 454192896Sjamie putc(c, fp); 455185435Sbz } 456192896Sjamie if (qc) 457192896Sjamie putc(qc, fp); 458185435Sbz} 459185435Sbz 460192896Sjamiestatic void 461192896Sjamieset_param(const char *name, char *value) 462185435Sbz{ 463192896Sjamie struct param *param; 464192896Sjamie char *ep, *p; 465192896Sjamie size_t buflen, mlen; 466192896Sjamie int i, nval, mib[CTL_MAXNAME]; 467192896Sjamie struct { 468192896Sjamie int i; 469192896Sjamie char s[MAXPATHLEN]; 470192896Sjamie } buf; 471185435Sbz 472192896Sjamie static int paramlistsize; 473185435Sbz 474192896Sjamie /* Separate the name from the value, if not done already. */ 475192896Sjamie if (name == NULL) { 476192896Sjamie name = value; 477192896Sjamie if ((value = strchr(value, '='))) 478192896Sjamie *value++ = '\0'; 479192896Sjamie } 480185435Sbz 481192896Sjamie /* Check for repeat parameters */ 482192896Sjamie for (i = 0; i < nparams; i++) 483192896Sjamie if (!strcmp(name, params[i].name.iov_base)) { 484192896Sjamie memcpy(params + i, params + i + 1, 485192896Sjamie (--nparams - i) * sizeof(struct param)); 486192896Sjamie break; 487192896Sjamie } 488185435Sbz 489192896Sjamie /* Make sure there is room for the new param record. */ 490192896Sjamie if (!nparams) { 491192896Sjamie paramlistsize = 32; 492192896Sjamie params = malloc(paramlistsize * sizeof(*params)); 493192896Sjamie param_values = malloc(paramlistsize * sizeof(*param_values)); 494192896Sjamie if (params == NULL || param_values == NULL) 495192896Sjamie err(1, "malloc"); 496192896Sjamie } else if (nparams >= paramlistsize) { 497192896Sjamie paramlistsize *= 2; 498192896Sjamie params = realloc(params, paramlistsize * sizeof(*params)); 499192896Sjamie param_values = realloc(param_values, 500192896Sjamie paramlistsize * sizeof(*param_values)); 501192896Sjamie if (params == NULL) 502192896Sjamie err(1, "realloc"); 503192896Sjamie } 504185435Sbz 505192896Sjamie /* Look up the paramter. */ 506192896Sjamie param_values[nparams] = value; 507192896Sjamie param = params + nparams++; 508192896Sjamie *(const void **)¶m->name.iov_base = name; 509192896Sjamie param->name.iov_len = strlen(name) + 1; 510192896Sjamie /* Trivial values - no value or errmsg. */ 511192896Sjamie if (value == NULL) { 512192896Sjamie param->value.iov_base = NULL; 513192896Sjamie param->value.iov_len = 0; 514192896Sjamie return; 515185435Sbz } 516192896Sjamie if (!strcmp(name, "errmsg")) { 517192896Sjamie param->value.iov_base = value; 518192896Sjamie param->value.iov_len = ERRMSG_SIZE; 519192896Sjamie return; 520192896Sjamie } 521192896Sjamie mib[0] = 0; 522192896Sjamie mib[1] = 3; 523192896Sjamie snprintf(buf.s, sizeof(buf.s), SJPARAM ".%s", name); 524192896Sjamie mlen = sizeof(mib) - 2 * sizeof(int); 525192896Sjamie if (sysctl(mib, 2, mib + 2, &mlen, buf.s, strlen(buf.s)) < 0) 526192896Sjamie errx(1, "unknown parameter: %s", name); 527192896Sjamie mib[1] = 4; 528192896Sjamie buflen = sizeof(buf); 529192896Sjamie if (sysctl(mib, (mlen / sizeof(int)) + 2, &buf, &buflen, NULL, 0) < 0) 530192896Sjamie err(1, "sysctl(0.4.%s)", name); 531192896Sjamie /* 532192896Sjamie * See if this is an array type. 533192896Sjamie * Treat non-arrays as an array of one. 534192896Sjamie */ 535192896Sjamie p = strchr(buf.s, '\0'); 536192896Sjamie nval = 1; 537192896Sjamie if (p - 2 >= buf.s && !strcmp(p - 2, ",a")) { 538192896Sjamie if (value[0] == '\0' || 539192896Sjamie (value[0] == '-' && value[1] == '\0')) { 540192896Sjamie param->value.iov_base = value; 541192896Sjamie param->value.iov_len = 0; 542192896Sjamie return; 543192896Sjamie } 544192896Sjamie p[-2] = 0; 545192896Sjamie for (p = strchr(value, ','); p; p = strchr(p + 1, ',')) { 546192896Sjamie *p = '\0'; 547192896Sjamie nval++; 548192896Sjamie } 549192896Sjamie } 550192896Sjamie 551192896Sjamie /* Set the values according to the parameter type. */ 552192896Sjamie switch (buf.i & CTLTYPE) { 553192896Sjamie case CTLTYPE_INT: 554192896Sjamie case CTLTYPE_UINT: 555192896Sjamie param->value.iov_len = nval * sizeof(int); 556192896Sjamie break; 557192896Sjamie case CTLTYPE_LONG: 558192896Sjamie case CTLTYPE_ULONG: 559192896Sjamie param->value.iov_len = nval * sizeof(long); 560192896Sjamie break; 561192896Sjamie case CTLTYPE_STRUCT: 562192896Sjamie if (!strcmp(buf.s, "S,in_addr")) 563192896Sjamie param->value.iov_len = nval * sizeof(struct in_addr); 564192896Sjamie#ifdef INET6 565192896Sjamie else if (!strcmp(buf.s, "S,in6_addr")) 566192896Sjamie param->value.iov_len = nval * sizeof(struct in6_addr); 567192896Sjamie#endif 568192896Sjamie else 569192896Sjamie errx(1, "%s: unknown parameter structure (%s)", 570192896Sjamie name, buf.s); 571192896Sjamie break; 572192896Sjamie case CTLTYPE_STRING: 573192896Sjamie if (!strcmp(name, "path")) { 574192896Sjamie param->value.iov_base = malloc(MAXPATHLEN); 575192896Sjamie if (param->value.iov_base == NULL) 576192896Sjamie err(1, "malloc"); 577192896Sjamie if (realpath(value, param->value.iov_base) == NULL) 578192896Sjamie err(1, "%s: realpath(%s)", name, value); 579192896Sjamie if (chdir(param->value.iov_base) != 0) 580192896Sjamie err(1, "chdir: %s", 581192896Sjamie (char *)param->value.iov_base); 582192896Sjamie } else 583192896Sjamie param->value.iov_base = value; 584192896Sjamie param->value.iov_len = strlen(param->value.iov_base) + 1; 585192896Sjamie return; 586192896Sjamie default: 587192896Sjamie errx(1, "%s: unknown parameter type %d (%s)", 588192896Sjamie name, buf.i, buf.s); 589192896Sjamie } 590192896Sjamie param->value.iov_base = malloc(param->value.iov_len); 591192896Sjamie for (i = 0; i < nval; i++) { 592192896Sjamie switch (buf.i & CTLTYPE) { 593192896Sjamie case CTLTYPE_INT: 594192896Sjamie ((int *)param->value.iov_base)[i] = 595192896Sjamie strtol(value, &ep, 10); 596192896Sjamie if (ep[0] != '\0') 597192896Sjamie errx(1, "%s: non-integer value \"%s\"", 598192896Sjamie name, value); 599192896Sjamie break; 600192896Sjamie case CTLTYPE_UINT: 601192896Sjamie ((unsigned *)param->value.iov_base)[i] = 602192896Sjamie strtoul(value, &ep, 10); 603192896Sjamie if (ep[0] != '\0') 604192896Sjamie errx(1, "%s: non-integer value \"%s\"", 605192896Sjamie name, value); 606192896Sjamie break; 607192896Sjamie case CTLTYPE_LONG: 608192896Sjamie ((long *)param->value.iov_base)[i] = 609192896Sjamie strtol(value, &ep, 10); 610192896Sjamie if (ep[0] != '\0') 611192896Sjamie errx(1, "%s: non-integer value \"%s\"", 612192896Sjamie name, value); 613192896Sjamie break; 614192896Sjamie case CTLTYPE_ULONG: 615192896Sjamie ((unsigned long *)param->value.iov_base)[i] = 616192896Sjamie strtoul(value, &ep, 10); 617192896Sjamie if (ep[0] != '\0') 618192896Sjamie errx(1, "%s: non-integer value \"%s\"", 619192896Sjamie name, value); 620192896Sjamie break; 621192896Sjamie case CTLTYPE_STRUCT: 622192896Sjamie if (!strcmp(buf.s, "S,in_addr")) { 623192896Sjamie if (inet_pton(AF_INET, value, 624192896Sjamie &((struct in_addr *) 625192896Sjamie param->value.iov_base)[i]) != 1) 626192896Sjamie errx(1, "%s: not an IPv4 address: %s", 627192896Sjamie name, value); 628192896Sjamie } 629192896Sjamie#ifdef INET6 630192896Sjamie else if (!strcmp(buf.s, "S,in6_addr")) { 631192896Sjamie if (inet_pton(AF_INET6, value, 632192896Sjamie &((struct in6_addr *) 633192896Sjamie param->value.iov_base)[i]) != 1) 634192896Sjamie errx(1, "%s: not an IPv6 address: %s", 635192896Sjamie name, value); 636192896Sjamie } 637192896Sjamie#endif 638192896Sjamie } 639192896Sjamie if (i > 0) 640192896Sjamie value[-1] = ','; 641192896Sjamie value = strchr(value, '\0') + 1; 642192896Sjamie } 643192896Sjamie} 644185435Sbz 645192896Sjamiestatic void 646192896Sjamieusage(void) 647192896Sjamie{ 648192896Sjamie 649192896Sjamie (void)fprintf(stderr, 650192896Sjamie "usage: jail [-d] [-h] [-i] [-J jid_file] " 651192896Sjamie "[-l -u username | -U username]\n" 652192896Sjamie " [-c | -m] param=value ... [command=command ...]\n" 653192896Sjamie " jail [-r jail]\n"); 654192896Sjamie exit(1); 655185435Sbz} 656