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$"); 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, 96234712Sjamie IP_EXEC_PRESTART, 97234712Sjamie IP__OP, 98234712Sjamie IP_VNET_INTERFACE, 99234712Sjamie IP_EXEC_START, 100234712Sjamie IP_COMMAND, 101234712Sjamie IP_EXEC_POSTSTART, 102234988Sjamie IP__NULL 103234712Sjamie}; 104192896Sjamie 105234712Sjamiestatic const enum intparam stopcommands[] = { 106234988Sjamie IP__NULL, 107234712Sjamie IP_EXEC_PRESTOP, 108234712Sjamie IP_EXEC_STOP, 109234712Sjamie IP_STOP_TIMEOUT, 110234712Sjamie IP__OP, 111234712Sjamie IP_EXEC_POSTSTOP, 112256387Shrs IP_MOUNT_FDESCFS, 113234712Sjamie IP_MOUNT_DEVFS, 114234712Sjamie IP__MOUNT_FROM_FSTAB, 115234712Sjamie IP_MOUNT, 116234712Sjamie#ifdef INET6 117234712Sjamie IP__IP6_IFADDR, 118234712Sjamie#endif 119234712Sjamie#ifdef INET 120234712Sjamie IP__IP4_IFADDR, 121234712Sjamie#endif 122234988Sjamie IP__NULL 123234712Sjamie}; 124129848Smaxim 12546155Sphkint 12646155Sphkmain(int argc, char **argv) 12746155Sphk{ 128234712Sjamie struct stat st; 129234712Sjamie FILE *jfp; 130234712Sjamie struct cfjail *j; 131234712Sjamie char *JidFile; 132193929Sjamie size_t sysvallen; 133234712Sjamie unsigned op, pi; 134234712Sjamie int ch, docf, error, i, oldcl, sysval; 135236198Sjamie int dflag, Rflag; 136194869Sjamie char enforce_statfs[4]; 137234712Sjamie#if defined(INET) || defined(INET6) 138234712Sjamie char *cs, *ncs; 139234712Sjamie#endif 140234712Sjamie#if defined(INET) && defined(INET6) 141234712Sjamie struct in6_addr addr6; 142234712Sjamie#endif 14346155Sphk 144234712Sjamie op = 0; 145236198Sjamie dflag = Rflag = 0; 146234712Sjamie docf = 1; 147234712Sjamie cfname = CONF_FILE; 148234712Sjamie JidFile = NULL; 149112705Smaxim 150237697Smaxim while ((ch = getopt(argc, argv, "cdf:hiJ:lmn:p:qrRs:u:U:v")) != -1) { 151112705Smaxim switch (ch) { 152234712Sjamie case 'c': 153234712Sjamie op |= JF_START; 154234712Sjamie break; 155192896Sjamie case 'd': 156234712Sjamie dflag = 1; 157192896Sjamie break; 158234712Sjamie case 'f': 159234712Sjamie cfname = optarg; 160234712Sjamie break; 161185435Sbz case 'h': 162234712Sjamie#if defined(INET) || defined(INET6) 163234712Sjamie add_param(NULL, NULL, IP_IP_HOSTNAME, NULL); 164234712Sjamie#endif 165234712Sjamie docf = 0; 166185435Sbz break; 167113277Smike case 'i': 168113277Smike iflag = 1; 169234712Sjamie verbose = -1; 170113277Smike break; 171153056Sphilip case 'J': 172153056Sphilip JidFile = optarg; 173153056Sphilip break; 174234712Sjamie case 'l': 175234712Sjamie add_param(NULL, NULL, IP_EXEC_CLEAN, NULL); 176234712Sjamie docf = 0; 177234712Sjamie break; 178234712Sjamie case 'm': 179234712Sjamie op |= JF_SET; 180234712Sjamie break; 181185435Sbz case 'n': 182234712Sjamie add_param(NULL, NULL, KP_NAME, optarg); 183234712Sjamie docf = 0; 184185435Sbz break; 185234712Sjamie case 'p': 186234712Sjamie paralimit = strtol(optarg, NULL, 10); 187234712Sjamie if (paralimit == 0) 188234712Sjamie paralimit = -1; 189234712Sjamie break; 190234712Sjamie case 'q': 191234712Sjamie verbose = -1; 192234712Sjamie break; 193234712Sjamie case 'r': 194234712Sjamie op |= JF_STOP; 195234712Sjamie break; 196234712Sjamie case 'R': 197234712Sjamie op |= JF_STOP; 198234712Sjamie Rflag = 1; 199234712Sjamie break; 200158428Smatteo case 's': 201234712Sjamie add_param(NULL, NULL, KP_SECURELEVEL, optarg); 202234712Sjamie docf = 0; 203158428Smatteo break; 204112705Smaxim case 'u': 205234712Sjamie add_param(NULL, NULL, IP_EXEC_JAIL_USER, optarg); 206234712Sjamie add_param(NULL, NULL, IP_EXEC_SYSTEM_JAIL_USER, NULL); 207234712Sjamie docf = 0; 208112705Smaxim break; 209129848Smaxim case 'U': 210234712Sjamie add_param(NULL, NULL, IP_EXEC_JAIL_USER, optarg); 211234712Sjamie add_param(NULL, NULL, IP_EXEC_SYSTEM_JAIL_USER, 212234712Sjamie "false"); 213234712Sjamie docf = 0; 214129848Smaxim break; 215234712Sjamie case 'v': 216234712Sjamie verbose = 1; 217133743Smaxim break; 218112705Smaxim default: 219112705Smaxim usage(); 220112705Smaxim } 221113277Smike } 222112705Smaxim argc -= optind; 223112705Smaxim argv += optind; 224234712Sjamie 225234712Sjamie /* Find out which of the four command line styles this is. */ 226234712Sjamie oldcl = 0; 227234712Sjamie if (!op) { 228234712Sjamie /* Old-style command line with four fixed parameters */ 229234712Sjamie if (argc < 4 || argv[0][0] != '/') 230192896Sjamie usage(); 231234712Sjamie op = JF_START; 232234712Sjamie docf = 0; 233234712Sjamie oldcl = 1; 234234712Sjamie add_param(NULL, NULL, KP_PATH, argv[0]); 235234712Sjamie add_param(NULL, NULL, KP_HOST_HOSTNAME, argv[1]); 236234712Sjamie#if defined(INET) || defined(INET6) 237234712Sjamie if (argv[2][0] != '\0') { 238234712Sjamie for (cs = argv[2];; cs = ncs + 1) { 239234712Sjamie ncs = strchr(cs, ','); 240234712Sjamie if (ncs) 241234712Sjamie *ncs = '\0'; 242234712Sjamie add_param(NULL, NULL, 243234712Sjamie#if defined(INET) && defined(INET6) 244234712Sjamie inet_pton(AF_INET6, cs, &addr6) == 1 245234712Sjamie ? KP_IP6_ADDR : KP_IP4_ADDR, 246234712Sjamie#elif defined(INET) 247234712Sjamie KP_IP4_ADDR, 248234712Sjamie#elif defined(INET6) 249234712Sjamie KP_IP6_ADDR, 250222465Sbz#endif 251234712Sjamie cs); 252234712Sjamie if (!ncs) 253192896Sjamie break; 254192896Sjamie } 255192896Sjamie } 256192896Sjamie#endif 257234712Sjamie for (i = 3; i < argc; i++) 258234712Sjamie add_param(NULL, NULL, IP_COMMAND, argv[i]); 259234712Sjamie /* Emulate the defaults from security.jail.* sysctls. */ 260193929Sjamie sysvallen = sizeof(sysval); 261193929Sjamie if (sysctlbyname("security.jail.jailed", &sysval, &sysvallen, 262193929Sjamie NULL, 0) == 0 && sysval == 0) { 263193929Sjamie for (pi = 0; pi < sizeof(perm_sysctl) / 264193929Sjamie sizeof(perm_sysctl[0]); pi++) { 265193929Sjamie sysvallen = sizeof(sysval); 266234712Sjamie if (sysctlbyname(perm_sysctl[pi].name, 267193929Sjamie &sysval, &sysvallen, NULL, 0) == 0) 268234712Sjamie add_param(NULL, NULL, 269234712Sjamie perm_sysctl[pi].ipnum, 270234712Sjamie (sysval ? 1 : 0) ^ 271234712Sjamie perm_sysctl[pi].rev 272234712Sjamie ? NULL : "false"); 273193929Sjamie } 274193929Sjamie sysvallen = sizeof(sysval); 275193929Sjamie if (sysctlbyname("security.jail.enforce_statfs", 276193929Sjamie &sysval, &sysvallen, NULL, 0) == 0) { 277193929Sjamie snprintf(enforce_statfs, 278193929Sjamie sizeof(enforce_statfs), "%d", sysval); 279234712Sjamie add_param(NULL, NULL, KP_ENFORCE_STATFS, 280234712Sjamie enforce_statfs); 281193929Sjamie } 282193929Sjamie } 283234712Sjamie } else if (op == JF_STOP) { 284234712Sjamie /* Jail remove, perhaps using the config file */ 285234712Sjamie if (!docf || argc == 0) 286234712Sjamie usage(); 287234712Sjamie if (!Rflag) 288234712Sjamie for (i = 0; i < argc; i++) 289234712Sjamie if (strchr(argv[i], '=')) 290234712Sjamie usage(); 291234712Sjamie if ((docf = !Rflag && 292234712Sjamie (!strcmp(cfname, "-") || stat(cfname, &st) == 0))) 293234712Sjamie load_config(); 294234712Sjamie note_remove = docf || argc > 1 || wild_jail_name(argv[0]); 295234712Sjamie } else if (argc > 1 || (argc == 1 && strchr(argv[0], '='))) { 296234712Sjamie /* Single jail specified on the command line */ 297234712Sjamie if (Rflag) 298234712Sjamie usage(); 299234712Sjamie docf = 0; 300234712Sjamie for (i = 0; i < argc; i++) { 301234712Sjamie if (!strncmp(argv[i], "command", 7) && 302234712Sjamie (argv[i][7] == '\0' || argv[i][7] == '=')) { 303234712Sjamie if (argv[i][7] == '=') 304234712Sjamie add_param(NULL, NULL, IP_COMMAND, 305234712Sjamie argv[i] + 8); 306234712Sjamie for (i++; i < argc; i++) 307234712Sjamie add_param(NULL, NULL, IP_COMMAND, 308234712Sjamie argv[i]); 309234712Sjamie } 310239602Sjamie#ifdef INET 311239602Sjamie else if (!strncmp(argv[i], "ip4.addr=", 9)) { 312239602Sjamie for (cs = argv[i] + 9;; cs = ncs + 1) { 313239602Sjamie ncs = strchr(cs, ','); 314239602Sjamie if (ncs) 315239602Sjamie *ncs = '\0'; 316239602Sjamie add_param(NULL, NULL, KP_IP4_ADDR, cs); 317239602Sjamie if (!ncs) 318239602Sjamie break; 319239602Sjamie } 320239602Sjamie } 321239602Sjamie#endif 322239602Sjamie#ifdef INET6 323239602Sjamie else if (!strncmp(argv[i], "ip6.addr=", 9)) { 324239602Sjamie for (cs = argv[i] + 9;; cs = ncs + 1) { 325239602Sjamie ncs = strchr(cs, ','); 326239602Sjamie if (ncs) 327239602Sjamie *ncs = '\0'; 328239602Sjamie add_param(NULL, NULL, KP_IP6_ADDR, cs); 329239602Sjamie if (!ncs) 330239602Sjamie break; 331239602Sjamie } 332239602Sjamie } 333239602Sjamie#endif 334239602Sjamie else 335239602Sjamie add_param(NULL, NULL, 0, argv[i]); 336234712Sjamie } 337234712Sjamie } else { 338234712Sjamie /* From the config file, perhaps with a specified jail */ 339234712Sjamie if (Rflag || !docf) 340234712Sjamie usage(); 341234712Sjamie load_config(); 342185435Sbz } 343185435Sbz 344234712Sjamie /* Find out which jails will be run. */ 345234712Sjamie dep_setup(docf); 346234712Sjamie error = 0; 347234712Sjamie if (op == JF_STOP) { 348234712Sjamie for (i = 0; i < argc; i++) 349234712Sjamie if (start_state(argv[i], docf, op, Rflag) < 0) 350234712Sjamie error = 1; 351234712Sjamie } else { 352234712Sjamie if (start_state(argv[0], docf, op, 0) < 0) 353234712Sjamie exit(1); 354153056Sphilip } 355234712Sjamie 356234712Sjamie jfp = NULL; 357234712Sjamie if (JidFile != NULL) { 358234712Sjamie jfp = fopen(JidFile, "w"); 359234712Sjamie if (jfp == NULL) 360234712Sjamie err(1, "open %s", JidFile); 361234712Sjamie setlinebuf(jfp); 362113804Smike } 363234712Sjamie setlinebuf(stdout); 364234712Sjamie 365234712Sjamie /* 366234712Sjamie * The main loop: Get an available jail and perform the required 367234712Sjamie * operation on it. When that is done, the jail may be finished, 368234712Sjamie * or it may go back for the next step. 369234712Sjamie */ 370234712Sjamie while ((j = next_jail())) 371234712Sjamie { 372234712Sjamie if (j->flags & JF_FAILED) { 373234712Sjamie error = 1; 374234712Sjamie if (j->comparam == NULL) { 375234712Sjamie dep_done(j, 0); 376234712Sjamie continue; 377234712Sjamie } 378234712Sjamie } 379234712Sjamie if (!(j->flags & JF_PARAMS)) 380234712Sjamie { 381234712Sjamie j->flags |= JF_PARAMS; 382234712Sjamie if (dflag) 383234712Sjamie add_param(j, NULL, IP_ALLOW_DYING, NULL); 384234712Sjamie if (check_intparams(j) < 0) 385234712Sjamie continue; 386234712Sjamie if ((j->flags & (JF_START | JF_SET)) && 387234712Sjamie import_params(j) < 0) 388234712Sjamie continue; 389234712Sjamie } 390234712Sjamie if (!j->jid) 391234712Sjamie running_jid(j, 392234712Sjamie (j->flags & (JF_SET | JF_DEPEND)) == JF_SET 393234712Sjamie ? dflag || bool_param(j->intparams[IP_ALLOW_DYING]) 394234712Sjamie : 0); 395234712Sjamie if (finish_command(j)) 396234712Sjamie continue; 397234712Sjamie 398234712Sjamie switch (j->flags & JF_OP_MASK) { 399234712Sjamie /* 400234712Sjamie * These operations just turn into a different op 401234712Sjamie * depending on the jail's current status. 402234712Sjamie */ 403234712Sjamie case JF_START_SET: 404234712Sjamie j->flags = j->jid < 0 ? JF_START : JF_SET; 405234712Sjamie break; 406234712Sjamie case JF_SET_RESTART: 407234712Sjamie if (j->jid < 0) { 408234712Sjamie jail_quoted_warnx(j, "not found", 409234712Sjamie "no jail specified"); 410234712Sjamie failed(j); 411234712Sjamie continue; 412234712Sjamie } 413234712Sjamie j->flags = rdtun_params(j, 0) ? JF_RESTART : JF_SET; 414234712Sjamie if (j->flags == JF_RESTART) 415234712Sjamie dep_reset(j); 416234712Sjamie break; 417234712Sjamie case JF_START_SET_RESTART: 418234712Sjamie j->flags = j->jid < 0 ? JF_START 419234712Sjamie : rdtun_params(j, 0) ? JF_RESTART : JF_SET; 420234712Sjamie if (j->flags == JF_RESTART) 421234712Sjamie dep_reset(j); 422234712Sjamie } 423234712Sjamie 424234712Sjamie switch (j->flags & JF_OP_MASK) { 425234712Sjamie case JF_START: 426234712Sjamie if (j->comparam == NULL) { 427234712Sjamie if (j->jid > 0 && 428234712Sjamie !(j->flags & (JF_DEPEND | JF_WILD))) { 429234712Sjamie jail_quoted_warnx(j, "already exists", 430234712Sjamie NULL); 431234712Sjamie failed(j); 432234712Sjamie continue; 433192896Sjamie } 434234712Sjamie if (dep_check(j)) 435234712Sjamie continue; 436234712Sjamie if (j->jid > 0) 437234712Sjamie goto jail_create_done; 438234712Sjamie j->comparam = startcommands; 439234712Sjamie j->comstring = NULL; 440234712Sjamie } 441234712Sjamie if (next_command(j)) 442234712Sjamie continue; 443234712Sjamie jail_create_done: 444234712Sjamie clear_persist(j); 445234712Sjamie if (jfp != NULL) 446234712Sjamie print_jail(jfp, j, oldcl); 447234712Sjamie dep_done(j, 0); 448234712Sjamie break; 449234712Sjamie 450234712Sjamie case JF_SET: 451234712Sjamie if (j->jid < 0 && !(j->flags & JF_DEPEND)) { 452234712Sjamie jail_quoted_warnx(j, "not found", 453234712Sjamie "no jail specified"); 454234712Sjamie failed(j); 455234712Sjamie continue; 456234712Sjamie } 457234712Sjamie if (dep_check(j)) 458234712Sjamie continue; 459234712Sjamie if (!(j->flags & JF_DEPEND)) { 460234712Sjamie if (rdtun_params(j, 1) < 0 || 461234712Sjamie update_jail(j) < 0) 462234712Sjamie continue; 463234712Sjamie if (verbose >= 0 && (j->name || verbose > 0)) 464234712Sjamie jail_note(j, "updated\n"); 465234712Sjamie } 466234712Sjamie dep_done(j, 0); 467234712Sjamie break; 468234712Sjamie 469234712Sjamie case JF_STOP: 470234712Sjamie case JF_RESTART: 471234712Sjamie if (j->comparam == NULL) { 472234712Sjamie if (dep_check(j)) 473234712Sjamie continue; 474234712Sjamie if (j->jid < 0) { 475256256Shrs if (!(j->flags & (JF_DEPEND|JF_WILD))) { 476256256Shrs if (verbose >= 0) 477256256Shrs jail_quoted_warnx(j, 478256256Shrs "not found", NULL); 479256256Shrs failed(j); 480256256Shrs } 481234712Sjamie goto jail_remove_done; 482234712Sjamie } 483234712Sjamie j->comparam = stopcommands; 484234712Sjamie j->comstring = NULL; 485234712Sjamie } else if ((j->flags & JF_FAILED) && j->jid > 0) 486234712Sjamie goto jail_remove_done; 487234712Sjamie if (next_command(j)) 488234712Sjamie continue; 489234712Sjamie jail_remove_done: 490234712Sjamie dep_done(j, 0); 491234712Sjamie if ((j->flags & (JF_START | JF_FAILED)) == JF_START) { 492234712Sjamie j->comparam = NULL; 493234712Sjamie j->flags &= ~JF_STOP; 494234712Sjamie dep_reset(j); 495234712Sjamie requeue(j, j->ndeps ? &depend : &ready); 496234712Sjamie } 497234712Sjamie break; 498153056Sphilip } 499153056Sphilip } 500234712Sjamie 501234712Sjamie if (jfp != NULL) 502234712Sjamie fclose(jfp); 503234712Sjamie exit(error); 504234712Sjamie} 505234712Sjamie 506234712Sjamie/* 507234712Sjamie * Mark a jail's failure for future handling. 508234712Sjamie */ 509234712Sjamievoid 510234712Sjamiefailed(struct cfjail *j) 511234712Sjamie{ 512234712Sjamie j->flags |= JF_FAILED; 513234712Sjamie TAILQ_REMOVE(j->queue, j, tq); 514234712Sjamie TAILQ_INSERT_HEAD(&ready, j, tq); 515234712Sjamie j->queue = &ready; 516234712Sjamie} 517234712Sjamie 518234712Sjamie/* 519234712Sjamie * Exit slightly more gracefully when out of memory. 520234712Sjamie */ 521234712Sjamievoid * 522234712Sjamieemalloc(size_t size) 523234712Sjamie{ 524234712Sjamie void *p; 525234712Sjamie 526234712Sjamie p = malloc(size); 527234712Sjamie if (!p) 528234712Sjamie err(1, "malloc"); 529234712Sjamie return p; 530234712Sjamie} 531234712Sjamie 532234712Sjamievoid * 533234712Sjamieerealloc(void *ptr, size_t size) 534234712Sjamie{ 535234712Sjamie void *p; 536234712Sjamie 537234712Sjamie p = realloc(ptr, size); 538234712Sjamie if (!p) 539234712Sjamie err(1, "malloc"); 540234712Sjamie return p; 541234712Sjamie} 542234712Sjamie 543234712Sjamiechar * 544234712Sjamieestrdup(const char *str) 545234712Sjamie{ 546234712Sjamie char *ns; 547234712Sjamie 548234712Sjamie ns = strdup(str); 549234712Sjamie if (!ns) 550234712Sjamie err(1, "malloc"); 551234712Sjamie return ns; 552234712Sjamie} 553234712Sjamie 554234712Sjamie/* 555234712Sjamie * Print a message including an optional jail name. 556234712Sjamie */ 557234712Sjamievoid 558234712Sjamiejail_note(const struct cfjail *j, const char *fmt, ...) 559234712Sjamie{ 560234712Sjamie va_list ap, tap; 561234712Sjamie char *cs; 562234712Sjamie size_t len; 563234712Sjamie 564234712Sjamie va_start(ap, fmt); 565234712Sjamie va_copy(tap, ap); 566234712Sjamie len = vsnprintf(NULL, 0, fmt, tap); 567234712Sjamie va_end(tap); 568234712Sjamie cs = alloca(len + 1); 569234712Sjamie (void)vsnprintf(cs, len + 1, fmt, ap); 570234712Sjamie va_end(ap); 571234712Sjamie if (j->name) 572234712Sjamie printf("%s: %s", j->name, cs); 573234712Sjamie else 574234712Sjamie printf("%s", cs); 575234712Sjamie} 576234712Sjamie 577234712Sjamie/* 578234712Sjamie * Print a warning message including an optional jail name. 579234712Sjamie */ 580234712Sjamievoid 581234712Sjamiejail_warnx(const struct cfjail *j, const char *fmt, ...) 582234712Sjamie{ 583234712Sjamie va_list ap, tap; 584234712Sjamie char *cs; 585234712Sjamie size_t len; 586234712Sjamie 587234712Sjamie va_start(ap, fmt); 588234712Sjamie va_copy(tap, ap); 589234712Sjamie len = vsnprintf(NULL, 0, fmt, tap); 590234712Sjamie va_end(tap); 591234712Sjamie cs = alloca(len + 1); 592234712Sjamie (void)vsnprintf(cs, len + 1, fmt, ap); 593234712Sjamie va_end(ap); 594234712Sjamie if (j->name) 595234712Sjamie warnx("%s: %s", j->name, cs); 596234712Sjamie else 597234712Sjamie warnx("%s", cs); 598234712Sjamie} 599234712Sjamie 600234712Sjamie/* 601234712Sjamie * Create a new jail. 602234712Sjamie */ 603234712Sjamieint 604234712Sjamiecreate_jail(struct cfjail *j) 605234712Sjamie{ 606234712Sjamie struct iovec jiov[4]; 607234712Sjamie struct stat st; 608234712Sjamie struct jailparam *jp, *setparams, *setparams2, *sjp; 609234712Sjamie const char *path; 610234712Sjamie int dopersist, ns, jid, dying, didfail; 611234712Sjamie 612234712Sjamie /* 613234712Sjamie * Check the jail's path, with a better error message than jail_set 614234712Sjamie * gives. 615234712Sjamie */ 616234712Sjamie if ((path = string_param(j->intparams[KP_PATH]))) { 617234712Sjamie if (j->name != NULL && path[0] != '/') { 618234712Sjamie jail_warnx(j, "path %s: not an absolute pathname", 619234712Sjamie path); 620234712Sjamie return -1; 621133743Smaxim } 622234712Sjamie if (stat(path, &st) < 0) { 623234712Sjamie jail_warnx(j, "path %s: %s", path, strerror(errno)); 624234712Sjamie return -1; 625234712Sjamie } 626234712Sjamie if (!S_ISDIR(st.st_mode)) { 627234712Sjamie jail_warnx(j, "path %s: %s", path, strerror(ENOTDIR)); 628234712Sjamie return -1; 629234712Sjamie } 630112705Smaxim } 631234712Sjamie 632234712Sjamie /* 633234712Sjamie * Copy all the parameters, except that "persist" is always set when 634234712Sjamie * there are commands to run later. 635234712Sjamie */ 636234712Sjamie dopersist = !bool_param(j->intparams[KP_PERSIST]) && 637234712Sjamie (j->intparams[IP_EXEC_START] || j->intparams[IP_COMMAND] || 638234712Sjamie j->intparams[IP_EXEC_POSTSTART]); 639234712Sjamie sjp = setparams = 640234712Sjamie alloca((j->njp + dopersist) * sizeof(struct jailparam)); 641234712Sjamie if (dopersist && jailparam_init(sjp++, "persist") < 0) { 642234712Sjamie jail_warnx(j, "%s", jail_errmsg); 643234712Sjamie return -1; 644133743Smaxim } 645234712Sjamie for (jp = j->jp; jp < j->jp + j->njp; jp++) 646234712Sjamie if (!dopersist || !equalopts(jp->jp_name, "persist")) 647234712Sjamie *sjp++ = *jp; 648234712Sjamie ns = sjp - setparams; 649234712Sjamie 650234712Sjamie didfail = 0; 651234712Sjamie j->jid = jailparam_set_note(j, setparams, ns, JAIL_CREATE); 652234712Sjamie if (j->jid < 0 && errno == EEXIST && 653234712Sjamie bool_param(j->intparams[IP_ALLOW_DYING]) && 654234712Sjamie int_param(j->intparams[KP_JID], &jid) && jid != 0) { 655234712Sjamie /* 656234712Sjamie * The jail already exists, but may be dying. 657234712Sjamie * Make sure it is, in which case an update is appropriate. 658234712Sjamie */ 659234712Sjamie *(const void **)&jiov[0].iov_base = "jid"; 660234712Sjamie jiov[0].iov_len = sizeof("jid"); 661234712Sjamie jiov[1].iov_base = &jid; 662234712Sjamie jiov[1].iov_len = sizeof(jid); 663234712Sjamie *(const void **)&jiov[2].iov_base = "dying"; 664234712Sjamie jiov[2].iov_len = sizeof("dying"); 665234712Sjamie jiov[3].iov_base = &dying; 666234712Sjamie jiov[3].iov_len = sizeof(dying); 667234712Sjamie if (jail_get(jiov, 4, JAIL_DYING) < 0) { 668234712Sjamie /* 669234712Sjamie * It could be that the jail just barely finished 670234712Sjamie * dying, or it could be that the jid never existed 671234712Sjamie * but the name does. In either case, another try 672234712Sjamie * at creating the jail should do the right thing. 673234712Sjamie */ 674234712Sjamie if (errno == ENOENT) 675234712Sjamie j->jid = jailparam_set_note(j, setparams, ns, 676234712Sjamie JAIL_CREATE); 677234712Sjamie } else if (dying) { 678234712Sjamie j->jid = jid; 679234712Sjamie if (rdtun_params(j, 1) < 0) { 680234712Sjamie j->jid = -1; 681234712Sjamie didfail = 1; 682234712Sjamie } else { 683234712Sjamie sjp = setparams2 = alloca((j->njp + dopersist) * 684234712Sjamie sizeof(struct jailparam)); 685234712Sjamie for (jp = setparams; jp < setparams + ns; jp++) 686234712Sjamie if (!JP_RDTUN(jp) || 687234712Sjamie !strcmp(jp->jp_name, "jid")) 688234712Sjamie *sjp++ = *jp; 689234712Sjamie j->jid = jailparam_set_note(j, setparams2, 690234712Sjamie sjp - setparams2, JAIL_UPDATE | JAIL_DYING); 691234712Sjamie /* 692234712Sjamie * Again, perhaps the jail just finished dying. 693234712Sjamie */ 694234712Sjamie if (j->jid < 0 && errno == ENOENT) 695234712Sjamie j->jid = jailparam_set_note(j, 696234712Sjamie setparams, ns, JAIL_CREATE); 697234712Sjamie } 698234712Sjamie } 699234712Sjamie } 700234712Sjamie if (j->jid < 0 && !didfail) { 701234712Sjamie jail_warnx(j, "%s", jail_errmsg); 702234712Sjamie failed(j); 703234712Sjamie } 704234712Sjamie if (dopersist) { 705234712Sjamie jailparam_free(setparams, 1); 706234712Sjamie if (j->jid > 0) 707234712Sjamie j->flags |= JF_PERSIST; 708234712Sjamie } 709234712Sjamie return j->jid; 71046155Sphk} 711112705Smaxim 712234712Sjamie/* 713234712Sjamie * Remove a temporarily set "persist" parameter. 714234712Sjamie */ 715112705Smaximstatic void 716234712Sjamieclear_persist(struct cfjail *j) 717112705Smaxim{ 718234712Sjamie struct iovec jiov[4]; 719234712Sjamie int jid; 720112705Smaxim 721234712Sjamie if (!(j->flags & JF_PERSIST)) 722234712Sjamie return; 723234712Sjamie j->flags &= ~JF_PERSIST; 724234712Sjamie *(const void **)&jiov[0].iov_base = "jid"; 725234712Sjamie jiov[0].iov_len = sizeof("jid"); 726234712Sjamie jiov[1].iov_base = &j->jid; 727234712Sjamie jiov[1].iov_len = sizeof(j->jid); 728234712Sjamie *(const void **)&jiov[2].iov_base = "nopersist"; 729234712Sjamie jiov[2].iov_len = sizeof("nopersist"); 730234712Sjamie jiov[3].iov_base = NULL; 731234712Sjamie jiov[3].iov_len = 0; 732234712Sjamie jid = jail_set(jiov, 4, JAIL_UPDATE); 733234712Sjamie if (verbose > 0) 734234712Sjamie jail_note(j, "jail_set(JAIL_UPDATE) jid=%d nopersist%s%s\n", 735234712Sjamie j->jid, jid < 0 ? ": " : "", 736234712Sjamie jid < 0 ? strerror(errno) : ""); 737234712Sjamie} 738234712Sjamie 739234712Sjamie/* 740234712Sjamie * Set a jail's parameters. 741234712Sjamie */ 742234712Sjamiestatic int 743234712Sjamieupdate_jail(struct cfjail *j) 744234712Sjamie{ 745234712Sjamie struct jailparam *jp, *setparams, *sjp; 746234712Sjamie int ns, jid; 747234712Sjamie 748234712Sjamie ns = 0; 749234712Sjamie for (jp = j->jp; jp < j->jp + j->njp; jp++) 750234712Sjamie if (!JP_RDTUN(jp)) 751234712Sjamie ns++; 752234712Sjamie if (ns == 0) 753234712Sjamie return 0; 754234712Sjamie sjp = setparams = alloca(++ns * sizeof(struct jailparam)); 755234712Sjamie if (jailparam_init(sjp, "jid") < 0 || 756234712Sjamie jailparam_import_raw(sjp, &j->jid, sizeof j->jid) < 0) { 757234712Sjamie jail_warnx(j, "%s", jail_errmsg); 758234712Sjamie failed(j); 759234712Sjamie return -1; 760192896Sjamie } 761234712Sjamie for (jp = j->jp; jp < j->jp + j->njp; jp++) 762234712Sjamie if (!JP_RDTUN(jp)) 763234712Sjamie *++sjp = *jp; 764234712Sjamie 765234712Sjamie jid = jailparam_set_note(j, setparams, ns, 766234712Sjamie bool_param(j->intparams[IP_ALLOW_DYING]) 767234712Sjamie ? JAIL_UPDATE | JAIL_DYING : JAIL_UPDATE); 768234712Sjamie if (jid < 0) { 769234712Sjamie jail_warnx(j, "%s", jail_errmsg); 770234712Sjamie failed(j); 771234712Sjamie } 772234712Sjamie jailparam_free(setparams, 1); 773234712Sjamie return jid; 774112705Smaxim} 775185435Sbz 776234712Sjamie/* 777234712Sjamie * Return if a jail set would change any create-only parameters. 778234712Sjamie */ 779234712Sjamiestatic int 780234712Sjamierdtun_params(struct cfjail *j, int dofail) 781234712Sjamie{ 782234712Sjamie struct jailparam *jp, *rtparams, *rtjp; 783234712Sjamie int nrt, rval; 784234712Sjamie 785234712Sjamie if (j->flags & JF_RDTUN) 786234712Sjamie return 0; 787234712Sjamie j->flags |= JF_RDTUN; 788234712Sjamie nrt = 0; 789234712Sjamie for (jp = j->jp; jp < j->jp + j->njp; jp++) 790234712Sjamie if (JP_RDTUN(jp) && strcmp(jp->jp_name, "jid")) 791234712Sjamie nrt++; 792234712Sjamie if (nrt == 0) 793234712Sjamie return 0; 794234712Sjamie rtjp = rtparams = alloca(++nrt * sizeof(struct jailparam)); 795234712Sjamie if (jailparam_init(rtjp, "jid") < 0 || 796234712Sjamie jailparam_import_raw(rtjp, &j->jid, sizeof j->jid) < 0) { 797234712Sjamie jail_warnx(j, "%s", jail_errmsg); 798234712Sjamie exit(1); 799234712Sjamie } 800234712Sjamie for (jp = j->jp; jp < j->jp + j->njp; jp++) 801234712Sjamie if (JP_RDTUN(jp) && strcmp(jp->jp_name, "jid")) 802234712Sjamie *++rtjp = *jp; 803234712Sjamie rval = 0; 804234712Sjamie if (jailparam_get(rtparams, nrt, 805234712Sjamie bool_param(j->intparams[IP_ALLOW_DYING]) ? JAIL_DYING : 0) > 0) { 806234712Sjamie rtjp = rtparams + 1; 807234712Sjamie for (jp = j->jp, rtjp = rtparams + 1; rtjp < rtparams + nrt; 808234712Sjamie jp++) { 809234712Sjamie if (JP_RDTUN(jp) && strcmp(jp->jp_name, "jid")) { 810234712Sjamie if (!((jp->jp_flags & (JP_BOOL | JP_NOBOOL)) && 811234712Sjamie jp->jp_valuelen == 0 && 812234712Sjamie *(int *)jp->jp_value) && 813234712Sjamie !(rtjp->jp_valuelen == jp->jp_valuelen && 814234712Sjamie !memcmp(rtjp->jp_value, jp->jp_value, 815234712Sjamie jp->jp_valuelen))) { 816234712Sjamie if (dofail) { 817234712Sjamie jail_warnx(j, "%s cannot be " 818234712Sjamie "changed after creation", 819234712Sjamie jp->jp_name); 820234712Sjamie failed(j); 821234712Sjamie rval = -1; 822234712Sjamie } else 823234712Sjamie rval = 1; 824234712Sjamie break; 825234712Sjamie } 826234712Sjamie rtjp++; 827234712Sjamie } 828234712Sjamie } 829234712Sjamie } 830234712Sjamie for (rtjp = rtparams + 1; rtjp < rtparams + nrt; rtjp++) 831234712Sjamie rtjp->jp_name = NULL; 832234712Sjamie jailparam_free(rtparams, nrt); 833234712Sjamie return rval; 834234712Sjamie} 835234712Sjamie 836234712Sjamie/* 837234712Sjamie * Get the jail's jid if it is running. 838234712Sjamie */ 839192896Sjamiestatic void 840234712Sjamierunning_jid(struct cfjail *j, int dflag) 841185435Sbz{ 842234712Sjamie struct iovec jiov[2]; 843234712Sjamie const char *pval; 844234712Sjamie char *ep; 845234712Sjamie int jid; 846192896Sjamie 847234712Sjamie if ((pval = string_param(j->intparams[KP_JID]))) { 848234712Sjamie if (!(jid = strtol(pval, &ep, 10)) || *ep) { 849234712Sjamie j->jid = -1; 850234712Sjamie return; 851234712Sjamie } 852234712Sjamie *(const void **)&jiov[0].iov_base = "jid"; 853234712Sjamie jiov[0].iov_len = sizeof("jid"); 854234712Sjamie jiov[1].iov_base = &jid; 855234712Sjamie jiov[1].iov_len = sizeof(jid); 856234712Sjamie } else if ((pval = string_param(j->intparams[KP_NAME]))) { 857234712Sjamie *(const void **)&jiov[0].iov_base = "name"; 858234712Sjamie jiov[0].iov_len = sizeof("name"); 859234712Sjamie jiov[1].iov_len = strlen(pval) + 1; 860234712Sjamie jiov[1].iov_base = alloca(jiov[1].iov_len); 861234712Sjamie strcpy(jiov[1].iov_base, pval); 862234712Sjamie } else { 863234712Sjamie j->jid = -1; 864234712Sjamie return; 865192896Sjamie } 866234712Sjamie j->jid = jail_get(jiov, 2, dflag ? JAIL_DYING : 0); 867192896Sjamie} 868192896Sjamie 869192896Sjamiestatic void 870234712Sjamiejail_quoted_warnx(const struct cfjail *j, const char *name_msg, 871234712Sjamie const char *noname_msg) 872192896Sjamie{ 873234712Sjamie const char *pval; 874234712Sjamie 875234712Sjamie if ((pval = j->name) || (pval = string_param(j->intparams[KP_JID])) || 876234712Sjamie (pval = string_param(j->intparams[KP_NAME]))) 877234712Sjamie warnx("\"%s\" %s", pval, name_msg); 878234712Sjamie else 879234712Sjamie warnx("%s", noname_msg); 880234712Sjamie} 881234712Sjamie 882234712Sjamie/* 883234712Sjamie * Set jail parameters and possible print them out. 884234712Sjamie */ 885234712Sjamiestatic int 886234712Sjamiejailparam_set_note(const struct cfjail *j, struct jailparam *jp, unsigned njp, 887234712Sjamie int flags) 888234712Sjamie{ 889234712Sjamie char *value; 890234712Sjamie int jid; 891234712Sjamie unsigned i; 892234712Sjamie 893234712Sjamie jid = jailparam_set(jp, njp, flags); 894234712Sjamie if (verbose > 0) { 895234712Sjamie jail_note(j, "jail_set(%s%s)", 896234712Sjamie (flags & (JAIL_CREATE | JAIL_UPDATE)) == JAIL_CREATE 897234712Sjamie ? "JAIL_CREATE" : "JAIL_UPDATE", 898234712Sjamie (flags & JAIL_DYING) ? " | JAIL_DYING" : ""); 899234712Sjamie for (i = 0; i < njp; i++) { 900234712Sjamie printf(" %s", jp[i].jp_name); 901234712Sjamie if (jp[i].jp_value == NULL) 902234712Sjamie continue; 903234712Sjamie putchar('='); 904234712Sjamie value = jailparam_export(jp + i); 905234712Sjamie if (value == NULL) 906234712Sjamie err(1, "jailparam_export"); 907234712Sjamie quoted_print(stdout, value); 908234712Sjamie free(value); 909234712Sjamie } 910234712Sjamie if (jid < 0) 911234712Sjamie printf(": %s", strerror(errno)); 912234712Sjamie printf("\n"); 913234712Sjamie } 914234712Sjamie return jid; 915234712Sjamie} 916234712Sjamie 917234712Sjamie/* 918234712Sjamie * Print a jail record. 919234712Sjamie */ 920234712Sjamiestatic void 921234712Sjamieprint_jail(FILE *fp, struct cfjail *j, int oldcl) 922234712Sjamie{ 923234712Sjamie struct cfparam *p; 924234712Sjamie 925234712Sjamie if (oldcl) { 926234712Sjamie fprintf(fp, "%d\t", j->jid); 927234712Sjamie print_param(fp, j->intparams[KP_PATH], ',', 0); 928234712Sjamie putc('\t', fp); 929234712Sjamie print_param(fp, j->intparams[KP_HOST_HOSTNAME], ',', 0); 930234712Sjamie putc('\t', fp); 931222465Sbz#ifdef INET 932234712Sjamie print_param(fp, j->intparams[KP_IP4_ADDR], ',', 0); 933185435Sbz#ifdef INET6 934234712Sjamie if (j->intparams[KP_IP4_ADDR] && 935234712Sjamie !TAILQ_EMPTY(&j->intparams[KP_IP4_ADDR]->val) && 936234712Sjamie j->intparams[KP_IP6_ADDR] && 937234712Sjamie !TAILQ_EMPTY(&j->intparams[KP_IP6_ADDR]->val)) 938234712Sjamie putc(',', fp); 939185435Sbz#endif 940192896Sjamie#endif 941185435Sbz#ifdef INET6 942234712Sjamie print_param(fp, j->intparams[KP_IP6_ADDR], ',', 0); 943185435Sbz#endif 944234712Sjamie putc('\t', fp); 945234712Sjamie print_param(fp, j->intparams[IP_COMMAND], ' ', 0); 946234712Sjamie } else { 947234712Sjamie fprintf(fp, "jid=%d", j->jid); 948234712Sjamie TAILQ_FOREACH(p, &j->params, tq) 949234712Sjamie if (strcmp(p->name, "jid")) { 950234712Sjamie putc(' ', fp); 951234712Sjamie print_param(fp, p, ',', 1); 952234712Sjamie } 953234712Sjamie } 954234712Sjamie putc('\n', fp); 955185435Sbz} 956185435Sbz 957234712Sjamie/* 958234712Sjamie * Print a parameter value, or a name=value pair. 959234712Sjamie */ 960192896Sjamiestatic void 961234712Sjamieprint_param(FILE *fp, const struct cfparam *p, int sep, int doname) 962234712Sjamie{ 963234712Sjamie const struct cfstring *s, *ts; 964234712Sjamie 965234712Sjamie if (doname) 966234712Sjamie fputs(p->name, fp); 967234712Sjamie if (p == NULL || TAILQ_EMPTY(&p->val)) 968234712Sjamie return; 969234712Sjamie if (doname) 970234712Sjamie putc('=', fp); 971234712Sjamie TAILQ_FOREACH_SAFE(s, &p->val, tq, ts) { 972234712Sjamie quoted_print(fp, s->s); 973234712Sjamie if (ts != NULL) 974234712Sjamie putc(sep, fp); 975234712Sjamie } 976234712Sjamie} 977234712Sjamie 978234712Sjamie/* 979234712Sjamie * Print a string with quotes around spaces. 980234712Sjamie */ 981234712Sjamiestatic void 982192896Sjamiequoted_print(FILE *fp, char *str) 983185435Sbz{ 984192896Sjamie int c, qc; 985192896Sjamie char *p = str; 986185435Sbz 987234712Sjamie qc = !*p ? '"' 988234712Sjamie : strchr(p, '\'') ? '"' 989192896Sjamie : strchr(p, '"') ? '\'' 990192896Sjamie : strchr(p, ' ') || strchr(p, '\t') ? '"' 991192896Sjamie : 0; 992192896Sjamie if (qc) 993192896Sjamie putc(qc, fp); 994192896Sjamie while ((c = *p++)) { 995192896Sjamie if (c == '\\' || c == qc) 996192896Sjamie putc('\\', fp); 997192896Sjamie putc(c, fp); 998185435Sbz } 999192896Sjamie if (qc) 1000192896Sjamie putc(qc, fp); 1001185435Sbz} 1002185435Sbz 1003192896Sjamiestatic void 1004192896Sjamieusage(void) 1005192896Sjamie{ 1006192896Sjamie 1007192896Sjamie (void)fprintf(stderr, 1008234712Sjamie "usage: jail [-dhilqv] [-J jid_file] [-u username] [-U username]\n" 1009234712Sjamie " -[cmr] param=value ... [command=command ...]\n" 1010234712Sjamie " jail [-dqv] [-f file] -[cmr] [jail]\n" 1011234712Sjamie " jail [-qv] [-f file] -[rR] ['*' | jail ...]\n" 1012234712Sjamie " jail [-dhilqv] [-J jid_file] [-u username] [-U username]\n" 1013234712Sjamie " [-n jailname] [-s securelevel]\n" 1014234712Sjamie " path hostname [ip[,...]] command ...\n"); 1015192896Sjamie exit(1); 1016185435Sbz} 1017