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