1191668Sjamie/*- 2191668Sjamie * Copyright (c) 1999 Poul-Henning Kamp. 3234712Sjamie * Copyright (c) 2009-2012 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: releng/10.3/usr.sbin/jail/jail.c 278484 2015-02-10 01:05:51Z jamie $"); 30117280Scharnier 31234712Sjamie#include <sys/types.h> 32234712Sjamie#include <sys/stat.h> 33185435Sbz#include <sys/socket.h> 34158428Smatteo#include <sys/sysctl.h> 3578723Sdd 36192896Sjamie#include <arpa/inet.h> 3746155Sphk#include <netinet/in.h> 3846155Sphk 3978723Sdd#include <err.h> 40129848Smaxim#include <errno.h> 41234712Sjamie#include <stdarg.h> 4278723Sdd#include <stdio.h> 4378723Sdd#include <stdlib.h> 4478723Sdd#include <string.h> 4578723Sdd#include <unistd.h> 4678723Sdd 47234712Sjamie#include "jailp.h" 48192896Sjamie 49234712Sjamie#define JP_RDTUN(jp) (((jp)->jp_ctltype & CTLFLAG_RDTUN) == CTLFLAG_RDTUN) 50185435Sbz 51234712Sjamiestruct permspec { 52234712Sjamie const char *name; 53234712Sjamie enum intparam ipnum; 54234712Sjamie int rev; 55234712Sjamie}; 56234712Sjamie 57234712Sjamieconst char *cfname; 58236198Sjamieint iflag; 59234712Sjamieint note_remove; 60234712Sjamieint verbose; 61234712Sjamie 62234712Sjamiestatic void clear_persist(struct cfjail *j); 63234712Sjamiestatic int update_jail(struct cfjail *j); 64234712Sjamiestatic int rdtun_params(struct cfjail *j, int dofail); 65234712Sjamiestatic void running_jid(struct cfjail *j, int dflag); 66234712Sjamiestatic void jail_quoted_warnx(const struct cfjail *j, const char *name_msg, 67234712Sjamie const char *noname_msg); 68234712Sjamiestatic int jailparam_set_note(const struct cfjail *j, struct jailparam *jp, 69234712Sjamie unsigned njp, int flags); 70234712Sjamiestatic void print_jail(FILE *fp, struct cfjail *j, int oldcl); 71234712Sjamiestatic void print_param(FILE *fp, const struct cfparam *p, int sep, int doname); 72192896Sjamiestatic void quoted_print(FILE *fp, char *str); 73192896Sjamiestatic void usage(void); 74185435Sbz 75234712Sjamiestatic struct permspec perm_sysctl[] = { 76234712Sjamie { "security.jail.set_hostname_allowed", KP_ALLOW_SET_HOSTNAME, 0 }, 77234712Sjamie { "security.jail.sysvipc_allowed", KP_ALLOW_SYSVIPC, 0 }, 78234712Sjamie { "security.jail.allow_raw_sockets", KP_ALLOW_RAW_SOCKETS, 0 }, 79234712Sjamie { "security.jail.chflags_allowed", KP_ALLOW_CHFLAGS, 0 }, 80234712Sjamie { "security.jail.mount_allowed", KP_ALLOW_MOUNT, 0 }, 81234712Sjamie { "security.jail.socket_unixiproute_only", KP_ALLOW_SOCKET_AF, 1 }, 82193929Sjamie}; 83193929Sjamie 84234712Sjamiestatic const enum intparam startcommands[] = { 85234988Sjamie IP__NULL, 86234712Sjamie#ifdef INET 87234712Sjamie IP__IP4_IFADDR, 88234712Sjamie#endif 89234712Sjamie#ifdef INET6 90234712Sjamie IP__IP6_IFADDR, 91234712Sjamie#endif 92234712Sjamie IP_MOUNT, 93234712Sjamie IP__MOUNT_FROM_FSTAB, 94234712Sjamie IP_MOUNT_DEVFS, 95256387Shrs IP_MOUNT_FDESCFS, 96278484Sjamie IP_MOUNT_PROCFS, 97234712Sjamie IP_EXEC_PRESTART, 98234712Sjamie IP__OP, 99234712Sjamie IP_VNET_INTERFACE, 100234712Sjamie IP_EXEC_START, 101234712Sjamie IP_COMMAND, 102234712Sjamie IP_EXEC_POSTSTART, 103234988Sjamie IP__NULL 104234712Sjamie}; 105192896Sjamie 106234712Sjamiestatic const enum intparam stopcommands[] = { 107234988Sjamie IP__NULL, 108234712Sjamie IP_EXEC_PRESTOP, 109234712Sjamie IP_EXEC_STOP, 110234712Sjamie IP_STOP_TIMEOUT, 111234712Sjamie IP__OP, 112234712Sjamie IP_EXEC_POSTSTOP, 113278484Sjamie IP_MOUNT_PROCFS, 114256387Shrs IP_MOUNT_FDESCFS, 115234712Sjamie IP_MOUNT_DEVFS, 116234712Sjamie IP__MOUNT_FROM_FSTAB, 117234712Sjamie IP_MOUNT, 118234712Sjamie#ifdef INET6 119234712Sjamie IP__IP6_IFADDR, 120234712Sjamie#endif 121234712Sjamie#ifdef INET 122234712Sjamie IP__IP4_IFADDR, 123234712Sjamie#endif 124234988Sjamie IP__NULL 125234712Sjamie}; 126129848Smaxim 12746155Sphkint 12846155Sphkmain(int argc, char **argv) 12946155Sphk{ 130234712Sjamie struct stat st; 131234712Sjamie FILE *jfp; 132234712Sjamie struct cfjail *j; 133234712Sjamie char *JidFile; 134193929Sjamie size_t sysvallen; 135234712Sjamie unsigned op, pi; 136234712Sjamie int ch, docf, error, i, oldcl, sysval; 137236198Sjamie int dflag, Rflag; 138194869Sjamie char enforce_statfs[4]; 139234712Sjamie#if defined(INET) || defined(INET6) 140234712Sjamie char *cs, *ncs; 141234712Sjamie#endif 142234712Sjamie#if defined(INET) && defined(INET6) 143234712Sjamie struct in6_addr addr6; 144234712Sjamie#endif 14546155Sphk 146234712Sjamie op = 0; 147236198Sjamie dflag = Rflag = 0; 148234712Sjamie docf = 1; 149234712Sjamie cfname = CONF_FILE; 150234712Sjamie JidFile = NULL; 151112705Smaxim 152237697Smaxim while ((ch = getopt(argc, argv, "cdf:hiJ:lmn:p:qrRs:u:U:v")) != -1) { 153112705Smaxim switch (ch) { 154234712Sjamie case 'c': 155234712Sjamie op |= JF_START; 156234712Sjamie break; 157192896Sjamie case 'd': 158234712Sjamie dflag = 1; 159192896Sjamie break; 160234712Sjamie case 'f': 161234712Sjamie cfname = optarg; 162234712Sjamie break; 163185435Sbz case 'h': 164234712Sjamie#if defined(INET) || defined(INET6) 165234712Sjamie add_param(NULL, NULL, IP_IP_HOSTNAME, NULL); 166234712Sjamie#endif 167234712Sjamie docf = 0; 168185435Sbz break; 169113277Smike case 'i': 170113277Smike iflag = 1; 171234712Sjamie verbose = -1; 172113277Smike break; 173153056Sphilip case 'J': 174153056Sphilip JidFile = optarg; 175153056Sphilip break; 176234712Sjamie case 'l': 177234712Sjamie add_param(NULL, NULL, IP_EXEC_CLEAN, NULL); 178234712Sjamie docf = 0; 179234712Sjamie break; 180234712Sjamie case 'm': 181234712Sjamie op |= JF_SET; 182234712Sjamie break; 183185435Sbz case 'n': 184234712Sjamie add_param(NULL, NULL, KP_NAME, optarg); 185234712Sjamie docf = 0; 186185435Sbz break; 187234712Sjamie case 'p': 188234712Sjamie paralimit = strtol(optarg, NULL, 10); 189234712Sjamie if (paralimit == 0) 190234712Sjamie paralimit = -1; 191234712Sjamie break; 192234712Sjamie case 'q': 193234712Sjamie verbose = -1; 194234712Sjamie break; 195234712Sjamie case 'r': 196234712Sjamie op |= JF_STOP; 197234712Sjamie break; 198234712Sjamie case 'R': 199234712Sjamie op |= JF_STOP; 200234712Sjamie Rflag = 1; 201234712Sjamie break; 202158428Smatteo case 's': 203234712Sjamie add_param(NULL, NULL, KP_SECURELEVEL, optarg); 204234712Sjamie docf = 0; 205158428Smatteo break; 206112705Smaxim case 'u': 207234712Sjamie add_param(NULL, NULL, IP_EXEC_JAIL_USER, optarg); 208234712Sjamie add_param(NULL, NULL, IP_EXEC_SYSTEM_JAIL_USER, NULL); 209234712Sjamie docf = 0; 210112705Smaxim break; 211129848Smaxim case 'U': 212234712Sjamie add_param(NULL, NULL, IP_EXEC_JAIL_USER, optarg); 213234712Sjamie add_param(NULL, NULL, IP_EXEC_SYSTEM_JAIL_USER, 214234712Sjamie "false"); 215234712Sjamie docf = 0; 216129848Smaxim break; 217234712Sjamie case 'v': 218234712Sjamie verbose = 1; 219133743Smaxim break; 220112705Smaxim default: 221112705Smaxim usage(); 222112705Smaxim } 223113277Smike } 224112705Smaxim argc -= optind; 225112705Smaxim argv += optind; 226234712Sjamie 227234712Sjamie /* Find out which of the four command line styles this is. */ 228234712Sjamie oldcl = 0; 229234712Sjamie if (!op) { 230234712Sjamie /* Old-style command line with four fixed parameters */ 231234712Sjamie if (argc < 4 || argv[0][0] != '/') 232192896Sjamie usage(); 233234712Sjamie op = JF_START; 234234712Sjamie docf = 0; 235234712Sjamie oldcl = 1; 236234712Sjamie add_param(NULL, NULL, KP_PATH, argv[0]); 237234712Sjamie add_param(NULL, NULL, KP_HOST_HOSTNAME, argv[1]); 238234712Sjamie#if defined(INET) || defined(INET6) 239234712Sjamie if (argv[2][0] != '\0') { 240234712Sjamie for (cs = argv[2];; cs = ncs + 1) { 241234712Sjamie ncs = strchr(cs, ','); 242234712Sjamie if (ncs) 243234712Sjamie *ncs = '\0'; 244234712Sjamie add_param(NULL, NULL, 245234712Sjamie#if defined(INET) && defined(INET6) 246234712Sjamie inet_pton(AF_INET6, cs, &addr6) == 1 247234712Sjamie ? KP_IP6_ADDR : KP_IP4_ADDR, 248234712Sjamie#elif defined(INET) 249234712Sjamie KP_IP4_ADDR, 250234712Sjamie#elif defined(INET6) 251234712Sjamie KP_IP6_ADDR, 252222465Sbz#endif 253234712Sjamie cs); 254234712Sjamie if (!ncs) 255192896Sjamie break; 256192896Sjamie } 257192896Sjamie } 258192896Sjamie#endif 259234712Sjamie for (i = 3; i < argc; i++) 260234712Sjamie add_param(NULL, NULL, IP_COMMAND, argv[i]); 261234712Sjamie /* Emulate the defaults from security.jail.* sysctls. */ 262193929Sjamie sysvallen = sizeof(sysval); 263193929Sjamie if (sysctlbyname("security.jail.jailed", &sysval, &sysvallen, 264193929Sjamie NULL, 0) == 0 && sysval == 0) { 265193929Sjamie for (pi = 0; pi < sizeof(perm_sysctl) / 266193929Sjamie sizeof(perm_sysctl[0]); pi++) { 267193929Sjamie sysvallen = sizeof(sysval); 268234712Sjamie if (sysctlbyname(perm_sysctl[pi].name, 269193929Sjamie &sysval, &sysvallen, NULL, 0) == 0) 270234712Sjamie add_param(NULL, NULL, 271234712Sjamie perm_sysctl[pi].ipnum, 272234712Sjamie (sysval ? 1 : 0) ^ 273234712Sjamie perm_sysctl[pi].rev 274234712Sjamie ? NULL : "false"); 275193929Sjamie } 276193929Sjamie sysvallen = sizeof(sysval); 277193929Sjamie if (sysctlbyname("security.jail.enforce_statfs", 278193929Sjamie &sysval, &sysvallen, NULL, 0) == 0) { 279193929Sjamie snprintf(enforce_statfs, 280193929Sjamie sizeof(enforce_statfs), "%d", sysval); 281234712Sjamie add_param(NULL, NULL, KP_ENFORCE_STATFS, 282234712Sjamie enforce_statfs); 283193929Sjamie } 284193929Sjamie } 285234712Sjamie } else if (op == JF_STOP) { 286234712Sjamie /* Jail remove, perhaps using the config file */ 287234712Sjamie if (!docf || argc == 0) 288234712Sjamie usage(); 289234712Sjamie if (!Rflag) 290234712Sjamie for (i = 0; i < argc; i++) 291234712Sjamie if (strchr(argv[i], '=')) 292234712Sjamie usage(); 293234712Sjamie if ((docf = !Rflag && 294234712Sjamie (!strcmp(cfname, "-") || stat(cfname, &st) == 0))) 295234712Sjamie load_config(); 296234712Sjamie note_remove = docf || argc > 1 || wild_jail_name(argv[0]); 297234712Sjamie } else if (argc > 1 || (argc == 1 && strchr(argv[0], '='))) { 298234712Sjamie /* Single jail specified on the command line */ 299234712Sjamie if (Rflag) 300234712Sjamie usage(); 301234712Sjamie docf = 0; 302234712Sjamie for (i = 0; i < argc; i++) { 303234712Sjamie if (!strncmp(argv[i], "command", 7) && 304234712Sjamie (argv[i][7] == '\0' || argv[i][7] == '=')) { 305234712Sjamie if (argv[i][7] == '=') 306234712Sjamie add_param(NULL, NULL, IP_COMMAND, 307234712Sjamie argv[i] + 8); 308234712Sjamie for (i++; i < argc; i++) 309234712Sjamie add_param(NULL, NULL, IP_COMMAND, 310234712Sjamie argv[i]); 311234712Sjamie } 312239602Sjamie#ifdef INET 313239602Sjamie else if (!strncmp(argv[i], "ip4.addr=", 9)) { 314239602Sjamie for (cs = argv[i] + 9;; cs = ncs + 1) { 315239602Sjamie ncs = strchr(cs, ','); 316239602Sjamie if (ncs) 317239602Sjamie *ncs = '\0'; 318239602Sjamie add_param(NULL, NULL, KP_IP4_ADDR, cs); 319239602Sjamie if (!ncs) 320239602Sjamie break; 321239602Sjamie } 322239602Sjamie } 323239602Sjamie#endif 324239602Sjamie#ifdef INET6 325239602Sjamie else if (!strncmp(argv[i], "ip6.addr=", 9)) { 326239602Sjamie for (cs = argv[i] + 9;; cs = ncs + 1) { 327239602Sjamie ncs = strchr(cs, ','); 328239602Sjamie if (ncs) 329239602Sjamie *ncs = '\0'; 330239602Sjamie add_param(NULL, NULL, KP_IP6_ADDR, cs); 331239602Sjamie if (!ncs) 332239602Sjamie break; 333239602Sjamie } 334239602Sjamie } 335239602Sjamie#endif 336239602Sjamie else 337239602Sjamie add_param(NULL, NULL, 0, argv[i]); 338234712Sjamie } 339234712Sjamie } else { 340234712Sjamie /* From the config file, perhaps with a specified jail */ 341234712Sjamie if (Rflag || !docf) 342234712Sjamie usage(); 343234712Sjamie load_config(); 344185435Sbz } 345185435Sbz 346234712Sjamie /* Find out which jails will be run. */ 347234712Sjamie dep_setup(docf); 348234712Sjamie error = 0; 349234712Sjamie if (op == JF_STOP) { 350234712Sjamie for (i = 0; i < argc; i++) 351234712Sjamie if (start_state(argv[i], docf, op, Rflag) < 0) 352234712Sjamie error = 1; 353234712Sjamie } else { 354234712Sjamie if (start_state(argv[0], docf, op, 0) < 0) 355234712Sjamie exit(1); 356153056Sphilip } 357234712Sjamie 358234712Sjamie jfp = NULL; 359234712Sjamie if (JidFile != NULL) { 360234712Sjamie jfp = fopen(JidFile, "w"); 361234712Sjamie if (jfp == NULL) 362234712Sjamie err(1, "open %s", JidFile); 363234712Sjamie setlinebuf(jfp); 364113804Smike } 365234712Sjamie setlinebuf(stdout); 366234712Sjamie 367234712Sjamie /* 368234712Sjamie * The main loop: Get an available jail and perform the required 369234712Sjamie * operation on it. When that is done, the jail may be finished, 370234712Sjamie * or it may go back for the next step. 371234712Sjamie */ 372234712Sjamie while ((j = next_jail())) 373234712Sjamie { 374234712Sjamie if (j->flags & JF_FAILED) { 375234712Sjamie error = 1; 376234712Sjamie if (j->comparam == NULL) { 377234712Sjamie dep_done(j, 0); 378234712Sjamie continue; 379234712Sjamie } 380234712Sjamie } 381234712Sjamie if (!(j->flags & JF_PARAMS)) 382234712Sjamie { 383234712Sjamie j->flags |= JF_PARAMS; 384234712Sjamie if (dflag) 385234712Sjamie add_param(j, NULL, IP_ALLOW_DYING, NULL); 386234712Sjamie if (check_intparams(j) < 0) 387234712Sjamie continue; 388234712Sjamie if ((j->flags & (JF_START | JF_SET)) && 389234712Sjamie import_params(j) < 0) 390234712Sjamie continue; 391234712Sjamie } 392234712Sjamie if (!j->jid) 393234712Sjamie running_jid(j, 394234712Sjamie (j->flags & (JF_SET | JF_DEPEND)) == JF_SET 395234712Sjamie ? dflag || bool_param(j->intparams[IP_ALLOW_DYING]) 396234712Sjamie : 0); 397234712Sjamie if (finish_command(j)) 398234712Sjamie continue; 399234712Sjamie 400234712Sjamie switch (j->flags & JF_OP_MASK) { 401234712Sjamie /* 402234712Sjamie * These operations just turn into a different op 403234712Sjamie * depending on the jail's current status. 404234712Sjamie */ 405234712Sjamie case JF_START_SET: 406234712Sjamie j->flags = j->jid < 0 ? JF_START : JF_SET; 407234712Sjamie break; 408234712Sjamie case JF_SET_RESTART: 409234712Sjamie if (j->jid < 0) { 410234712Sjamie jail_quoted_warnx(j, "not found", 411234712Sjamie "no jail specified"); 412234712Sjamie failed(j); 413234712Sjamie continue; 414234712Sjamie } 415234712Sjamie j->flags = rdtun_params(j, 0) ? JF_RESTART : JF_SET; 416234712Sjamie if (j->flags == JF_RESTART) 417234712Sjamie dep_reset(j); 418234712Sjamie break; 419234712Sjamie case JF_START_SET_RESTART: 420234712Sjamie j->flags = j->jid < 0 ? JF_START 421234712Sjamie : rdtun_params(j, 0) ? JF_RESTART : JF_SET; 422234712Sjamie if (j->flags == JF_RESTART) 423234712Sjamie dep_reset(j); 424234712Sjamie } 425234712Sjamie 426234712Sjamie switch (j->flags & JF_OP_MASK) { 427234712Sjamie case JF_START: 428234712Sjamie if (j->comparam == NULL) { 429234712Sjamie if (j->jid > 0 && 430234712Sjamie !(j->flags & (JF_DEPEND | JF_WILD))) { 431234712Sjamie jail_quoted_warnx(j, "already exists", 432234712Sjamie NULL); 433234712Sjamie failed(j); 434234712Sjamie continue; 435192896Sjamie } 436234712Sjamie if (dep_check(j)) 437234712Sjamie continue; 438234712Sjamie if (j->jid > 0) 439234712Sjamie goto jail_create_done; 440234712Sjamie j->comparam = startcommands; 441234712Sjamie j->comstring = NULL; 442234712Sjamie } 443234712Sjamie if (next_command(j)) 444234712Sjamie continue; 445234712Sjamie jail_create_done: 446234712Sjamie clear_persist(j); 447234712Sjamie if (jfp != NULL) 448234712Sjamie print_jail(jfp, j, oldcl); 449234712Sjamie dep_done(j, 0); 450234712Sjamie break; 451234712Sjamie 452234712Sjamie case JF_SET: 453234712Sjamie if (j->jid < 0 && !(j->flags & JF_DEPEND)) { 454234712Sjamie jail_quoted_warnx(j, "not found", 455234712Sjamie "no jail specified"); 456234712Sjamie failed(j); 457234712Sjamie continue; 458234712Sjamie } 459234712Sjamie if (dep_check(j)) 460234712Sjamie continue; 461234712Sjamie if (!(j->flags & JF_DEPEND)) { 462234712Sjamie if (rdtun_params(j, 1) < 0 || 463234712Sjamie update_jail(j) < 0) 464234712Sjamie continue; 465234712Sjamie if (verbose >= 0 && (j->name || verbose > 0)) 466234712Sjamie jail_note(j, "updated\n"); 467234712Sjamie } 468234712Sjamie dep_done(j, 0); 469234712Sjamie break; 470234712Sjamie 471234712Sjamie case JF_STOP: 472234712Sjamie case JF_RESTART: 473234712Sjamie if (j->comparam == NULL) { 474234712Sjamie if (dep_check(j)) 475234712Sjamie continue; 476234712Sjamie if (j->jid < 0) { 477256256Shrs if (!(j->flags & (JF_DEPEND|JF_WILD))) { 478256256Shrs if (verbose >= 0) 479256256Shrs jail_quoted_warnx(j, 480256256Shrs "not found", NULL); 481256256Shrs failed(j); 482256256Shrs } 483234712Sjamie goto jail_remove_done; 484234712Sjamie } 485234712Sjamie j->comparam = stopcommands; 486234712Sjamie j->comstring = NULL; 487234712Sjamie } else if ((j->flags & JF_FAILED) && j->jid > 0) 488234712Sjamie goto jail_remove_done; 489234712Sjamie if (next_command(j)) 490234712Sjamie continue; 491234712Sjamie jail_remove_done: 492234712Sjamie dep_done(j, 0); 493234712Sjamie if ((j->flags & (JF_START | JF_FAILED)) == JF_START) { 494234712Sjamie j->comparam = NULL; 495234712Sjamie j->flags &= ~JF_STOP; 496234712Sjamie dep_reset(j); 497234712Sjamie requeue(j, j->ndeps ? &depend : &ready); 498234712Sjamie } 499234712Sjamie break; 500153056Sphilip } 501153056Sphilip } 502234712Sjamie 503234712Sjamie if (jfp != NULL) 504234712Sjamie fclose(jfp); 505234712Sjamie exit(error); 506234712Sjamie} 507234712Sjamie 508234712Sjamie/* 509234712Sjamie * Mark a jail's failure for future handling. 510234712Sjamie */ 511234712Sjamievoid 512234712Sjamiefailed(struct cfjail *j) 513234712Sjamie{ 514234712Sjamie j->flags |= JF_FAILED; 515234712Sjamie TAILQ_REMOVE(j->queue, j, tq); 516234712Sjamie TAILQ_INSERT_HEAD(&ready, j, tq); 517234712Sjamie j->queue = &ready; 518234712Sjamie} 519234712Sjamie 520234712Sjamie/* 521234712Sjamie * Exit slightly more gracefully when out of memory. 522234712Sjamie */ 523234712Sjamievoid * 524234712Sjamieemalloc(size_t size) 525234712Sjamie{ 526234712Sjamie void *p; 527234712Sjamie 528234712Sjamie p = malloc(size); 529234712Sjamie if (!p) 530234712Sjamie err(1, "malloc"); 531234712Sjamie return p; 532234712Sjamie} 533234712Sjamie 534234712Sjamievoid * 535234712Sjamieerealloc(void *ptr, size_t size) 536234712Sjamie{ 537234712Sjamie void *p; 538234712Sjamie 539234712Sjamie p = realloc(ptr, size); 540234712Sjamie if (!p) 541234712Sjamie err(1, "malloc"); 542234712Sjamie return p; 543234712Sjamie} 544234712Sjamie 545234712Sjamiechar * 546234712Sjamieestrdup(const char *str) 547234712Sjamie{ 548234712Sjamie char *ns; 549234712Sjamie 550234712Sjamie ns = strdup(str); 551234712Sjamie if (!ns) 552234712Sjamie err(1, "malloc"); 553234712Sjamie return ns; 554234712Sjamie} 555234712Sjamie 556234712Sjamie/* 557234712Sjamie * Print a message including an optional jail name. 558234712Sjamie */ 559234712Sjamievoid 560234712Sjamiejail_note(const struct cfjail *j, const char *fmt, ...) 561234712Sjamie{ 562234712Sjamie va_list ap, tap; 563234712Sjamie char *cs; 564234712Sjamie size_t len; 565234712Sjamie 566234712Sjamie va_start(ap, fmt); 567234712Sjamie va_copy(tap, ap); 568234712Sjamie len = vsnprintf(NULL, 0, fmt, tap); 569234712Sjamie va_end(tap); 570234712Sjamie cs = alloca(len + 1); 571234712Sjamie (void)vsnprintf(cs, len + 1, fmt, ap); 572234712Sjamie va_end(ap); 573234712Sjamie if (j->name) 574234712Sjamie printf("%s: %s", j->name, cs); 575234712Sjamie else 576234712Sjamie printf("%s", cs); 577234712Sjamie} 578234712Sjamie 579234712Sjamie/* 580234712Sjamie * Print a warning message including an optional jail name. 581234712Sjamie */ 582234712Sjamievoid 583234712Sjamiejail_warnx(const struct cfjail *j, const char *fmt, ...) 584234712Sjamie{ 585234712Sjamie va_list ap, tap; 586234712Sjamie char *cs; 587234712Sjamie size_t len; 588234712Sjamie 589234712Sjamie va_start(ap, fmt); 590234712Sjamie va_copy(tap, ap); 591234712Sjamie len = vsnprintf(NULL, 0, fmt, tap); 592234712Sjamie va_end(tap); 593234712Sjamie cs = alloca(len + 1); 594234712Sjamie (void)vsnprintf(cs, len + 1, fmt, ap); 595234712Sjamie va_end(ap); 596234712Sjamie if (j->name) 597234712Sjamie warnx("%s: %s", j->name, cs); 598234712Sjamie else 599234712Sjamie warnx("%s", cs); 600234712Sjamie} 601234712Sjamie 602234712Sjamie/* 603234712Sjamie * Create a new jail. 604234712Sjamie */ 605234712Sjamieint 606234712Sjamiecreate_jail(struct cfjail *j) 607234712Sjamie{ 608234712Sjamie struct iovec jiov[4]; 609234712Sjamie struct stat st; 610234712Sjamie struct jailparam *jp, *setparams, *setparams2, *sjp; 611234712Sjamie const char *path; 612234712Sjamie int dopersist, ns, jid, dying, didfail; 613234712Sjamie 614234712Sjamie /* 615234712Sjamie * Check the jail's path, with a better error message than jail_set 616234712Sjamie * gives. 617234712Sjamie */ 618234712Sjamie if ((path = string_param(j->intparams[KP_PATH]))) { 619234712Sjamie if (j->name != NULL && path[0] != '/') { 620234712Sjamie jail_warnx(j, "path %s: not an absolute pathname", 621234712Sjamie path); 622234712Sjamie return -1; 623133743Smaxim } 624234712Sjamie if (stat(path, &st) < 0) { 625234712Sjamie jail_warnx(j, "path %s: %s", path, strerror(errno)); 626234712Sjamie return -1; 627234712Sjamie } 628234712Sjamie if (!S_ISDIR(st.st_mode)) { 629234712Sjamie jail_warnx(j, "path %s: %s", path, strerror(ENOTDIR)); 630234712Sjamie return -1; 631234712Sjamie } 632112705Smaxim } 633234712Sjamie 634234712Sjamie /* 635234712Sjamie * Copy all the parameters, except that "persist" is always set when 636234712Sjamie * there are commands to run later. 637234712Sjamie */ 638234712Sjamie dopersist = !bool_param(j->intparams[KP_PERSIST]) && 639234712Sjamie (j->intparams[IP_EXEC_START] || j->intparams[IP_COMMAND] || 640234712Sjamie j->intparams[IP_EXEC_POSTSTART]); 641234712Sjamie sjp = setparams = 642234712Sjamie alloca((j->njp + dopersist) * sizeof(struct jailparam)); 643234712Sjamie if (dopersist && jailparam_init(sjp++, "persist") < 0) { 644234712Sjamie jail_warnx(j, "%s", jail_errmsg); 645234712Sjamie return -1; 646133743Smaxim } 647234712Sjamie for (jp = j->jp; jp < j->jp + j->njp; jp++) 648234712Sjamie if (!dopersist || !equalopts(jp->jp_name, "persist")) 649234712Sjamie *sjp++ = *jp; 650234712Sjamie ns = sjp - setparams; 651234712Sjamie 652234712Sjamie didfail = 0; 653234712Sjamie j->jid = jailparam_set_note(j, setparams, ns, JAIL_CREATE); 654234712Sjamie if (j->jid < 0 && errno == EEXIST && 655234712Sjamie bool_param(j->intparams[IP_ALLOW_DYING]) && 656234712Sjamie int_param(j->intparams[KP_JID], &jid) && jid != 0) { 657234712Sjamie /* 658234712Sjamie * The jail already exists, but may be dying. 659234712Sjamie * Make sure it is, in which case an update is appropriate. 660234712Sjamie */ 661234712Sjamie *(const void **)&jiov[0].iov_base = "jid"; 662234712Sjamie jiov[0].iov_len = sizeof("jid"); 663234712Sjamie jiov[1].iov_base = &jid; 664234712Sjamie jiov[1].iov_len = sizeof(jid); 665234712Sjamie *(const void **)&jiov[2].iov_base = "dying"; 666234712Sjamie jiov[2].iov_len = sizeof("dying"); 667234712Sjamie jiov[3].iov_base = &dying; 668234712Sjamie jiov[3].iov_len = sizeof(dying); 669234712Sjamie if (jail_get(jiov, 4, JAIL_DYING) < 0) { 670234712Sjamie /* 671234712Sjamie * It could be that the jail just barely finished 672234712Sjamie * dying, or it could be that the jid never existed 673234712Sjamie * but the name does. In either case, another try 674234712Sjamie * at creating the jail should do the right thing. 675234712Sjamie */ 676234712Sjamie if (errno == ENOENT) 677234712Sjamie j->jid = jailparam_set_note(j, setparams, ns, 678234712Sjamie JAIL_CREATE); 679234712Sjamie } else if (dying) { 680234712Sjamie j->jid = jid; 681234712Sjamie if (rdtun_params(j, 1) < 0) { 682234712Sjamie j->jid = -1; 683234712Sjamie didfail = 1; 684234712Sjamie } else { 685234712Sjamie sjp = setparams2 = alloca((j->njp + dopersist) * 686234712Sjamie sizeof(struct jailparam)); 687234712Sjamie for (jp = setparams; jp < setparams + ns; jp++) 688234712Sjamie if (!JP_RDTUN(jp) || 689234712Sjamie !strcmp(jp->jp_name, "jid")) 690234712Sjamie *sjp++ = *jp; 691234712Sjamie j->jid = jailparam_set_note(j, setparams2, 692234712Sjamie sjp - setparams2, JAIL_UPDATE | JAIL_DYING); 693234712Sjamie /* 694234712Sjamie * Again, perhaps the jail just finished dying. 695234712Sjamie */ 696234712Sjamie if (j->jid < 0 && errno == ENOENT) 697234712Sjamie j->jid = jailparam_set_note(j, 698234712Sjamie setparams, ns, JAIL_CREATE); 699234712Sjamie } 700234712Sjamie } 701234712Sjamie } 702234712Sjamie if (j->jid < 0 && !didfail) { 703234712Sjamie jail_warnx(j, "%s", jail_errmsg); 704234712Sjamie failed(j); 705234712Sjamie } 706234712Sjamie if (dopersist) { 707234712Sjamie jailparam_free(setparams, 1); 708234712Sjamie if (j->jid > 0) 709234712Sjamie j->flags |= JF_PERSIST; 710234712Sjamie } 711234712Sjamie return j->jid; 71246155Sphk} 713112705Smaxim 714234712Sjamie/* 715234712Sjamie * Remove a temporarily set "persist" parameter. 716234712Sjamie */ 717112705Smaximstatic void 718234712Sjamieclear_persist(struct cfjail *j) 719112705Smaxim{ 720234712Sjamie struct iovec jiov[4]; 721234712Sjamie int jid; 722112705Smaxim 723234712Sjamie if (!(j->flags & JF_PERSIST)) 724234712Sjamie return; 725234712Sjamie j->flags &= ~JF_PERSIST; 726234712Sjamie *(const void **)&jiov[0].iov_base = "jid"; 727234712Sjamie jiov[0].iov_len = sizeof("jid"); 728234712Sjamie jiov[1].iov_base = &j->jid; 729234712Sjamie jiov[1].iov_len = sizeof(j->jid); 730234712Sjamie *(const void **)&jiov[2].iov_base = "nopersist"; 731234712Sjamie jiov[2].iov_len = sizeof("nopersist"); 732234712Sjamie jiov[3].iov_base = NULL; 733234712Sjamie jiov[3].iov_len = 0; 734234712Sjamie jid = jail_set(jiov, 4, JAIL_UPDATE); 735234712Sjamie if (verbose > 0) 736234712Sjamie jail_note(j, "jail_set(JAIL_UPDATE) jid=%d nopersist%s%s\n", 737234712Sjamie j->jid, jid < 0 ? ": " : "", 738234712Sjamie jid < 0 ? strerror(errno) : ""); 739234712Sjamie} 740234712Sjamie 741234712Sjamie/* 742234712Sjamie * Set a jail's parameters. 743234712Sjamie */ 744234712Sjamiestatic int 745234712Sjamieupdate_jail(struct cfjail *j) 746234712Sjamie{ 747234712Sjamie struct jailparam *jp, *setparams, *sjp; 748234712Sjamie int ns, jid; 749234712Sjamie 750234712Sjamie ns = 0; 751234712Sjamie for (jp = j->jp; jp < j->jp + j->njp; jp++) 752234712Sjamie if (!JP_RDTUN(jp)) 753234712Sjamie ns++; 754234712Sjamie if (ns == 0) 755234712Sjamie return 0; 756234712Sjamie sjp = setparams = alloca(++ns * sizeof(struct jailparam)); 757234712Sjamie if (jailparam_init(sjp, "jid") < 0 || 758234712Sjamie jailparam_import_raw(sjp, &j->jid, sizeof j->jid) < 0) { 759234712Sjamie jail_warnx(j, "%s", jail_errmsg); 760234712Sjamie failed(j); 761234712Sjamie return -1; 762192896Sjamie } 763234712Sjamie for (jp = j->jp; jp < j->jp + j->njp; jp++) 764234712Sjamie if (!JP_RDTUN(jp)) 765234712Sjamie *++sjp = *jp; 766234712Sjamie 767234712Sjamie jid = jailparam_set_note(j, setparams, ns, 768234712Sjamie bool_param(j->intparams[IP_ALLOW_DYING]) 769234712Sjamie ? JAIL_UPDATE | JAIL_DYING : JAIL_UPDATE); 770234712Sjamie if (jid < 0) { 771234712Sjamie jail_warnx(j, "%s", jail_errmsg); 772234712Sjamie failed(j); 773234712Sjamie } 774234712Sjamie jailparam_free(setparams, 1); 775234712Sjamie return jid; 776112705Smaxim} 777185435Sbz 778234712Sjamie/* 779234712Sjamie * Return if a jail set would change any create-only parameters. 780234712Sjamie */ 781234712Sjamiestatic int 782234712Sjamierdtun_params(struct cfjail *j, int dofail) 783234712Sjamie{ 784234712Sjamie struct jailparam *jp, *rtparams, *rtjp; 785234712Sjamie int nrt, rval; 786234712Sjamie 787234712Sjamie if (j->flags & JF_RDTUN) 788234712Sjamie return 0; 789234712Sjamie j->flags |= JF_RDTUN; 790234712Sjamie nrt = 0; 791234712Sjamie for (jp = j->jp; jp < j->jp + j->njp; jp++) 792234712Sjamie if (JP_RDTUN(jp) && strcmp(jp->jp_name, "jid")) 793234712Sjamie nrt++; 794234712Sjamie if (nrt == 0) 795234712Sjamie return 0; 796234712Sjamie rtjp = rtparams = alloca(++nrt * sizeof(struct jailparam)); 797234712Sjamie if (jailparam_init(rtjp, "jid") < 0 || 798234712Sjamie jailparam_import_raw(rtjp, &j->jid, sizeof j->jid) < 0) { 799234712Sjamie jail_warnx(j, "%s", jail_errmsg); 800234712Sjamie exit(1); 801234712Sjamie } 802234712Sjamie for (jp = j->jp; jp < j->jp + j->njp; jp++) 803234712Sjamie if (JP_RDTUN(jp) && strcmp(jp->jp_name, "jid")) 804234712Sjamie *++rtjp = *jp; 805234712Sjamie rval = 0; 806234712Sjamie if (jailparam_get(rtparams, nrt, 807234712Sjamie bool_param(j->intparams[IP_ALLOW_DYING]) ? JAIL_DYING : 0) > 0) { 808234712Sjamie rtjp = rtparams + 1; 809234712Sjamie for (jp = j->jp, rtjp = rtparams + 1; rtjp < rtparams + nrt; 810234712Sjamie jp++) { 811234712Sjamie if (JP_RDTUN(jp) && strcmp(jp->jp_name, "jid")) { 812234712Sjamie if (!((jp->jp_flags & (JP_BOOL | JP_NOBOOL)) && 813234712Sjamie jp->jp_valuelen == 0 && 814234712Sjamie *(int *)jp->jp_value) && 815234712Sjamie !(rtjp->jp_valuelen == jp->jp_valuelen && 816234712Sjamie !memcmp(rtjp->jp_value, jp->jp_value, 817234712Sjamie jp->jp_valuelen))) { 818234712Sjamie if (dofail) { 819234712Sjamie jail_warnx(j, "%s cannot be " 820234712Sjamie "changed after creation", 821234712Sjamie jp->jp_name); 822234712Sjamie failed(j); 823234712Sjamie rval = -1; 824234712Sjamie } else 825234712Sjamie rval = 1; 826234712Sjamie break; 827234712Sjamie } 828234712Sjamie rtjp++; 829234712Sjamie } 830234712Sjamie } 831234712Sjamie } 832234712Sjamie for (rtjp = rtparams + 1; rtjp < rtparams + nrt; rtjp++) 833234712Sjamie rtjp->jp_name = NULL; 834234712Sjamie jailparam_free(rtparams, nrt); 835234712Sjamie return rval; 836234712Sjamie} 837234712Sjamie 838234712Sjamie/* 839234712Sjamie * Get the jail's jid if it is running. 840234712Sjamie */ 841192896Sjamiestatic void 842234712Sjamierunning_jid(struct cfjail *j, int dflag) 843185435Sbz{ 844234712Sjamie struct iovec jiov[2]; 845234712Sjamie const char *pval; 846234712Sjamie char *ep; 847234712Sjamie int jid; 848192896Sjamie 849234712Sjamie if ((pval = string_param(j->intparams[KP_JID]))) { 850234712Sjamie if (!(jid = strtol(pval, &ep, 10)) || *ep) { 851234712Sjamie j->jid = -1; 852234712Sjamie return; 853234712Sjamie } 854234712Sjamie *(const void **)&jiov[0].iov_base = "jid"; 855234712Sjamie jiov[0].iov_len = sizeof("jid"); 856234712Sjamie jiov[1].iov_base = &jid; 857234712Sjamie jiov[1].iov_len = sizeof(jid); 858234712Sjamie } else if ((pval = string_param(j->intparams[KP_NAME]))) { 859234712Sjamie *(const void **)&jiov[0].iov_base = "name"; 860234712Sjamie jiov[0].iov_len = sizeof("name"); 861234712Sjamie jiov[1].iov_len = strlen(pval) + 1; 862234712Sjamie jiov[1].iov_base = alloca(jiov[1].iov_len); 863234712Sjamie strcpy(jiov[1].iov_base, pval); 864234712Sjamie } else { 865234712Sjamie j->jid = -1; 866234712Sjamie return; 867192896Sjamie } 868234712Sjamie j->jid = jail_get(jiov, 2, dflag ? JAIL_DYING : 0); 869192896Sjamie} 870192896Sjamie 871192896Sjamiestatic void 872234712Sjamiejail_quoted_warnx(const struct cfjail *j, const char *name_msg, 873234712Sjamie const char *noname_msg) 874192896Sjamie{ 875234712Sjamie const char *pval; 876234712Sjamie 877234712Sjamie if ((pval = j->name) || (pval = string_param(j->intparams[KP_JID])) || 878234712Sjamie (pval = string_param(j->intparams[KP_NAME]))) 879234712Sjamie warnx("\"%s\" %s", pval, name_msg); 880234712Sjamie else 881234712Sjamie warnx("%s", noname_msg); 882234712Sjamie} 883234712Sjamie 884234712Sjamie/* 885234712Sjamie * Set jail parameters and possible print them out. 886234712Sjamie */ 887234712Sjamiestatic int 888234712Sjamiejailparam_set_note(const struct cfjail *j, struct jailparam *jp, unsigned njp, 889234712Sjamie int flags) 890234712Sjamie{ 891234712Sjamie char *value; 892234712Sjamie int jid; 893234712Sjamie unsigned i; 894234712Sjamie 895234712Sjamie jid = jailparam_set(jp, njp, flags); 896234712Sjamie if (verbose > 0) { 897234712Sjamie jail_note(j, "jail_set(%s%s)", 898234712Sjamie (flags & (JAIL_CREATE | JAIL_UPDATE)) == JAIL_CREATE 899234712Sjamie ? "JAIL_CREATE" : "JAIL_UPDATE", 900234712Sjamie (flags & JAIL_DYING) ? " | JAIL_DYING" : ""); 901234712Sjamie for (i = 0; i < njp; i++) { 902234712Sjamie printf(" %s", jp[i].jp_name); 903234712Sjamie if (jp[i].jp_value == NULL) 904234712Sjamie continue; 905234712Sjamie putchar('='); 906234712Sjamie value = jailparam_export(jp + i); 907234712Sjamie if (value == NULL) 908234712Sjamie err(1, "jailparam_export"); 909234712Sjamie quoted_print(stdout, value); 910234712Sjamie free(value); 911234712Sjamie } 912234712Sjamie if (jid < 0) 913234712Sjamie printf(": %s", strerror(errno)); 914234712Sjamie printf("\n"); 915234712Sjamie } 916234712Sjamie return jid; 917234712Sjamie} 918234712Sjamie 919234712Sjamie/* 920234712Sjamie * Print a jail record. 921234712Sjamie */ 922234712Sjamiestatic void 923234712Sjamieprint_jail(FILE *fp, struct cfjail *j, int oldcl) 924234712Sjamie{ 925234712Sjamie struct cfparam *p; 926234712Sjamie 927234712Sjamie if (oldcl) { 928234712Sjamie fprintf(fp, "%d\t", j->jid); 929234712Sjamie print_param(fp, j->intparams[KP_PATH], ',', 0); 930234712Sjamie putc('\t', fp); 931234712Sjamie print_param(fp, j->intparams[KP_HOST_HOSTNAME], ',', 0); 932234712Sjamie putc('\t', fp); 933222465Sbz#ifdef INET 934234712Sjamie print_param(fp, j->intparams[KP_IP4_ADDR], ',', 0); 935185435Sbz#ifdef INET6 936234712Sjamie if (j->intparams[KP_IP4_ADDR] && 937234712Sjamie !TAILQ_EMPTY(&j->intparams[KP_IP4_ADDR]->val) && 938234712Sjamie j->intparams[KP_IP6_ADDR] && 939234712Sjamie !TAILQ_EMPTY(&j->intparams[KP_IP6_ADDR]->val)) 940234712Sjamie putc(',', fp); 941185435Sbz#endif 942192896Sjamie#endif 943185435Sbz#ifdef INET6 944234712Sjamie print_param(fp, j->intparams[KP_IP6_ADDR], ',', 0); 945185435Sbz#endif 946234712Sjamie putc('\t', fp); 947234712Sjamie print_param(fp, j->intparams[IP_COMMAND], ' ', 0); 948234712Sjamie } else { 949234712Sjamie fprintf(fp, "jid=%d", j->jid); 950234712Sjamie TAILQ_FOREACH(p, &j->params, tq) 951234712Sjamie if (strcmp(p->name, "jid")) { 952234712Sjamie putc(' ', fp); 953234712Sjamie print_param(fp, p, ',', 1); 954234712Sjamie } 955234712Sjamie } 956234712Sjamie putc('\n', fp); 957185435Sbz} 958185435Sbz 959234712Sjamie/* 960234712Sjamie * Print a parameter value, or a name=value pair. 961234712Sjamie */ 962192896Sjamiestatic void 963234712Sjamieprint_param(FILE *fp, const struct cfparam *p, int sep, int doname) 964234712Sjamie{ 965234712Sjamie const struct cfstring *s, *ts; 966234712Sjamie 967234712Sjamie if (doname) 968234712Sjamie fputs(p->name, fp); 969234712Sjamie if (p == NULL || TAILQ_EMPTY(&p->val)) 970234712Sjamie return; 971234712Sjamie if (doname) 972234712Sjamie putc('=', fp); 973234712Sjamie TAILQ_FOREACH_SAFE(s, &p->val, tq, ts) { 974234712Sjamie quoted_print(fp, s->s); 975234712Sjamie if (ts != NULL) 976234712Sjamie putc(sep, fp); 977234712Sjamie } 978234712Sjamie} 979234712Sjamie 980234712Sjamie/* 981234712Sjamie * Print a string with quotes around spaces. 982234712Sjamie */ 983234712Sjamiestatic void 984192896Sjamiequoted_print(FILE *fp, char *str) 985185435Sbz{ 986192896Sjamie int c, qc; 987192896Sjamie char *p = str; 988185435Sbz 989234712Sjamie qc = !*p ? '"' 990234712Sjamie : strchr(p, '\'') ? '"' 991192896Sjamie : strchr(p, '"') ? '\'' 992192896Sjamie : strchr(p, ' ') || strchr(p, '\t') ? '"' 993192896Sjamie : 0; 994192896Sjamie if (qc) 995192896Sjamie putc(qc, fp); 996192896Sjamie while ((c = *p++)) { 997192896Sjamie if (c == '\\' || c == qc) 998192896Sjamie putc('\\', fp); 999192896Sjamie putc(c, fp); 1000185435Sbz } 1001192896Sjamie if (qc) 1002192896Sjamie putc(qc, fp); 1003185435Sbz} 1004185435Sbz 1005192896Sjamiestatic void 1006192896Sjamieusage(void) 1007192896Sjamie{ 1008192896Sjamie 1009192896Sjamie (void)fprintf(stderr, 1010234712Sjamie "usage: jail [-dhilqv] [-J jid_file] [-u username] [-U username]\n" 1011234712Sjamie " -[cmr] param=value ... [command=command ...]\n" 1012234712Sjamie " jail [-dqv] [-f file] -[cmr] [jail]\n" 1013234712Sjamie " jail [-qv] [-f file] -[rR] ['*' | jail ...]\n" 1014234712Sjamie " jail [-dhilqv] [-J jid_file] [-u username] [-U username]\n" 1015234712Sjamie " [-n jailname] [-s securelevel]\n" 1016234712Sjamie " path hostname [ip[,...]] command ...\n"); 1017192896Sjamie exit(1); 1018185435Sbz} 1019