1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2009 James Gritton.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/param.h>
30#include <sys/jail.h>
31#include <sys/linker.h>
32#include <sys/socket.h>
33#include <sys/sysctl.h>
34
35#include <arpa/inet.h>
36#include <netinet/in.h>
37
38#include <errno.h>
39#include <inttypes.h>
40#include <stdio.h>
41#include <stdarg.h>
42#include <stdlib.h>
43#include <string.h>
44
45#include "jail.h"
46
47#define	SJPARAM		"security.jail.param"
48
49#define JPS_IN_ADDR	1
50#define JPS_IN6_ADDR	2
51
52#define ARRAY_SANITY	5
53#define ARRAY_SLOP	5
54
55
56static int jailparam_import_enum(const char **values, int nvalues,
57    const char *valstr, size_t valsize, int *value);
58static int jailparam_type(struct jailparam *jp);
59static int kldload_param(const char *name);
60static char *noname(const char *name);
61static char *nononame(const char *name);
62
63char jail_errmsg[JAIL_ERRMSGLEN];
64
65static const char *bool_values[] = { "false", "true" };
66static const char *jailsys_values[] = { "disable", "new", "inherit" };
67
68
69/*
70 * Import a null-terminated parameter list and set a jail with the flags
71 * and parameters.
72 */
73int
74jail_setv(int flags, ...)
75{
76	va_list ap, tap;
77	struct jailparam *jp;
78	const char *name, *value;
79	int njp, jid;
80
81	/* Create the parameter list and import the parameters. */
82	va_start(ap, flags);
83	va_copy(tap, ap);
84	for (njp = 0; va_arg(tap, char *) != NULL; njp++)
85		(void)va_arg(tap, char *);
86	va_end(tap);
87	jp = alloca(njp * sizeof(struct jailparam));
88	for (njp = 0; (name = va_arg(ap, char *)) != NULL;) {
89		value = va_arg(ap, char *);
90		if (jailparam_init(jp + njp, name) < 0)
91			goto error;
92		if (jailparam_import(jp + njp++, value) < 0)
93			goto error;
94	}
95	va_end(ap);
96	jid = jailparam_set(jp, njp, flags);
97	jailparam_free(jp, njp);
98	return (jid);
99
100 error:
101	jailparam_free(jp, njp);
102	va_end(ap);
103	return (-1);
104}
105
106/*
107 * Read a null-terminated parameter list, get the referenced jail, and export
108 * the parameters to the list.
109 */
110int
111jail_getv(int flags, ...)
112{
113	va_list ap, tap;
114	struct jailparam *jp, *jp_lastjid, *jp_jid, *jp_name, *jp_key;
115	char *valarg, *value;
116	const char *name, *key_value, *lastjid_value, *jid_value, *name_value;
117	int njp, i, jid;
118
119	/* Create the parameter list and find the key. */
120	va_start(ap, flags);
121	va_copy(tap, ap);
122	for (njp = 0; va_arg(tap, char *) != NULL; njp++)
123		(void)va_arg(tap, char *);
124	va_end(tap);
125
126	jp = alloca(njp * sizeof(struct jailparam));
127	va_copy(tap, ap);
128	jp_lastjid = jp_jid = jp_name = NULL;
129	lastjid_value = jid_value = name_value = NULL;
130	for (njp = 0; (name = va_arg(tap, char *)) != NULL; njp++) {
131		value = va_arg(tap, char *);
132		if (jailparam_init(jp + njp, name) < 0) {
133			va_end(tap);
134			goto error;
135		}
136		if (!strcmp(jp[njp].jp_name, "lastjid")) {
137			jp_lastjid = jp + njp;
138			lastjid_value = value;
139		} else if (!strcmp(jp[njp].jp_name, "jid")) {
140			jp_jid = jp + njp;
141			jid_value = value;
142		} if (!strcmp(jp[njp].jp_name, "name")) {
143			jp_name = jp + njp;
144			name_value = value;
145		}
146	}
147	va_end(tap);
148	/* Import the key parameter. */
149	if (jp_lastjid != NULL) {
150		jp_key = jp_lastjid;
151		key_value = lastjid_value;
152	} else if (jp_jid != NULL && strtol(jid_value, NULL, 10) != 0) {
153		jp_key = jp_jid;
154		key_value = jid_value;
155	} else if (jp_name != NULL) {
156		jp_key = jp_name;
157		key_value = name_value;
158	} else {
159		strlcpy(jail_errmsg, "no jail specified", JAIL_ERRMSGLEN);
160		errno = ENOENT;
161		goto error;
162	}
163	if (jailparam_import(jp_key, key_value) < 0)
164		goto error;
165	/* Get the jail and export the parameters. */
166	jid = jailparam_get(jp, njp, flags);
167	if (jid < 0)
168		goto error;
169	for (i = 0; i < njp; i++) {
170		(void)va_arg(ap, char *);
171		valarg = va_arg(ap, char *);
172		if (jp + i != jp_key) {
173			/* It's up to the caller to ensure there's room. */
174			if ((jp[i].jp_ctltype & CTLTYPE) == CTLTYPE_STRING)
175				strcpy(valarg, jp[i].jp_value);
176			else {
177				value = jailparam_export(jp + i);
178				if (value == NULL)
179					goto error;
180				strcpy(valarg, value);
181				free(value);
182			}
183		}
184	}
185	jailparam_free(jp, njp);
186	va_end(ap);
187	return (jid);
188
189 error:
190	jailparam_free(jp, njp);
191	va_end(ap);
192	return (-1);
193}
194
195/*
196 * Return a list of all known parameters.
197 */
198int
199jailparam_all(struct jailparam **jpp)
200{
201	struct jailparam *jp, *tjp;
202	size_t mlen1, mlen2, buflen;
203	unsigned njp, nlist;
204	int mib1[CTL_MAXNAME], mib2[CTL_MAXNAME - 2];
205	char buf[MAXPATHLEN];
206
207	njp = 0;
208	nlist = 32;
209	jp = malloc(nlist * sizeof(*jp));
210	if (jp == NULL) {
211		strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
212		return (-1);
213	}
214	mib1[0] = 0;
215	mib1[1] = 2;
216	mlen1 = CTL_MAXNAME - 2;
217	if (sysctlnametomib(SJPARAM, mib1 + 2, &mlen1) < 0) {
218		snprintf(jail_errmsg, JAIL_ERRMSGLEN,
219		    "sysctlnametomib(" SJPARAM "): %s", strerror(errno));
220		goto error;
221	}
222	for (;; njp++) {
223		/* Get the next parameter. */
224		mlen2 = sizeof(mib2);
225		if (sysctl(mib1, mlen1 + 2, mib2, &mlen2, NULL, 0) < 0) {
226			if (errno == ENOENT) {
227				/* No more entries. */
228				break;
229			}
230			snprintf(jail_errmsg, JAIL_ERRMSGLEN,
231			    "sysctl(0.2): %s", strerror(errno));
232			goto error;
233		}
234		if (mib2[0] != mib1[2] ||
235		    mib2[1] != mib1[3] ||
236		    mib2[2] != mib1[4])
237			break;
238		/* Convert it to an ascii name. */
239		memcpy(mib1 + 2, mib2, mlen2);
240		mlen1 = mlen2 / sizeof(int);
241		mib1[1] = 1;
242		buflen = sizeof(buf);
243		if (sysctl(mib1, mlen1 + 2, buf, &buflen, NULL, 0) < 0) {
244			snprintf(jail_errmsg, JAIL_ERRMSGLEN,
245			    "sysctl(0.1): %s", strerror(errno));
246			goto error;
247		}
248		if (buf[buflen - 2] == '.')
249			buf[buflen - 2] = '\0';
250		/* Add the parameter to the list */
251		if (njp >= nlist) {
252			nlist *= 2;
253			tjp = reallocarray(jp, nlist, sizeof(*jp));
254			if (tjp == NULL)
255				goto error;
256			jp = tjp;
257		}
258		if (jailparam_init(jp + njp, buf + sizeof(SJPARAM)) < 0)
259			goto error;
260		mib1[1] = 2;
261	}
262	/* Just return the untrimmed buffer if reallocarray() somehow fails. */
263	tjp = reallocarray(jp, njp, sizeof(*jp));
264	if (tjp != NULL)
265		jp = tjp;
266	*jpp = jp;
267	return (njp);
268
269 error:
270	jailparam_free(jp, njp);
271	free(jp);
272	return (-1);
273}
274
275/*
276 * Clear a jail parameter and copy in its name.
277 */
278int
279jailparam_init(struct jailparam *jp, const char *name)
280{
281
282	memset(jp, 0, sizeof(*jp));
283	jp->jp_name = strdup(name);
284	if (jp->jp_name == NULL) {
285		strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
286		return (-1);
287	}
288	if (jailparam_type(jp) < 0) {
289		jailparam_free(jp, 1);
290		jp->jp_name = NULL;
291		jp->jp_value = NULL;
292		return (-1);
293	}
294	return (0);
295}
296
297/*
298 * Put a name and value into a jail parameter element, converting the value
299 * to internal form.
300 */
301int
302jailparam_import(struct jailparam *jp, const char *value)
303{
304	char *p, *ep, *tvalue;
305	const char *avalue;
306	int i, nval, fw;
307
308	if (value == NULL)
309		return (0);
310	if ((jp->jp_ctltype & CTLTYPE) == CTLTYPE_STRING) {
311		jp->jp_value = strdup(value);
312		if (jp->jp_value == NULL) {
313			strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
314			return (-1);
315		}
316		return (0);
317	}
318	nval = 1;
319	if (jp->jp_elemlen) {
320		if (value[0] == '\0' || (value[0] == '-' && value[1] == '\0')) {
321			jp->jp_value = strdup("");
322			if (jp->jp_value == NULL) {
323				strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
324				return (-1);
325			}
326			jp->jp_valuelen = 0;
327			return (0);
328		}
329		for (p = strchr(value, ','); p; p = strchr(p + 1, ','))
330			nval++;
331		jp->jp_valuelen = jp->jp_elemlen * nval;
332	}
333	jp->jp_value = malloc(jp->jp_valuelen);
334	if (jp->jp_value == NULL) {
335		strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
336		return (-1);
337	}
338	avalue = value;
339	for (i = 0; i < nval; i++) {
340		fw = nval == 1 ? strlen(avalue) : strcspn(avalue, ",");
341		switch (jp->jp_ctltype & CTLTYPE) {
342		case CTLTYPE_INT:
343			if (jp->jp_flags & (JP_BOOL | JP_NOBOOL)) {
344				if (!jailparam_import_enum(bool_values, 2,
345				    avalue, fw, &((int *)jp->jp_value)[i])) {
346					snprintf(jail_errmsg,
347					    JAIL_ERRMSGLEN, "%s: "
348					    "unknown boolean value \"%.*s\"",
349					    jp->jp_name, fw, avalue);
350					errno = EINVAL;
351					goto error;
352				}
353				break;
354			}
355			if (jp->jp_flags & JP_JAILSYS) {
356				/*
357				 * Allow setting a jailsys parameter to "new"
358				 * in a booleanesque fashion.
359				 */
360				if (value[0] == '\0')
361					((int *)jp->jp_value)[i] = JAIL_SYS_NEW;
362				else if (!jailparam_import_enum(jailsys_values,
363				    sizeof(jailsys_values) /
364				    sizeof(jailsys_values[0]), avalue, fw,
365				    &((int *)jp->jp_value)[i])) {
366					snprintf(jail_errmsg,
367					    JAIL_ERRMSGLEN, "%s: "
368					    "unknown jailsys value \"%.*s\"",
369					    jp->jp_name, fw, avalue);
370					errno = EINVAL;
371					goto error;
372				}
373				break;
374			}
375			((int *)jp->jp_value)[i] = strtol(avalue, &ep, 10);
376		integer_test:
377			if (ep != avalue + fw) {
378				snprintf(jail_errmsg, JAIL_ERRMSGLEN,
379				    "%s: non-integer value \"%.*s\"",
380				    jp->jp_name, fw, avalue);
381				errno = EINVAL;
382				goto error;
383			}
384			break;
385		case CTLTYPE_UINT:
386			((unsigned *)jp->jp_value)[i] =
387			    strtoul(avalue, &ep, 10);
388			goto integer_test;
389		case CTLTYPE_LONG:
390			((long *)jp->jp_value)[i] = strtol(avalue, &ep, 10);
391			goto integer_test;
392		case CTLTYPE_ULONG:
393			((unsigned long *)jp->jp_value)[i] =
394			    strtoul(avalue, &ep, 10);
395			goto integer_test;
396		case CTLTYPE_S64:
397			((int64_t *)jp->jp_value)[i] =
398			    strtoimax(avalue, &ep, 10);
399			goto integer_test;
400		case CTLTYPE_U64:
401			((uint64_t *)jp->jp_value)[i] =
402			    strtoumax(avalue, &ep, 10);
403			goto integer_test;
404		case CTLTYPE_STRUCT:
405			tvalue = alloca(fw + 1);
406			strlcpy(tvalue, avalue, fw + 1);
407			switch (jp->jp_structtype) {
408			case JPS_IN_ADDR:
409				if (inet_pton(AF_INET, tvalue,
410				    &((struct in_addr *)jp->jp_value)[i]) != 1)
411				{
412					snprintf(jail_errmsg,
413					    JAIL_ERRMSGLEN,
414					    "%s: not an IPv4 address: %s",
415					    jp->jp_name, tvalue);
416					errno = EINVAL;
417					goto error;
418				}
419				break;
420			case JPS_IN6_ADDR:
421				if (inet_pton(AF_INET6, tvalue,
422				    &((struct in6_addr *)jp->jp_value)[i]) != 1)
423				{
424					snprintf(jail_errmsg,
425					    JAIL_ERRMSGLEN,
426					    "%s: not an IPv6 address: %s",
427					    jp->jp_name, tvalue);
428					errno = EINVAL;
429					goto error;
430				}
431				break;
432			default:
433				goto unknown_type;
434			}
435			break;
436		default:
437		unknown_type:
438			snprintf(jail_errmsg, JAIL_ERRMSGLEN,
439			    "unknown type for %s", jp->jp_name);
440			errno = ENOENT;
441			goto error;
442		}
443		avalue += fw + 1;
444	}
445	return (0);
446
447 error:
448	free(jp->jp_value);
449	jp->jp_value = NULL;
450	return (-1);
451}
452
453static int
454jailparam_import_enum(const char **values, int nvalues, const char *valstr,
455    size_t valsize, int *value)
456{
457	char *ep;
458	int i;
459
460	for (i = 0; i < nvalues; i++)
461		if (valsize == strlen(values[i]) &&
462		    !strncasecmp(valstr, values[i], valsize)) {
463			*value = i;
464			return 1;
465		}
466	*value = strtol(valstr, &ep, 10);
467	return (ep == valstr + valsize);
468}
469
470/*
471 * Put a name and value into a jail parameter element, copying the value
472 * but not altering it.
473 */
474int
475jailparam_import_raw(struct jailparam *jp, void *value, size_t valuelen)
476{
477
478	jp->jp_value = value;
479	jp->jp_valuelen = valuelen;
480	jp->jp_flags |= JP_RAWVALUE;
481	return (0);
482}
483
484/*
485 * Run the jail_set and jail_get system calls on a parameter list.
486 */
487int
488jailparam_set(struct jailparam *jp, unsigned njp, int flags)
489{
490	struct iovec *jiov;
491	char *nname;
492	int i, jid, bool0;
493	unsigned j;
494
495	jiov = alloca(sizeof(struct iovec) * 2 * (njp + 1));
496	bool0 = 0;
497	for (i = j = 0; j < njp; j++) {
498		jiov[i].iov_base = jp[j].jp_name;
499		jiov[i].iov_len = strlen(jp[j].jp_name) + 1;
500		i++;
501		if (jp[j].jp_flags & (JP_BOOL | JP_NOBOOL)) {
502			/*
503			 * Set booleans without values.  If one has a value of
504			 * zero, change it to (or from) its "no" counterpart.
505			 */
506			jiov[i].iov_base = NULL;
507			jiov[i].iov_len = 0;
508			if (jp[j].jp_value != NULL &&
509			    jp[j].jp_valuelen == sizeof(int) &&
510			    !*(int *)jp[j].jp_value) {
511				bool0 = 1;
512				nname = jp[j].jp_flags & JP_BOOL
513				    ? noname(jp[j].jp_name)
514				    : nononame(jp[j].jp_name);
515				if (nname == NULL) {
516					njp = j;
517					jid = -1;
518					goto done;
519				}
520				jiov[i - 1].iov_base = nname;
521				jiov[i - 1].iov_len = strlen(nname) + 1;
522
523			}
524		} else {
525			/*
526			 * Try to fill in missing values with an empty string.
527			 */
528			if (jp[j].jp_value == NULL && jp[j].jp_valuelen > 0 &&
529			    jailparam_import(jp + j, "") < 0) {
530				njp = j;
531				jid = -1;
532				goto done;
533			}
534			jiov[i].iov_base = jp[j].jp_value;
535			jiov[i].iov_len =
536			    (jp[j].jp_ctltype & CTLTYPE) == CTLTYPE_STRING
537			    ? strlen(jp[j].jp_value) + 1
538			    : jp[j].jp_valuelen;
539		}
540		i++;
541	}
542	jiov[i].iov_base = __DECONST(char *, "errmsg");
543	jiov[i].iov_len = sizeof("errmsg");
544	i++;
545	jiov[i].iov_base = jail_errmsg;
546	jiov[i].iov_len = JAIL_ERRMSGLEN;
547	i++;
548	jail_errmsg[0] = 0;
549	jid = jail_set(jiov, i, flags);
550	if (jid < 0 && !jail_errmsg[0])
551		snprintf(jail_errmsg, sizeof(jail_errmsg), "jail_set: %s",
552		    strerror(errno));
553 done:
554	if (bool0)
555		for (j = 0; j < njp; j++)
556			if ((jp[j].jp_flags & (JP_BOOL | JP_NOBOOL)) &&
557			    jp[j].jp_value != NULL &&
558			    jp[j].jp_valuelen == sizeof(int) &&
559			    !*(int *)jp[j].jp_value)
560				free(jiov[j * 2].iov_base);
561	return (jid);
562}
563
564int
565jailparam_get(struct jailparam *jp, unsigned njp, int flags)
566{
567	struct iovec *jiov;
568	struct jailparam *jp_lastjid, *jp_jid, *jp_name, *jp_key;
569	int i, ai, ki, jid, arrays, sanity;
570	unsigned j;
571
572	/*
573	 * Get the types for all parameters.
574	 * Find the key and any array parameters.
575	 */
576	jiov = alloca(sizeof(struct iovec) * 2 * (njp + 1));
577	jp_lastjid = jp_jid = jp_name = NULL;
578	arrays = 0;
579	for (ai = j = 0; j < njp; j++) {
580		if (!strcmp(jp[j].jp_name, "lastjid"))
581			jp_lastjid = jp + j;
582		else if (!strcmp(jp[j].jp_name, "jid"))
583			jp_jid = jp + j;
584		else if (!strcmp(jp[j].jp_name, "name"))
585			jp_name = jp + j;
586		else if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) {
587			arrays = 1;
588			jiov[ai].iov_base = jp[j].jp_name;
589			jiov[ai].iov_len = strlen(jp[j].jp_name) + 1;
590			ai++;
591			jiov[ai].iov_base = NULL;
592			jiov[ai].iov_len = 0;
593			ai++;
594		}
595	}
596	jp_key = jp_lastjid ? jp_lastjid :
597	    jp_jid && jp_jid->jp_valuelen == sizeof(int) &&
598	    jp_jid->jp_value && *(int *)jp_jid->jp_value ? jp_jid : jp_name;
599	if (jp_key == NULL || jp_key->jp_value == NULL) {
600		strlcpy(jail_errmsg, "no jail specified", JAIL_ERRMSGLEN);
601		errno = ENOENT;
602		return (-1);
603	}
604	ki = ai;
605	jiov[ki].iov_base = jp_key->jp_name;
606	jiov[ki].iov_len = strlen(jp_key->jp_name) + 1;
607	ki++;
608	jiov[ki].iov_base = jp_key->jp_value;
609	jiov[ki].iov_len = (jp_key->jp_ctltype & CTLTYPE) == CTLTYPE_STRING
610	    ? strlen(jp_key->jp_value) + 1 : jp_key->jp_valuelen;
611	ki++;
612	jiov[ki].iov_base = __DECONST(char *, "errmsg");
613	jiov[ki].iov_len = sizeof("errmsg");
614	ki++;
615	jiov[ki].iov_base = jail_errmsg;
616	jiov[ki].iov_len = JAIL_ERRMSGLEN;
617	ki++;
618	jail_errmsg[0] = 0;
619	if (arrays && jail_get(jiov, ki, flags) < 0) {
620		if (!jail_errmsg[0])
621			snprintf(jail_errmsg, sizeof(jail_errmsg),
622			    "jail_get: %s", strerror(errno));
623		return (-1);
624	}
625	/* Allocate storage for all parameters. */
626	for (ai = j = 0, i = ki; j < njp; j++) {
627		if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) {
628			ai++;
629			jiov[ai].iov_len += jp[j].jp_elemlen * ARRAY_SLOP;
630			if (jp[j].jp_valuelen >= jiov[ai].iov_len)
631				jiov[ai].iov_len = jp[j].jp_valuelen;
632			else {
633				jp[j].jp_valuelen = jiov[ai].iov_len;
634				if (jp[j].jp_value != NULL)
635					free(jp[j].jp_value);
636				jp[j].jp_value = malloc(jp[j].jp_valuelen);
637				if (jp[j].jp_value == NULL) {
638					strerror_r(errno, jail_errmsg,
639					    JAIL_ERRMSGLEN);
640					return (-1);
641				}
642			}
643			jiov[ai].iov_base = jp[j].jp_value;
644			memset(jiov[ai].iov_base, 0, jiov[ai].iov_len);
645			ai++;
646		} else if (jp + j != jp_key) {
647			jiov[i].iov_base = jp[j].jp_name;
648			jiov[i].iov_len = strlen(jp[j].jp_name) + 1;
649			i++;
650			if (jp[j].jp_value == NULL &&
651			    !(jp[j].jp_flags & JP_RAWVALUE)) {
652				jp[j].jp_value = malloc(jp[j].jp_valuelen);
653				if (jp[j].jp_value == NULL) {
654					strerror_r(errno, jail_errmsg,
655					    JAIL_ERRMSGLEN);
656					return (-1);
657				}
658			}
659			jiov[i].iov_base = jp[j].jp_value;
660			jiov[i].iov_len = jp[j].jp_valuelen;
661			memset(jiov[i].iov_base, 0, jiov[i].iov_len);
662			i++;
663		}
664	}
665	/*
666	 * Get the prison.  If there are array elements, retry a few times
667	 * in case their sizes changed from under us.
668	 */
669	for (sanity = 0;; sanity++) {
670		jid = jail_get(jiov, i, flags);
671		if (jid >= 0 || !arrays || sanity == ARRAY_SANITY ||
672		    errno != EINVAL || jail_errmsg[0])
673			break;
674		for (ai = j = 0; j < njp; j++) {
675			if (jp[j].jp_elemlen &&
676			    !(jp[j].jp_flags & JP_RAWVALUE)) {
677				ai++;
678				jiov[ai].iov_base = NULL;
679				jiov[ai].iov_len = 0;
680				ai++;
681			}
682		}
683		if (jail_get(jiov, ki, flags) < 0)
684			break;
685		for (ai = j = 0; j < njp; j++) {
686			if (jp[j].jp_elemlen &&
687			    !(jp[j].jp_flags & JP_RAWVALUE)) {
688				ai++;
689				jiov[ai].iov_len +=
690				    jp[j].jp_elemlen * ARRAY_SLOP;
691				if (jp[j].jp_valuelen >= jiov[ai].iov_len)
692					jiov[ai].iov_len = jp[j].jp_valuelen;
693				else {
694					jp[j].jp_valuelen = jiov[ai].iov_len;
695					if (jp[j].jp_value != NULL)
696						free(jp[j].jp_value);
697					jp[j].jp_value =
698					    malloc(jiov[ai].iov_len);
699					if (jp[j].jp_value == NULL) {
700						strerror_r(errno, jail_errmsg,
701						    JAIL_ERRMSGLEN);
702						return (-1);
703					}
704				}
705				jiov[ai].iov_base = jp[j].jp_value;
706				memset(jiov[ai].iov_base, 0, jiov[ai].iov_len);
707				ai++;
708			}
709		}
710	}
711	if (jid < 0 && !jail_errmsg[0])
712		snprintf(jail_errmsg, sizeof(jail_errmsg),
713		    "jail_get: %s", strerror(errno));
714	for (ai = j = 0, i = ki; j < njp; j++) {
715		if (jp[j].jp_elemlen && !(jp[j].jp_flags & JP_RAWVALUE)) {
716			ai++;
717			jp[j].jp_valuelen = jiov[ai].iov_len;
718			ai++;
719		} else if (jp + j != jp_key) {
720			i++;
721			jp[j].jp_valuelen = jiov[i].iov_len;
722			i++;
723		}
724	}
725	return (jid);
726}
727
728/*
729 * Convert a jail parameter's value to external form.
730 */
731char *
732jailparam_export(struct jailparam *jp)
733{
734	size_t *valuelens;
735	char *value, *tvalue, **values;
736	size_t valuelen;
737	int i, nval, ival;
738	char valbuf[INET6_ADDRSTRLEN];
739
740	if (jp->jp_value == NULL) {
741		snprintf(jail_errmsg, JAIL_ERRMSGLEN,
742		    "parameter %s was not imported", jp->jp_name);
743		errno = EINVAL;
744		return (NULL);
745	}
746	if ((jp->jp_ctltype & CTLTYPE) == CTLTYPE_STRING) {
747		value = strdup(jp->jp_value);
748		if (value == NULL)
749			strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
750		return (value);
751	}
752	nval = jp->jp_elemlen ? jp->jp_valuelen / jp->jp_elemlen : 1;
753	if (nval == 0) {
754		value = strdup("");
755		if (value == NULL)
756			strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
757		return (value);
758	}
759	values = alloca(nval * sizeof(char *));
760	valuelens = alloca(nval * sizeof(size_t));
761	valuelen = 0;
762	for (i = 0; i < nval; i++) {
763		switch (jp->jp_ctltype & CTLTYPE) {
764		case CTLTYPE_INT:
765			ival = ((int *)jp->jp_value)[i];
766			if ((jp->jp_flags & (JP_BOOL | JP_NOBOOL)) &&
767			    (unsigned)ival < 2) {
768				strlcpy(valbuf, bool_values[ival],
769				    sizeof(valbuf));
770				break;
771			}
772			if ((jp->jp_flags & JP_JAILSYS) &&
773			    (unsigned)ival < sizeof(jailsys_values) /
774			    sizeof(jailsys_values[0])) {
775				strlcpy(valbuf, jailsys_values[ival],
776				    sizeof(valbuf));
777				break;
778			}
779			snprintf(valbuf, sizeof(valbuf), "%d", ival);
780			break;
781		case CTLTYPE_UINT:
782			snprintf(valbuf, sizeof(valbuf), "%u",
783			    ((unsigned *)jp->jp_value)[i]);
784			break;
785		case CTLTYPE_LONG:
786			snprintf(valbuf, sizeof(valbuf), "%ld",
787			    ((long *)jp->jp_value)[i]);
788			break;
789		case CTLTYPE_ULONG:
790			snprintf(valbuf, sizeof(valbuf), "%lu",
791			    ((unsigned long *)jp->jp_value)[i]);
792			break;
793		case CTLTYPE_S64:
794			snprintf(valbuf, sizeof(valbuf), "%jd",
795			    (intmax_t)((int64_t *)jp->jp_value)[i]);
796			break;
797		case CTLTYPE_U64:
798			snprintf(valbuf, sizeof(valbuf), "%ju",
799			    (uintmax_t)((uint64_t *)jp->jp_value)[i]);
800			break;
801		case CTLTYPE_STRUCT:
802			switch (jp->jp_structtype) {
803			case JPS_IN_ADDR:
804				if (inet_ntop(AF_INET,
805				    &((struct in_addr *)jp->jp_value)[i],
806				    valbuf, sizeof(valbuf)) == NULL) {
807					strerror_r(errno, jail_errmsg,
808					    JAIL_ERRMSGLEN);
809					return (NULL);
810				}
811				break;
812			case JPS_IN6_ADDR:
813				if (inet_ntop(AF_INET6,
814				    &((struct in6_addr *)jp->jp_value)[i],
815				    valbuf, sizeof(valbuf)) == NULL) {
816					strerror_r(errno, jail_errmsg,
817					    JAIL_ERRMSGLEN);
818					return (NULL);
819				}
820				break;
821			default:
822				goto unknown_type;
823			}
824			break;
825		default:
826		unknown_type:
827			snprintf(jail_errmsg, JAIL_ERRMSGLEN,
828			    "unknown type for %s", jp->jp_name);
829			errno = ENOENT;
830			return (NULL);
831		}
832		valuelens[i] = strlen(valbuf) + 1;
833		valuelen += valuelens[i];
834		values[i] = alloca(valuelens[i]);
835		strcpy(values[i], valbuf);
836	}
837	value = malloc(valuelen);
838	if (value == NULL)
839		strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
840	else {
841		tvalue = value;
842		for (i = 0; i < nval; i++) {
843			strcpy(tvalue, values[i]);
844			if (i < nval - 1) {
845				tvalue += valuelens[i];
846				tvalue[-1] = ',';
847			}
848		}
849	}
850	return (value);
851}
852
853/*
854 * Free the contents of a jail parameter list (but not the list itself).
855 */
856void
857jailparam_free(struct jailparam *jp, unsigned njp)
858{
859	unsigned j;
860
861	for (j = 0; j < njp; j++) {
862		free(jp[j].jp_name);
863		if (!(jp[j].jp_flags & JP_RAWVALUE))
864			free(jp[j].jp_value);
865	}
866}
867
868/*
869 * Find a parameter's type and size from its MIB.
870 */
871static int
872jailparam_type(struct jailparam *jp)
873{
874	char *p, *name, *nname;
875	size_t miblen, desclen;
876	int i, isarray;
877	struct {
878	    int i;
879	    char s[MAXPATHLEN];
880	} desc;
881	int mib[CTL_MAXNAME];
882
883	/* The "lastjid" parameter isn't real. */
884	name = jp->jp_name;
885	if (!strcmp(name, "lastjid")) {
886		jp->jp_valuelen = sizeof(int);
887		jp->jp_ctltype = CTLTYPE_INT | CTLFLAG_WR;
888		return (0);
889	}
890
891	/* Find the sysctl that describes the parameter. */
892	mib[0] = 0;
893	mib[1] = 3;
894	snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", name);
895	miblen = sizeof(mib) - 2 * sizeof(int);
896	if (sysctl(mib, 2, mib + 2, &miblen, desc.s, strlen(desc.s)) < 0) {
897		if (errno != ENOENT) {
898			snprintf(jail_errmsg, JAIL_ERRMSGLEN,
899			    "sysctl(0.3.%s): %s", name, strerror(errno));
900			return (-1);
901		}
902		if (kldload_param(name) >= 0 && sysctl(mib, 2, mib + 2, &miblen,
903		    desc.s, strlen(desc.s)) >= 0)
904			goto mib_desc;
905		/*
906		 * The parameter probably doesn't exist.  But it might be
907		 * the "no" counterpart to a boolean.
908		 */
909		nname = nononame(name);
910		if (nname == NULL) {
911		unknown_parameter:
912			snprintf(jail_errmsg, JAIL_ERRMSGLEN,
913			    "unknown parameter: %s", jp->jp_name);
914			errno = ENOENT;
915			return (-1);
916		}
917		name = alloca(strlen(nname) + 1);
918		strcpy(name, nname);
919		free(nname);
920		snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", name);
921		miblen = sizeof(mib) - 2 * sizeof(int);
922		if (sysctl(mib, 2, mib + 2, &miblen, desc.s,
923		    strlen(desc.s)) < 0)
924			goto unknown_parameter;
925		jp->jp_flags |= JP_NOBOOL;
926	}
927 mib_desc:
928	mib[1] = 4;
929	desclen = sizeof(desc);
930	if (sysctl(mib, (miblen / sizeof(int)) + 2, &desc, &desclen,
931	    NULL, 0) < 0) {
932		snprintf(jail_errmsg, JAIL_ERRMSGLEN,
933		    "sysctl(0.4.%s): %s", name, strerror(errno));
934		return (-1);
935	}
936	jp->jp_ctltype = desc.i;
937	/* If this came from removing a "no", it better be a boolean. */
938	if (jp->jp_flags & JP_NOBOOL) {
939		if ((desc.i & CTLTYPE) == CTLTYPE_INT && desc.s[0] == 'B') {
940			jp->jp_valuelen = sizeof(int);
941			return (0);
942		}
943		else if ((desc.i & CTLTYPE) != CTLTYPE_NODE)
944			goto unknown_parameter;
945	}
946	/* See if this is an array type. */
947	p = strchr(desc.s, '\0');
948	isarray  = 0;
949	if (p - 2 < desc.s || strcmp(p - 2, ",a"))
950		isarray = 0;
951	else {
952		isarray = 1;
953		p[-2] = 0;
954	}
955	/* Look for types we understand. */
956	switch (desc.i & CTLTYPE) {
957	case CTLTYPE_INT:
958		if (desc.s[0] == 'B')
959			jp->jp_flags |= JP_BOOL;
960		else if (!strcmp(desc.s, "E,jailsys"))
961			jp->jp_flags |= JP_JAILSYS;
962	case CTLTYPE_UINT:
963		jp->jp_valuelen = sizeof(int);
964		break;
965	case CTLTYPE_LONG:
966	case CTLTYPE_ULONG:
967		jp->jp_valuelen = sizeof(long);
968		break;
969	case CTLTYPE_S64:
970	case CTLTYPE_U64:
971		jp->jp_valuelen = sizeof(int64_t);
972		break;
973	case CTLTYPE_STRING:
974		desc.s[0] = 0;
975		desclen = sizeof(desc.s);
976		if (sysctl(mib + 2, miblen / sizeof(int), desc.s, &desclen,
977		    NULL, 0) < 0) {
978			snprintf(jail_errmsg, JAIL_ERRMSGLEN,
979			    "sysctl(" SJPARAM ".%s): %s", name,
980			    strerror(errno));
981			return (-1);
982		}
983		jp->jp_valuelen = strtoul(desc.s, NULL, 10);
984		break;
985	case CTLTYPE_STRUCT:
986		if (!strcmp(desc.s, "S,in_addr")) {
987			jp->jp_structtype = JPS_IN_ADDR;
988			jp->jp_valuelen = sizeof(struct in_addr);
989		} else if (!strcmp(desc.s, "S,in6_addr")) {
990			jp->jp_structtype = JPS_IN6_ADDR;
991			jp->jp_valuelen = sizeof(struct in6_addr);
992		} else {
993			desclen = 0;
994			if (sysctl(mib + 2, miblen / sizeof(int),
995			    NULL, &jp->jp_valuelen, NULL, 0) < 0) {
996				snprintf(jail_errmsg, JAIL_ERRMSGLEN,
997				    "sysctl(" SJPARAM ".%s): %s", name,
998				    strerror(errno));
999				return (-1);
1000			}
1001		}
1002		break;
1003	case CTLTYPE_NODE:
1004		/*
1005		 * A node might be described by an empty-named child,
1006		 * which would be immediately before or after the node itself.
1007		 */
1008		mib[1] = 1;
1009		miblen += sizeof(int);
1010		for (i = -1; i <= 1; i += 2) {
1011			mib[(miblen / sizeof(int)) + 1] =
1012			    mib[(miblen / sizeof(int))] + i;
1013			desclen = sizeof(desc.s);
1014			if (sysctl(mib, (miblen / sizeof(int)) + 2, desc.s,
1015			    &desclen, NULL, 0) < 0) {
1016				if (errno == ENOENT)
1017					continue;
1018				snprintf(jail_errmsg, JAIL_ERRMSGLEN,
1019				    "sysctl(0.1): %s", strerror(errno));
1020				return (-1);
1021			}
1022			if (desclen == sizeof(SJPARAM) + strlen(name) + 2 &&
1023			    memcmp(SJPARAM ".", desc.s, sizeof(SJPARAM)) == 0 &&
1024			    memcmp(name, desc.s + sizeof(SJPARAM),
1025			    desclen - sizeof(SJPARAM) - 2) == 0 &&
1026			    desc.s[desclen - 2] == '.')
1027				goto mib_desc;
1028		}
1029		goto unknown_parameter;
1030	default:
1031		snprintf(jail_errmsg, JAIL_ERRMSGLEN,
1032		    "unknown type for %s", jp->jp_name);
1033		errno = ENOENT;
1034		return (-1);
1035	}
1036	if (isarray) {
1037		jp->jp_elemlen = jp->jp_valuelen;
1038		jp->jp_valuelen = 0;
1039	}
1040	return (0);
1041}
1042
1043/*
1044 * Attempt to load a kernel module matching an otherwise nonexistent parameter.
1045 */
1046static int
1047kldload_param(const char *name)
1048{
1049	int kl;
1050
1051	if (strcmp(name, "linux") == 0 || strncmp(name, "linux.", 6) == 0)
1052		kl = kldload("linux");
1053	else if (strcmp(name, "sysvmsg") == 0 || strcmp(name, "sysvsem") == 0 ||
1054	    strcmp(name, "sysvshm") == 0)
1055		kl = kldload(name);
1056	else if (strncmp(name, "allow.mount.", 12) == 0) {
1057		/* Load the matching filesystem */
1058		const char *modname = name + 12;
1059
1060		kl = kldload(modname);
1061		if (kl < 0 && errno == ENOENT &&
1062		    strncmp(modname, "no", 2) == 0)
1063			kl = kldload(modname + 2);
1064	} else {
1065		errno = ENOENT;
1066		return (-1);
1067	}
1068	if (kl < 0 && errno == EEXIST) {
1069		/*
1070		 * In the module is already loaded, then it must not contain
1071		 * the parameter.
1072		 */
1073		errno = ENOENT;
1074	}
1075	return kl;
1076}
1077
1078/*
1079 * Change a boolean parameter name into its "no" counterpart or vice versa.
1080 */
1081static char *
1082noname(const char *name)
1083{
1084	char *nname, *p;
1085
1086	nname = malloc(strlen(name) + 3);
1087	if (nname == NULL) {
1088		strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
1089		return (NULL);
1090	}
1091	p = strrchr(name, '.');
1092	if (p != NULL)
1093		sprintf(nname, "%.*s.no%s", (int)(p - name), name, p + 1);
1094	else
1095		sprintf(nname, "no%s", name);
1096	return (nname);
1097}
1098
1099static char *
1100nononame(const char *name)
1101{
1102	char *p, *nname;
1103
1104	p = strrchr(name, '.');
1105	if (strncmp(p ? p + 1 : name, "no", 2)) {
1106		snprintf(jail_errmsg, sizeof(jail_errmsg),
1107		    "mismatched boolean: %s", name);
1108		errno = EINVAL;
1109		return (NULL);
1110	}
1111	nname = malloc(strlen(name) - 1);
1112	if (nname == NULL) {
1113		strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
1114		return (NULL);
1115	}
1116	if (p != NULL)
1117		sprintf(nname, "%.*s.%s", (int)(p - name), name, p + 3);
1118	else
1119		strcpy(nname, name + 2);
1120	return (nname);
1121}
1122