1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 1999 Poul-Henning Kamp.
5 * Copyright (c) 2009-2012 James Gritton
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD$");
32
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <sys/socket.h>
36#include <sys/sysctl.h>
37
38#include <arpa/inet.h>
39#include <netinet/in.h>
40
41#include <err.h>
42#include <errno.h>
43#include <stdarg.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <string.h>
47#include <unistd.h>
48
49#include "jailp.h"
50
51#define JP_RDTUN(jp)	(((jp)->jp_ctltype & CTLFLAG_RDTUN) == CTLFLAG_RDTUN)
52
53struct permspec {
54	const char	*name;
55	enum intparam	ipnum;
56	int		rev;
57};
58
59const char *cfname;
60int iflag;
61int note_remove;
62int verbose;
63const char *separator = "\t";
64
65static void clear_persist(struct cfjail *j);
66static int update_jail(struct cfjail *j);
67static int rdtun_params(struct cfjail *j, int dofail);
68static void running_jid(struct cfjail *j, int dflag);
69static void jail_quoted_warnx(const struct cfjail *j, const char *name_msg,
70    const char *noname_msg);
71static int jailparam_set_note(const struct cfjail *j, struct jailparam *jp,
72    unsigned njp, int flags);
73static void print_jail(FILE *fp, struct cfjail *j, int oldcl, int running);
74static void print_param(FILE *fp, const struct cfparam *p, int sep, int doname);
75static void show_jails(void);
76static void quoted_print(FILE *fp, char *str);
77static void usage(void);
78
79static struct permspec perm_sysctl[] = {
80    { "security.jail.set_hostname_allowed", KP_ALLOW_SET_HOSTNAME, 0 },
81    { "security.jail.sysvipc_allowed", KP_ALLOW_SYSVIPC, 0 },
82    { "security.jail.allow_raw_sockets", KP_ALLOW_RAW_SOCKETS, 0 },
83    { "security.jail.chflags_allowed", KP_ALLOW_CHFLAGS, 0 },
84    { "security.jail.mount_allowed", KP_ALLOW_MOUNT, 0 },
85    { "security.jail.socket_unixiproute_only", KP_ALLOW_SOCKET_AF, 1 },
86};
87
88static const enum intparam startcommands[] = {
89    IP__NULL,
90    IP_EXEC_PREPARE,
91#ifdef INET
92    IP__IP4_IFADDR,
93#endif
94#ifdef INET6
95    IP__IP6_IFADDR,
96#endif
97    IP_MOUNT,
98    IP__MOUNT_FROM_FSTAB,
99    IP_MOUNT_DEVFS,
100    IP_MOUNT_FDESCFS,
101    IP_MOUNT_PROCFS,
102    IP_EXEC_PRESTART,
103    IP__OP,
104    IP_EXEC_CREATED,
105    IP_VNET_INTERFACE,
106    IP_EXEC_START,
107    IP_COMMAND,
108    IP_EXEC_POSTSTART,
109    IP__NULL
110};
111
112static const enum intparam stopcommands[] = {
113    IP__NULL,
114    IP_EXEC_PRESTOP,
115    IP_EXEC_STOP,
116    IP_STOP_TIMEOUT,
117    IP__OP,
118    IP_EXEC_POSTSTOP,
119    IP_MOUNT_PROCFS,
120    IP_MOUNT_FDESCFS,
121    IP_MOUNT_DEVFS,
122    IP__MOUNT_FROM_FSTAB,
123    IP_MOUNT,
124#ifdef INET6
125    IP__IP6_IFADDR,
126#endif
127#ifdef INET
128    IP__IP4_IFADDR,
129#endif
130    IP_EXEC_RELEASE,
131    IP__NULL
132};
133
134int
135main(int argc, char **argv)
136{
137	struct stat st;
138	FILE *jfp;
139	struct cfjail *j;
140	char *JidFile;
141	size_t sysvallen;
142	unsigned op, pi;
143	int ch, docf, error, i, oldcl, sysval;
144	int dflag, Rflag;
145#if defined(INET) || defined(INET6)
146	char *cs, *ncs;
147#endif
148#if defined(INET) && defined(INET6)
149	struct in6_addr addr6;
150#endif
151
152	op = 0;
153	dflag = Rflag = 0;
154	docf = 1;
155	cfname = CONF_FILE;
156	JidFile = NULL;
157
158	while ((ch = getopt(argc, argv, "cde:f:hiJ:lmn:p:qrRs:u:U:v")) != -1) {
159		switch (ch) {
160		case 'c':
161			op |= JF_START;
162			break;
163		case 'd':
164			dflag = 1;
165			break;
166		case 'e':
167			op |= JF_SHOW;
168			separator = optarg;
169			break;
170		case 'f':
171			cfname = optarg;
172			break;
173		case 'h':
174#if defined(INET) || defined(INET6)
175			add_param(NULL, NULL, IP_IP_HOSTNAME, NULL);
176#endif
177			docf = 0;
178			break;
179		case 'i':
180			iflag = 1;
181			verbose = -1;
182			break;
183		case 'J':
184			JidFile = optarg;
185			break;
186		case 'l':
187			add_param(NULL, NULL, IP_EXEC_CLEAN, NULL);
188			docf = 0;
189			break;
190		case 'm':
191			op |= JF_SET;
192			break;
193		case 'n':
194			add_param(NULL, NULL, KP_NAME, optarg);
195			docf = 0;
196			break;
197		case 'p':
198			paralimit = strtol(optarg, NULL, 10);
199			if (paralimit == 0)
200				paralimit = -1;
201			break;
202		case 'q':
203			verbose = -1;
204			break;
205		case 'r':
206			op |= JF_STOP;
207			break;
208		case 'R':
209			op |= JF_STOP;
210			Rflag = 1;
211			break;
212		case 's':
213			add_param(NULL, NULL, KP_SECURELEVEL, optarg);
214			docf = 0;
215			break;
216		case 'u':
217			add_param(NULL, NULL, IP_EXEC_JAIL_USER, optarg);
218			add_param(NULL, NULL, IP_EXEC_SYSTEM_JAIL_USER, NULL);
219			docf = 0;
220			break;
221		case 'U':
222			add_param(NULL, NULL, IP_EXEC_JAIL_USER, optarg);
223			add_param(NULL, NULL, IP_EXEC_SYSTEM_JAIL_USER,
224			    "false");
225			docf = 0;
226			break;
227		case 'v':
228			verbose = 1;
229			break;
230		default:
231			usage();
232		}
233	}
234	argc -= optind;
235	argv += optind;
236
237	/* Find out which of the four command line styles this is. */
238	oldcl = 0;
239	if (!op) {
240		/* Old-style command line with four fixed parameters */
241		if (argc < 4 || argv[0][0] != '/')
242			usage();
243		op = JF_START;
244		docf = 0;
245		oldcl = 1;
246		add_param(NULL, NULL, KP_PATH, argv[0]);
247		add_param(NULL, NULL, KP_HOST_HOSTNAME, argv[1]);
248#if defined(INET) || defined(INET6)
249		if (argv[2][0] != '\0') {
250			for (cs = argv[2];; cs = ncs + 1) {
251				ncs = strchr(cs, ',');
252				if (ncs)
253					*ncs = '\0';
254				add_param(NULL, NULL,
255#if defined(INET) && defined(INET6)
256				    inet_pton(AF_INET6, cs, &addr6) == 1
257				    ? KP_IP6_ADDR : KP_IP4_ADDR,
258#elif defined(INET)
259				    KP_IP4_ADDR,
260#elif defined(INET6)
261				    KP_IP6_ADDR,
262#endif
263				    cs);
264				if (!ncs)
265					break;
266			}
267		}
268#endif
269		for (i = 3; i < argc; i++)
270			add_param(NULL, NULL, IP_COMMAND, argv[i]);
271		/* Emulate the defaults from security.jail.* sysctls. */
272		sysvallen = sizeof(sysval);
273		if (sysctlbyname("security.jail.jailed", &sysval, &sysvallen,
274		    NULL, 0) == 0 && sysval == 0) {
275			for (pi = 0; pi < sizeof(perm_sysctl) /
276			     sizeof(perm_sysctl[0]); pi++) {
277				sysvallen = sizeof(sysval);
278				if (sysctlbyname(perm_sysctl[pi].name,
279				    &sysval, &sysvallen, NULL, 0) == 0)
280					add_param(NULL, NULL,
281					    perm_sysctl[pi].ipnum,
282					    (sysval ? 1 : 0) ^
283					    perm_sysctl[pi].rev
284					    ? NULL : "false");
285			}
286		}
287	} else if (op == JF_STOP || op == JF_SHOW) {
288		/* Just print list of all configured non-wildcard jails */
289		if (op == JF_SHOW) {
290			load_config();
291			show_jails();
292			exit(0);
293		}
294		/* Jail remove, perhaps using the config file */
295		if (!docf || argc == 0)
296			usage();
297		if (!Rflag)
298			for (i = 0; i < argc; i++)
299				if (strchr(argv[i], '='))
300					usage();
301		if ((docf = !Rflag &&
302		     (!strcmp(cfname, "-") || stat(cfname, &st) == 0)))
303			load_config();
304		note_remove = docf || argc > 1 || wild_jail_name(argv[0]);
305	} else if (argc > 1 || (argc == 1 && strchr(argv[0], '='))) {
306		/* Single jail specified on the command line */
307		if (Rflag)
308			usage();
309		docf = 0;
310		for (i = 0; i < argc; i++) {
311			if (!strncmp(argv[i], "command", 7) &&
312			    (argv[i][7] == '\0' || argv[i][7] == '=')) {
313				if (argv[i][7]  == '=')
314					add_param(NULL, NULL, IP_COMMAND,
315					    argv[i] + 8);
316				for (i++; i < argc; i++)
317					add_param(NULL, NULL, IP_COMMAND,
318					    argv[i]);
319			}
320#ifdef INET
321			else if (!strncmp(argv[i], "ip4.addr=", 9)) {
322				for (cs = argv[i] + 9;; cs = ncs + 1) {
323					ncs = strchr(cs, ',');
324					if (ncs)
325						*ncs = '\0';
326					add_param(NULL, NULL, KP_IP4_ADDR, cs);
327					if (!ncs)
328						break;
329				}
330			}
331#endif
332#ifdef INET6
333			else if (!strncmp(argv[i], "ip6.addr=", 9)) {
334				for (cs = argv[i] + 9;; cs = ncs + 1) {
335					ncs = strchr(cs, ',');
336					if (ncs)
337						*ncs = '\0';
338					add_param(NULL, NULL, KP_IP6_ADDR, cs);
339					if (!ncs)
340						break;
341				}
342			}
343#endif
344			else
345				add_param(NULL, NULL, 0, argv[i]);
346		}
347	} else {
348		/* From the config file, perhaps with a specified jail */
349		if (Rflag || !docf)
350			usage();
351		load_config();
352	}
353
354	/* Find out which jails will be run. */
355	dep_setup(docf);
356	error = 0;
357	if (op == JF_STOP) {
358		for (i = 0; i < argc; i++)
359			if (start_state(argv[i], docf, op, Rflag) < 0)
360				error = 1;
361	} else {
362		if (start_state(argv[0], docf, op, 0) < 0)
363			exit(1);
364	}
365
366	jfp = NULL;
367	if (JidFile != NULL) {
368		jfp = fopen(JidFile, "w");
369		if (jfp == NULL)
370			err(1, "open %s", JidFile);
371		setlinebuf(jfp);
372	}
373	setlinebuf(stdout);
374
375	/*
376	 * The main loop: Get an available jail and perform the required
377	 * operation on it.  When that is done, the jail may be finished,
378	 * or it may go back for the next step.
379	 */
380	while ((j = next_jail()))
381	{
382		if (j->flags & JF_FAILED) {
383			error = 1;
384			if (j->comparam == NULL) {
385				dep_done(j, 0);
386				continue;
387			}
388		}
389		if (!(j->flags & JF_PARAMS))
390		{
391			j->flags |= JF_PARAMS;
392			if (dflag)
393				add_param(j, NULL, IP_ALLOW_DYING, NULL);
394			if (check_intparams(j) < 0)
395				continue;
396			if ((j->flags & (JF_START | JF_SET)) &&
397			    import_params(j) < 0)
398				continue;
399		}
400		if (!j->jid)
401			running_jid(j,
402			    (j->flags & (JF_SET | JF_DEPEND)) == JF_SET
403			    ? dflag || bool_param(j->intparams[IP_ALLOW_DYING])
404			    : 0);
405		if (finish_command(j))
406			continue;
407
408		switch (j->flags & JF_OP_MASK) {
409			/*
410			 * These operations just turn into a different op
411			 * depending on the jail's current status.
412			 */
413		case JF_START_SET:
414			j->flags = j->jid < 0 ? JF_START : JF_SET;
415			break;
416		case JF_SET_RESTART:
417			if (j->jid < 0) {
418				jail_quoted_warnx(j, "not found",
419				    "no jail specified");
420				failed(j);
421				continue;
422			}
423			j->flags = rdtun_params(j, 0) ? JF_RESTART : JF_SET;
424			if (j->flags == JF_RESTART)
425				dep_reset(j);
426			break;
427		case JF_START_SET_RESTART:
428			j->flags = j->jid < 0 ? JF_START
429			    : rdtun_params(j, 0) ? JF_RESTART : JF_SET;
430			if (j->flags == JF_RESTART)
431				dep_reset(j);
432		}
433
434		switch (j->flags & JF_OP_MASK) {
435		case JF_START:
436			if (j->comparam == NULL) {
437				if (j->jid > 0 &&
438				    !(j->flags & (JF_DEPEND | JF_WILD))) {
439					jail_quoted_warnx(j, "already exists",
440					    NULL);
441					failed(j);
442					continue;
443				}
444				if (dep_check(j))
445					continue;
446				if (j->jid > 0)
447					goto jail_create_done;
448				j->comparam = startcommands;
449				j->comstring = NULL;
450			}
451			if (next_command(j))
452				continue;
453		jail_create_done:
454			clear_persist(j);
455			if (jfp != NULL)
456				print_jail(jfp, j, oldcl, 1);
457			dep_done(j, 0);
458			break;
459
460		case JF_SET:
461			if (j->jid < 0 && !(j->flags & JF_DEPEND)) {
462				jail_quoted_warnx(j, "not found",
463				    "no jail specified");
464				failed(j);
465				continue;
466			}
467			if (dep_check(j))
468				continue;
469			if (!(j->flags & JF_DEPEND)) {
470				if (rdtun_params(j, 1) < 0 ||
471				    update_jail(j) < 0)
472					continue;
473				if (verbose >= 0 && (j->name || verbose > 0))
474					jail_note(j, "updated\n");
475			}
476			dep_done(j, 0);
477			break;
478
479		case JF_STOP:
480		case JF_RESTART:
481			if (j->comparam == NULL) {
482				if (dep_check(j))
483					continue;
484				if (j->jid < 0) {
485					if (!(j->flags & (JF_DEPEND|JF_WILD))) {
486						if (verbose >= 0)
487							jail_quoted_warnx(j,
488							    "not found", NULL);
489						failed(j);
490					}
491					goto jail_remove_done;
492				}
493				j->comparam = stopcommands;
494				j->comstring = NULL;
495			} else if ((j->flags & JF_FAILED) && j->jid > 0)
496				goto jail_remove_done;
497			if (next_command(j))
498				continue;
499		jail_remove_done:
500			dep_done(j, 0);
501			if ((j->flags & (JF_START | JF_FAILED)) == JF_START) {
502				j->comparam = NULL;
503				j->flags &= ~JF_STOP;
504				dep_reset(j);
505				requeue(j, j->ndeps ? &depend : &ready);
506			}
507			break;
508		}
509	}
510
511	if (jfp != NULL)
512		fclose(jfp);
513	exit(error);
514}
515
516/*
517 * Mark a jail's failure for future handling.
518 */
519void
520failed(struct cfjail *j)
521{
522	j->flags |= JF_FAILED;
523	TAILQ_REMOVE(j->queue, j, tq);
524	TAILQ_INSERT_HEAD(&ready, j, tq);
525	j->queue = &ready;
526}
527
528/*
529 * Exit slightly more gracefully when out of memory.
530 */
531void *
532emalloc(size_t size)
533{
534	void *p;
535
536	p = malloc(size);
537	if (!p)
538		err(1, "malloc");
539	return p;
540}
541
542void *
543erealloc(void *ptr, size_t size)
544{
545	void *p;
546
547	p = realloc(ptr, size);
548	if (!p)
549		err(1, "malloc");
550	return p;
551}
552
553char *
554estrdup(const char *str)
555{
556	char *ns;
557
558	ns = strdup(str);
559	if (!ns)
560		err(1, "malloc");
561	return ns;
562}
563
564/*
565 * Print a message including an optional jail name.
566 */
567void
568jail_note(const struct cfjail *j, const char *fmt, ...)
569{
570	va_list ap, tap;
571	char *cs;
572	size_t len;
573
574	va_start(ap, fmt);
575	va_copy(tap, ap);
576	len = vsnprintf(NULL, 0, fmt, tap);
577	va_end(tap);
578	cs = alloca(len + 1);
579	(void)vsnprintf(cs, len + 1, fmt, ap);
580	va_end(ap);
581	if (j->name)
582		printf("%s: %s", j->name, cs);
583	else
584		printf("%s", cs);
585}
586
587/*
588 * Print a warning message including an optional jail name.
589 */
590void
591jail_warnx(const struct cfjail *j, const char *fmt, ...)
592{
593	va_list ap, tap;
594	char *cs;
595	size_t len;
596
597	va_start(ap, fmt);
598	va_copy(tap, ap);
599	len = vsnprintf(NULL, 0, fmt, tap);
600	va_end(tap);
601	cs = alloca(len + 1);
602	(void)vsnprintf(cs, len + 1, fmt, ap);
603	va_end(ap);
604	if (j->name)
605		warnx("%s: %s", j->name, cs);
606	else
607		warnx("%s", cs);
608}
609
610/*
611 * Create a new jail.
612 */
613int
614create_jail(struct cfjail *j)
615{
616	struct iovec jiov[4];
617	struct stat st;
618	struct jailparam *jp, *setparams, *setparams2, *sjp;
619	const char *path;
620	int dopersist, ns, jid, dying, didfail;
621
622	/*
623	 * Check the jail's path, with a better error message than jail_set
624	 * gives.
625	 */
626	if ((path = string_param(j->intparams[KP_PATH]))) {
627		if (j->name != NULL && path[0] != '/') {
628			jail_warnx(j, "path %s: not an absolute pathname",
629			    path);
630			return -1;
631		}
632		if (stat(path, &st) < 0) {
633			jail_warnx(j, "path %s: %s", path, strerror(errno));
634			return -1;
635		}
636		if (!S_ISDIR(st.st_mode)) {
637			jail_warnx(j, "path %s: %s", path, strerror(ENOTDIR));
638			return -1;
639		}
640	}
641
642	/*
643	 * Copy all the parameters, except that "persist" is always set when
644	 * there are commands to run later.
645	 */
646	dopersist = !bool_param(j->intparams[KP_PERSIST]) &&
647	    (j->intparams[IP_EXEC_START] || j->intparams[IP_COMMAND] ||
648	     j->intparams[IP_EXEC_POSTSTART]);
649	sjp = setparams =
650	    alloca((j->njp + dopersist) * sizeof(struct jailparam));
651	if (dopersist && jailparam_init(sjp++, "persist") < 0) {
652		jail_warnx(j, "%s", jail_errmsg);
653		return -1;
654	}
655	for (jp = j->jp; jp < j->jp + j->njp; jp++)
656		if (!dopersist || !equalopts(jp->jp_name, "persist"))
657			*sjp++ = *jp;
658	ns = sjp - setparams;
659
660	didfail = 0;
661	j->jid = jailparam_set_note(j, setparams, ns, JAIL_CREATE);
662	if (j->jid < 0 && errno == EEXIST &&
663	    bool_param(j->intparams[IP_ALLOW_DYING]) &&
664	    int_param(j->intparams[KP_JID], &jid) && jid != 0) {
665		/*
666		 * The jail already exists, but may be dying.
667		 * Make sure it is, in which case an update is appropriate.
668		 */
669		jiov[0].iov_base = __DECONST(char *, "jid");
670		jiov[0].iov_len = sizeof("jid");
671		jiov[1].iov_base = &jid;
672		jiov[1].iov_len = sizeof(jid);
673		jiov[2].iov_base = __DECONST(char *, "dying");
674		jiov[2].iov_len = sizeof("dying");
675		jiov[3].iov_base = &dying;
676		jiov[3].iov_len = sizeof(dying);
677		if (jail_get(jiov, 4, JAIL_DYING) < 0) {
678			/*
679			 * It could be that the jail just barely finished
680			 * dying, or it could be that the jid never existed
681			 * but the name does.  In either case, another try
682			 * at creating the jail should do the right thing.
683			 */
684			if (errno == ENOENT)
685				j->jid = jailparam_set_note(j, setparams, ns,
686				    JAIL_CREATE);
687		} else if (dying) {
688			j->jid = jid;
689			if (rdtun_params(j, 1) < 0) {
690				j->jid = -1;
691				didfail = 1;
692			} else {
693				sjp = setparams2 = alloca((j->njp + dopersist) *
694				    sizeof(struct jailparam));
695				for (jp = setparams; jp < setparams + ns; jp++)
696					if (!JP_RDTUN(jp) ||
697					    !strcmp(jp->jp_name, "jid"))
698						*sjp++ = *jp;
699				j->jid = jailparam_set_note(j, setparams2,
700				    sjp - setparams2, JAIL_UPDATE | JAIL_DYING);
701				/*
702				 * Again, perhaps the jail just finished dying.
703				 */
704				if (j->jid < 0 && errno == ENOENT)
705					j->jid = jailparam_set_note(j,
706					    setparams, ns, JAIL_CREATE);
707			}
708		}
709	}
710	if (j->jid < 0 && !didfail) {
711		jail_warnx(j, "%s", jail_errmsg);
712		failed(j);
713	}
714	if (dopersist) {
715		jailparam_free(setparams, 1);
716		if (j->jid > 0)
717			j->flags |= JF_PERSIST;
718	}
719	return j->jid;
720}
721
722/*
723 * Remove a temporarily set "persist" parameter.
724 */
725static void
726clear_persist(struct cfjail *j)
727{
728	struct iovec jiov[4];
729	int jid;
730
731	if (!(j->flags & JF_PERSIST))
732		return;
733	j->flags &= ~JF_PERSIST;
734	jiov[0].iov_base = __DECONST(char *, "jid");
735	jiov[0].iov_len = sizeof("jid");
736	jiov[1].iov_base = &j->jid;
737	jiov[1].iov_len = sizeof(j->jid);
738	jiov[2].iov_base = __DECONST(char *, "nopersist");
739	jiov[2].iov_len = sizeof("nopersist");
740	jiov[3].iov_base = NULL;
741	jiov[3].iov_len = 0;
742	jid = jail_set(jiov, 4, JAIL_UPDATE);
743	if (verbose > 0)
744		jail_note(j, "jail_set(JAIL_UPDATE) jid=%d nopersist%s%s\n",
745		    j->jid, jid < 0 ? ": " : "",
746		    jid < 0 ? strerror(errno) : "");
747}
748
749/*
750 * Set a jail's parameters.
751 */
752static int
753update_jail(struct cfjail *j)
754{
755	struct jailparam *jp, *setparams, *sjp;
756	int ns, jid;
757
758	ns = 0;
759	for (jp = j->jp; jp < j->jp + j->njp; jp++)
760		if (!JP_RDTUN(jp))
761			ns++;
762	if (ns == 0)
763		return 0;
764	sjp = setparams = alloca(++ns * sizeof(struct jailparam));
765	if (jailparam_init(sjp, "jid") < 0 ||
766	    jailparam_import_raw(sjp, &j->jid, sizeof j->jid) < 0) {
767		jail_warnx(j, "%s", jail_errmsg);
768		failed(j);
769		return -1;
770	}
771	for (jp = j->jp; jp < j->jp + j->njp; jp++)
772		if (!JP_RDTUN(jp))
773			*++sjp = *jp;
774
775	jid = jailparam_set_note(j, setparams, ns,
776	    bool_param(j->intparams[IP_ALLOW_DYING])
777	    ? JAIL_UPDATE | JAIL_DYING : JAIL_UPDATE);
778	if (jid < 0) {
779		jail_warnx(j, "%s", jail_errmsg);
780		failed(j);
781	}
782	jailparam_free(setparams, 1);
783	return jid;
784}
785
786/*
787 * Return if a jail set would change any create-only parameters.
788 */
789static int
790rdtun_params(struct cfjail *j, int dofail)
791{
792	struct jailparam *jp, *rtparams, *rtjp;
793	int nrt, rval;
794
795	if (j->flags & JF_RDTUN)
796		return 0;
797	j->flags |= JF_RDTUN;
798	nrt = 0;
799	for (jp = j->jp; jp < j->jp + j->njp; jp++)
800		if (JP_RDTUN(jp) && strcmp(jp->jp_name, "jid"))
801			nrt++;
802	if (nrt == 0)
803		return 0;
804	rtjp = rtparams = alloca(++nrt * sizeof(struct jailparam));
805	if (jailparam_init(rtjp, "jid") < 0 ||
806	    jailparam_import_raw(rtjp, &j->jid, sizeof j->jid) < 0) {
807		jail_warnx(j, "%s", jail_errmsg);
808		exit(1);
809	}
810	for (jp = j->jp; jp < j->jp + j->njp; jp++)
811		if (JP_RDTUN(jp) && strcmp(jp->jp_name, "jid")) {
812			*++rtjp = *jp;
813			rtjp->jp_value = NULL;
814		}
815	rval = 0;
816	if (jailparam_get(rtparams, nrt,
817	    bool_param(j->intparams[IP_ALLOW_DYING]) ? JAIL_DYING : 0) > 0) {
818		rtjp = rtparams + 1;
819		for (jp = j->jp; rtjp < rtparams + nrt; jp++) {
820			if (JP_RDTUN(jp) && strcmp(jp->jp_name, "jid")) {
821				if (!((jp->jp_flags & (JP_BOOL | JP_NOBOOL)) &&
822				    jp->jp_valuelen == 0 &&
823				    *(int *)jp->jp_value) &&
824				    !(rtjp->jp_valuelen == jp->jp_valuelen &&
825				    !((jp->jp_ctltype & CTLTYPE) ==
826				    CTLTYPE_STRING ? strncmp(rtjp->jp_value,
827				    jp->jp_value, jp->jp_valuelen) :
828				    memcmp(rtjp->jp_value, jp->jp_value,
829				    jp->jp_valuelen)))) {
830					if (dofail) {
831						jail_warnx(j, "%s cannot be "
832						    "changed after creation",
833						    jp->jp_name);
834						failed(j);
835						rval = -1;
836					} else
837						rval = 1;
838					break;
839				}
840				rtjp++;
841			}
842		}
843	}
844	for (rtjp = rtparams + 1; rtjp < rtparams + nrt; rtjp++)
845		rtjp->jp_name = NULL;
846	jailparam_free(rtparams, nrt);
847	return rval;
848}
849
850/*
851 * Get the jail's jid if it is running.
852 */
853static void
854running_jid(struct cfjail *j, int dflag)
855{
856	struct iovec jiov[2];
857	const char *pval;
858	char *ep;
859	int jid;
860
861	if ((pval = string_param(j->intparams[KP_JID]))) {
862		if (!(jid = strtol(pval, &ep, 10)) || *ep) {
863			j->jid = -1;
864			return;
865		}
866		jiov[0].iov_base = __DECONST(char *, "jid");
867		jiov[0].iov_len = sizeof("jid");
868		jiov[1].iov_base = &jid;
869		jiov[1].iov_len = sizeof(jid);
870	} else if ((pval = string_param(j->intparams[KP_NAME]))) {
871		jiov[0].iov_base = __DECONST(char *, "name");
872		jiov[0].iov_len = sizeof("name");
873		jiov[1].iov_len = strlen(pval) + 1;
874		jiov[1].iov_base = alloca(jiov[1].iov_len);
875		strcpy(jiov[1].iov_base, pval);
876	} else {
877		j->jid = -1;
878		return;
879	}
880	j->jid = jail_get(jiov, 2, dflag ? JAIL_DYING : 0);
881}
882
883static void
884jail_quoted_warnx(const struct cfjail *j, const char *name_msg,
885    const char *noname_msg)
886{
887	const char *pval;
888
889	if ((pval = j->name) || (pval = string_param(j->intparams[KP_JID])) ||
890	    (pval = string_param(j->intparams[KP_NAME])))
891		warnx("\"%s\" %s", pval, name_msg);
892	else
893		warnx("%s", noname_msg);
894}
895
896/*
897 * Set jail parameters and possibly print them out.
898 */
899static int
900jailparam_set_note(const struct cfjail *j, struct jailparam *jp, unsigned njp,
901    int flags)
902{
903	char *value;
904	int jid;
905	unsigned i;
906
907	jid = jailparam_set(jp, njp, flags);
908	if (verbose > 0) {
909		jail_note(j, "jail_set(%s%s)",
910		    (flags & (JAIL_CREATE | JAIL_UPDATE)) == JAIL_CREATE
911		    ? "JAIL_CREATE" : "JAIL_UPDATE",
912		    (flags & JAIL_DYING) ? " | JAIL_DYING" : "");
913		for (i = 0; i < njp; i++) {
914			printf(" %s", jp[i].jp_name);
915			if (jp[i].jp_value == NULL)
916				continue;
917			putchar('=');
918			value = jailparam_export(jp + i);
919			if (value == NULL)
920				err(1, "jailparam_export");
921			quoted_print(stdout, value);
922			free(value);
923		}
924		if (jid < 0)
925			printf(": %s", strerror(errno));
926		printf("\n");
927	}
928	return jid;
929}
930
931/*
932 * Print a jail record.
933 */
934static void
935print_jail(FILE *fp, struct cfjail *j, int oldcl, int running)
936{
937	struct cfparam *p;
938	int printsep;
939
940	if (oldcl) {
941		if (running)
942			fprintf(fp, "%d%s", j->jid, separator);
943		print_param(fp, j->intparams[KP_PATH], ',', 0);
944		fputs(separator, fp);
945		print_param(fp, j->intparams[KP_HOST_HOSTNAME], ',', 0);
946		fputs(separator, fp);
947#ifdef INET
948		print_param(fp, j->intparams[KP_IP4_ADDR], ',', 0);
949#ifdef INET6
950		if (j->intparams[KP_IP4_ADDR] &&
951		    !TAILQ_EMPTY(&j->intparams[KP_IP4_ADDR]->val) &&
952		    j->intparams[KP_IP6_ADDR] &&
953		    !TAILQ_EMPTY(&j->intparams[KP_IP6_ADDR]->val))
954		    putc(',', fp);
955#endif
956#endif
957#ifdef INET6
958		print_param(fp, j->intparams[KP_IP6_ADDR], ',', 0);
959#endif
960		fputs(separator, fp);
961		print_param(fp, j->intparams[IP_COMMAND], ' ', 0);
962	} else {
963		printsep = 0;
964		if (running) {
965			fprintf(fp, "jid=%d", j->jid);
966			printsep = 1;
967		}
968		TAILQ_FOREACH(p, &j->params, tq)
969			if (strcmp(p->name, "jid")) {
970				if (printsep)
971					fputs(separator, fp);
972				else
973					printsep = 1;
974				print_param(fp, p, ',', 1);
975			}
976	}
977	putc('\n', fp);
978}
979
980/*
981 * Exhibit list of all configured non-wildcard jails
982 */
983static void
984show_jails(void)
985{
986	struct cfjail *j;
987
988	TAILQ_FOREACH(j, &cfjails, tq)
989		print_jail(stdout, j, 0, 0);
990}
991
992/*
993 * Print a parameter value, or a name=value pair.
994 */
995static void
996print_param(FILE *fp, const struct cfparam *p, int sep, int doname)
997{
998	const struct cfstring *s, *ts;
999
1000	if (doname)
1001		fputs(p->name, fp);
1002	if (p == NULL || TAILQ_EMPTY(&p->val))
1003		return;
1004	if (doname)
1005		putc('=', fp);
1006	TAILQ_FOREACH_SAFE(s, &p->val, tq, ts) {
1007		quoted_print(fp, s->s);
1008		if (ts != NULL)
1009			putc(sep, fp);
1010	}
1011}
1012
1013/*
1014 * Print a string with quotes around spaces.
1015 */
1016static void
1017quoted_print(FILE *fp, char *str)
1018{
1019	int c, qc;
1020	char *p = str;
1021
1022	qc = !*p ? '"'
1023	    : strchr(p, '\'') ? '"'
1024	    : strchr(p, '"') ? '\''
1025	    : strchr(p, ' ') || strchr(p, '\t') ? '"'
1026	    : 0;
1027	if (qc)
1028		putc(qc, fp);
1029	while ((c = *p++)) {
1030		if (c == '\\' || c == qc)
1031			putc('\\', fp);
1032		putc(c, fp);
1033	}
1034	if (qc)
1035		putc(qc, fp);
1036}
1037
1038static void
1039usage(void)
1040{
1041
1042	(void)fprintf(stderr,
1043	    "usage: jail [-dhilqv] [-J jid_file] [-u username] [-U username]\n"
1044	    "            -[cmr] param=value ... [command=command ...]\n"
1045	    "       jail [-dqv] [-f file] -[cmr] [jail]\n"
1046	    "       jail [-qv] [-f file] -[rR] ['*' | jail ...]\n"
1047	    "       jail [-dhilqv] [-J jid_file] [-u username] [-U username]\n"
1048	    "            [-n jailname] [-s securelevel]\n"
1049	    "            path hostname ip[,...] command ...\n"
1050	    "       jail [-f file] -e separator\n");
1051	exit(1);
1052}
1053