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