xref: /freebsd/usr.sbin/jail/config.c (revision e6bfd18d21b225af6a0ed67ceeaf1293b7b9eba5)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2011 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/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/types.h>
33 #include <sys/errno.h>
34 #include <sys/socket.h>
35 #include <sys/sysctl.h>
36 
37 #include <arpa/inet.h>
38 #include <netinet/in.h>
39 
40 #include <err.h>
41 #include <netdb.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 
47 #include "jailp.h"
48 
49 struct ipspec {
50 	const char	*name;
51 	unsigned	flags;
52 };
53 
54 extern int yylex_init_extra(struct cflex *extra, void *scanner);
55 extern int yylex_destroy(void *scanner);
56 extern int yyparse(void *scanner);
57 extern int yyset_in(FILE *fp, void *scanner);
58 
59 struct cfjails cfjails = TAILQ_HEAD_INITIALIZER(cfjails);
60 
61 static void free_param(struct cfparams *pp, struct cfparam *p);
62 static void free_param_strings(struct cfparam *p);
63 
64 static const struct ipspec intparams[] = {
65     [IP_ALLOW_DYING] =		{"allow.dying",		PF_INTERNAL | PF_BOOL},
66     [IP_COMMAND] =		{"command",		PF_INTERNAL},
67     [IP_DEPEND] =		{"depend",		PF_INTERNAL},
68     [IP_EXEC_CLEAN] =		{"exec.clean",		PF_INTERNAL | PF_BOOL},
69     [IP_EXEC_CONSOLELOG] =	{"exec.consolelog",	PF_INTERNAL},
70     [IP_EXEC_FIB] =		{"exec.fib",		PF_INTERNAL | PF_INT},
71     [IP_EXEC_JAIL_USER] =	{"exec.jail_user",	PF_INTERNAL},
72     [IP_EXEC_POSTSTART] =	{"exec.poststart",	PF_INTERNAL},
73     [IP_EXEC_POSTSTOP] =	{"exec.poststop",	PF_INTERNAL},
74     [IP_EXEC_PREPARE] =		{"exec.prepare",	PF_INTERNAL},
75     [IP_EXEC_PRESTART] =	{"exec.prestart",	PF_INTERNAL},
76     [IP_EXEC_PRESTOP] =		{"exec.prestop",	PF_INTERNAL},
77     [IP_EXEC_RELEASE] =		{"exec.release",	PF_INTERNAL},
78     [IP_EXEC_CREATED] =		{"exec.created",	PF_INTERNAL},
79     [IP_EXEC_START] =		{"exec.start",		PF_INTERNAL},
80     [IP_EXEC_STOP] =		{"exec.stop",		PF_INTERNAL},
81     [IP_EXEC_SYSTEM_JAIL_USER]=	{"exec.system_jail_user",
82 							PF_INTERNAL | PF_BOOL},
83     [IP_EXEC_SYSTEM_USER] =	{"exec.system_user",	PF_INTERNAL},
84     [IP_EXEC_TIMEOUT] =		{"exec.timeout",	PF_INTERNAL | PF_INT},
85 #if defined(INET) || defined(INET6)
86     [IP_INTERFACE] =		{"interface",		PF_INTERNAL},
87     [IP_IP_HOSTNAME] =		{"ip_hostname",		PF_INTERNAL | PF_BOOL},
88 #endif
89     [IP_MOUNT] =		{"mount",		PF_INTERNAL | PF_REV},
90     [IP_MOUNT_DEVFS] =		{"mount.devfs",		PF_INTERNAL | PF_BOOL},
91     [IP_MOUNT_FDESCFS] =	{"mount.fdescfs",	PF_INTERNAL | PF_BOOL},
92     [IP_MOUNT_PROCFS] =		{"mount.procfs",	PF_INTERNAL | PF_BOOL},
93     [IP_MOUNT_FSTAB] =		{"mount.fstab",		PF_INTERNAL},
94     [IP_STOP_TIMEOUT] =		{"stop.timeout",	PF_INTERNAL | PF_INT},
95     [IP_VNET_INTERFACE] =	{"vnet.interface",	PF_INTERNAL},
96 #ifdef INET
97     [IP__IP4_IFADDR] =		{"ip4.addr",	PF_INTERNAL | PF_CONV | PF_REV},
98 #endif
99 #ifdef INET6
100     [IP__IP6_IFADDR] =		{"ip6.addr",	PF_INTERNAL | PF_CONV | PF_REV},
101 #endif
102     [IP__MOUNT_FROM_FSTAB] =	{"mount.fstab",	PF_INTERNAL | PF_CONV | PF_REV},
103     [IP__OP] =			{NULL,			PF_CONV},
104     [KP_ALLOW_CHFLAGS] =	{"allow.chflags",	0},
105     [KP_ALLOW_MOUNT] =		{"allow.mount",		0},
106     [KP_ALLOW_RAW_SOCKETS] =	{"allow.raw_sockets",	0},
107     [KP_ALLOW_SET_HOSTNAME]=	{"allow.set_hostname",	0},
108     [KP_ALLOW_SOCKET_AF] =	{"allow.socket_af",	0},
109     [KP_ALLOW_SYSVIPC] =	{"allow.sysvipc",	0},
110     [KP_DEVFS_RULESET] =	{"devfs_ruleset",	0},
111     [KP_HOST_HOSTNAME] =	{"host.hostname",	0},
112 #ifdef INET
113     [KP_IP4_ADDR] =		{"ip4.addr",		0},
114 #endif
115 #ifdef INET6
116     [KP_IP6_ADDR] =		{"ip6.addr",		0},
117 #endif
118     [KP_JID] =			{"jid",			PF_IMMUTABLE},
119     [KP_NAME] =			{"name",		PF_IMMUTABLE},
120     [KP_PATH] =			{"path",		0},
121     [KP_PERSIST] =		{"persist",		0},
122     [KP_SECURELEVEL] =		{"securelevel",		0},
123     [KP_VNET] =			{"vnet",		0},
124 };
125 
126 /*
127  * Parse the jail configuration file.
128  */
129 void
130 load_config(const char *cfname)
131 {
132 	struct cfjails wild;
133 	struct cfparams opp;
134 	struct cfjail *j, *tj, *wj;
135 	struct cfparam *p, *vp, *tp;
136 	struct cfstring *s, *vs, *ns;
137 	struct cfvar *v, *vv;
138 	struct cflex cflex;
139 	char *ep;
140 	void *scanner;
141 	int did_self, jseq, pgen;
142 
143 	cflex.cfname = cfname;
144 	cflex.error = 0;
145 	yylex_init_extra(&cflex, &scanner);
146 	if (!strcmp(cfname, "-")) {
147 		cflex.cfname = "STDIN";
148 		yyset_in(stdin, scanner);
149 	} else {
150 		FILE *yfp = fopen(cfname, "r");
151 		if (!yfp)
152 			err(1, "%s", cfname);
153 		yyset_in(yfp, scanner);
154 	}
155 	if (yyparse(scanner) || cflex.error)
156 		exit(1);
157 	yylex_destroy(scanner);
158 
159 	/* Separate the wildcard jails out from the actual jails. */
160 	jseq = 0;
161 	TAILQ_INIT(&wild);
162 	TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) {
163 		j->seq = ++jseq;
164 		if (wild_jail_name(j->name))
165 			requeue(j, &wild);
166 	}
167 
168 	TAILQ_FOREACH(j, &cfjails, tq) {
169 		/* Set aside the jail's parameters. */
170 		TAILQ_INIT(&opp);
171 		TAILQ_CONCAT(&opp, &j->params, tq);
172 		/*
173 		 * The jail name implies its "name" or "jid" parameter,
174 		 * though they may also be explicitly set later on.
175 		 */
176 		add_param(j, NULL,
177 		    strtol(j->name, &ep, 10) && !*ep ? KP_JID : KP_NAME,
178 		    j->name);
179 		/*
180 		 * Collect parameters for the jail, global parameters/variables,
181 		 * and any matching wildcard jails.
182 		 */
183 		did_self = 0;
184 		TAILQ_FOREACH(wj, &wild, tq) {
185 			if (j->seq < wj->seq && !did_self) {
186 				TAILQ_FOREACH(p, &opp, tq)
187 					add_param(j, p, 0, NULL);
188 				did_self = 1;
189 			}
190 			if (wild_jail_match(j->name, wj->name))
191 				TAILQ_FOREACH(p, &wj->params, tq)
192 					add_param(j, p, 0, NULL);
193 		}
194 		if (!did_self)
195 			TAILQ_FOREACH(p, &opp, tq)
196 				add_param(j, p, 0, NULL);
197 
198 		/* Resolve any variable substitutions. */
199 		pgen = 0;
200 		TAILQ_FOREACH(p, &j->params, tq) {
201 		    p->gen = ++pgen;
202 		find_vars:
203 		    TAILQ_FOREACH(s, &p->val, tq) {
204 			while ((v = STAILQ_FIRST(&s->vars))) {
205 				TAILQ_FOREACH(vp, &j->params, tq)
206 					if (!strcmp(vp->name, v->name))
207 						break;
208 				if (!vp || TAILQ_EMPTY(&vp->val)) {
209 					jail_warnx(j,
210 					    "%s: variable \"%s\" not found",
211 					    p->name, v->name);
212 				bad_var:
213 					j->flags |= JF_FAILED;
214 					TAILQ_FOREACH(vp, &j->params, tq)
215 						if (vp->gen == pgen)
216 							vp->flags |= PF_BAD;
217 					goto free_var;
218 				}
219 				if (vp->flags & PF_BAD)
220 					goto bad_var;
221 				if (vp->gen == pgen) {
222 					jail_warnx(j, "%s: variable loop",
223 					    v->name);
224 					goto bad_var;
225 				}
226 				TAILQ_FOREACH(vs, &vp->val, tq)
227 					if (!STAILQ_EMPTY(&vs->vars)) {
228 						vp->gen = pgen;
229 						TAILQ_REMOVE(&j->params, vp,
230 						    tq);
231 						TAILQ_INSERT_BEFORE(p, vp, tq);
232 						p = vp;
233 						goto find_vars;
234 					}
235 				vs = TAILQ_FIRST(&vp->val);
236 				if (TAILQ_NEXT(vs, tq) != NULL &&
237 				    (s->s[0] != '\0' ||
238 				     STAILQ_NEXT(v, tq))) {
239 					jail_warnx(j, "%s: array cannot be "
240 					    "substituted inline",
241 					    p->name);
242 					goto bad_var;
243 				}
244 				s->s = erealloc(s->s, s->len + vs->len + 1);
245 				memmove(s->s + v->pos + vs->len,
246 				    s->s + v->pos,
247 				    s->len - v->pos + 1);
248 				memcpy(s->s + v->pos, vs->s, vs->len);
249 				vv = v;
250 				while ((vv = STAILQ_NEXT(vv, tq)))
251 					vv->pos += vs->len;
252 				s->len += vs->len;
253 				while ((vs = TAILQ_NEXT(vs, tq))) {
254 					ns = emalloc(sizeof(struct cfstring));
255 					ns->s = estrdup(vs->s);
256 					ns->len = vs->len;
257 					STAILQ_INIT(&ns->vars);
258 					TAILQ_INSERT_AFTER(&p->val, s, ns, tq);
259 					s = ns;
260 				}
261 			free_var:
262 				free(v->name);
263 				STAILQ_REMOVE_HEAD(&s->vars, tq);
264 				free(v);
265 			}
266 		    }
267 		}
268 
269 		/* Free the jail's original parameter list and any variables. */
270 		while ((p = TAILQ_FIRST(&opp)))
271 			free_param(&opp, p);
272 		TAILQ_FOREACH_SAFE(p, &j->params, tq, tp)
273 			if (p->flags & PF_VAR)
274 				free_param(&j->params, p);
275 	}
276 	while ((wj = TAILQ_FIRST(&wild))) {
277 		free(wj->name);
278 		while ((p = TAILQ_FIRST(&wj->params)))
279 			free_param(&wj->params, p);
280 		TAILQ_REMOVE(&wild, wj, tq);
281 	}
282 }
283 
284 /*
285  * Create a new jail record.
286  */
287 struct cfjail *
288 add_jail(void)
289 {
290 	struct cfjail *j;
291 
292 	j = emalloc(sizeof(struct cfjail));
293 	memset(j, 0, sizeof(struct cfjail));
294 	TAILQ_INIT(&j->params);
295 	STAILQ_INIT(&j->dep[DEP_FROM]);
296 	STAILQ_INIT(&j->dep[DEP_TO]);
297 	j->queue = &cfjails;
298 	TAILQ_INSERT_TAIL(&cfjails, j, tq);
299 	return j;
300 }
301 
302 /*
303  * Add a parameter to a jail.
304  */
305 void
306 add_param(struct cfjail *j, const struct cfparam *p, enum intparam ipnum,
307     const char *value)
308 {
309 	struct cfstrings nss;
310 	struct cfparam *dp, *np;
311 	struct cfstring *s, *ns;
312 	struct cfvar *v, *nv;
313 	const char *name;
314 	char *cs, *tname;
315 	unsigned flags;
316 
317 	if (j == NULL) {
318 		/* Create a single anonymous jail if one doesn't yet exist. */
319 		j = TAILQ_LAST(&cfjails, cfjails);
320 		if (j == NULL)
321 			j = add_jail();
322 	}
323 	TAILQ_INIT(&nss);
324 	if (p != NULL) {
325 		name = p->name;
326 		flags = p->flags;
327 		/*
328 		 * Make a copy of the parameter's string list,
329 		 * which may be freed if it's overridden later.
330 		 */
331 		TAILQ_FOREACH(s, &p->val, tq) {
332 			ns = emalloc(sizeof(struct cfstring));
333 			ns->s = estrdup(s->s);
334 			ns->len = s->len;
335 			STAILQ_INIT(&ns->vars);
336 			STAILQ_FOREACH(v, &s->vars, tq) {
337 				nv = emalloc(sizeof(struct cfvar));
338 				nv->name = strdup(v->name);
339 				nv->pos = v->pos;
340 				STAILQ_INSERT_TAIL(&ns->vars, nv, tq);
341 			}
342 			TAILQ_INSERT_TAIL(&nss, ns, tq);
343 		}
344 	} else {
345 		flags = PF_APPEND;
346 		if (ipnum != IP__NULL) {
347 			name = intparams[ipnum].name;
348 			flags |= intparams[ipnum].flags;
349 		} else if ((cs = strchr(value, '='))) {
350 			tname = alloca(cs - value + 1);
351 			strlcpy(tname, value, cs - value + 1);
352 			name = tname;
353 			value = cs + 1;
354 		} else {
355 			name = value;
356 			value = NULL;
357 		}
358 		if (value != NULL) {
359 			ns = emalloc(sizeof(struct cfstring));
360 			ns->s = estrdup(value);
361 			ns->len = strlen(value);
362 			STAILQ_INIT(&ns->vars);
363 			TAILQ_INSERT_TAIL(&nss, ns, tq);
364 		}
365 	}
366 
367 	/* See if this parameter has already been added. */
368 	if (ipnum != IP__NULL)
369 		dp = j->intparams[ipnum];
370 	else
371 		TAILQ_FOREACH(dp, &j->params, tq)
372 			if (!(dp->flags & PF_CONV) && equalopts(dp->name, name))
373 				break;
374 	if (dp != NULL) {
375 		/* Found it - append or replace. */
376 		if ((flags ^ dp->flags) & PF_VAR) {
377 			jail_warnx(j, "variable \"$%s\" cannot have the same "
378 			    "name as a parameter.", name);
379 			j->flags |= JF_FAILED;
380 			return;
381 		}
382 		if (dp->flags & PF_IMMUTABLE) {
383 			jail_warnx(j, "cannot redefine parameter \"%s\".",
384 			    dp->name);
385 			j->flags |= JF_FAILED;
386 			return;
387 		}
388 		if (strcmp(dp->name, name)) {
389 			free(dp->name);
390 			dp->name = estrdup(name);
391 		}
392 		if (!(flags & PF_APPEND) || TAILQ_EMPTY(&nss))
393 			free_param_strings(dp);
394 		TAILQ_CONCAT(&dp->val, &nss, tq);
395 		dp->flags |= flags;
396 	} else {
397 		/* Not found - add it. */
398 		np = emalloc(sizeof(struct cfparam));
399 		np->name = estrdup(name);
400 		TAILQ_INIT(&np->val);
401 		TAILQ_CONCAT(&np->val, &nss, tq);
402 		np->flags = flags;
403 		np->gen = 0;
404 		TAILQ_INSERT_TAIL(&j->params, np, tq);
405 		if (ipnum != IP__NULL)
406 			j->intparams[ipnum] = np;
407 		else
408 			for (ipnum = IP__NULL + 1; ipnum < IP_NPARAM; ipnum++)
409 				if (!(intparams[ipnum].flags & PF_CONV) &&
410 				    equalopts(name, intparams[ipnum].name)) {
411 					if (flags & PF_VAR) {
412 						jail_warnx(j,
413 						    "variable \"$%s\" "
414 						    "cannot have the same "
415 						    "name as a parameter.",
416 						    name);
417 						j->flags |= JF_FAILED;
418 						return;
419 					}
420 					j->intparams[ipnum] = np;
421 					np->flags |= intparams[ipnum].flags;
422 					break;
423 				}
424 	}
425 }
426 
427 /*
428  * Return if a boolean parameter exists and is true.
429  */
430 int
431 bool_param(const struct cfparam *p)
432 {
433 	const char *cs;
434 
435 	if (p == NULL)
436 		return 0;
437 	cs = strrchr(p->name, '.');
438 	return !strncmp(cs ? cs + 1 : p->name, "no", 2) ^
439 	    (TAILQ_EMPTY(&p->val) ||
440 	     !strcasecmp(TAILQ_LAST(&p->val, cfstrings)->s, "true") ||
441 	     (strtol(TAILQ_LAST(&p->val, cfstrings)->s, NULL, 10)));
442 }
443 
444 /*
445  * Set an integer if a parameter if it exists.
446  */
447 int
448 int_param(const struct cfparam *p, int *ip)
449 {
450 	if (p == NULL || TAILQ_EMPTY(&p->val))
451 		return 0;
452 	*ip = strtol(TAILQ_LAST(&p->val, cfstrings)->s, NULL, 10);
453 	return 1;
454 }
455 
456 /*
457  * Return the string value of a scalar parameter if it exists.
458  */
459 const char *
460 string_param(const struct cfparam *p)
461 {
462 	return (p && !TAILQ_EMPTY(&p->val)
463 	    ? TAILQ_LAST(&p->val, cfstrings)->s : NULL);
464 }
465 
466 /*
467  * Check syntax and values of internal parameters.  Set some internal
468  * parameters based on the values of others.
469  */
470 int
471 check_intparams(struct cfjail *j)
472 {
473 	struct cfparam *p;
474 	struct cfstring *s;
475 	FILE *f;
476 	const char *val;
477 	char *cs, *ep, *ln;
478 	size_t lnlen;
479 	int error;
480 #if defined(INET) || defined(INET6)
481 	struct addrinfo hints;
482 	struct addrinfo *ai0, *ai;
483 	const char *hostname;
484 	int gicode, defif;
485 #endif
486 #ifdef INET
487 	struct in_addr addr4;
488 	int ip4ok;
489 	char avalue4[INET_ADDRSTRLEN];
490 #endif
491 #ifdef INET6
492 	struct in6_addr addr6;
493 	int ip6ok;
494 	char avalue6[INET6_ADDRSTRLEN];
495 #endif
496 
497 	error = 0;
498 	/* Check format of boolan and integer values. */
499 	TAILQ_FOREACH(p, &j->params, tq) {
500 		if (!TAILQ_EMPTY(&p->val) && (p->flags & (PF_BOOL | PF_INT))) {
501 			val = TAILQ_LAST(&p->val, cfstrings)->s;
502 			if (p->flags & PF_BOOL) {
503 				if (strcasecmp(val, "false") &&
504 				    strcasecmp(val, "true") &&
505 				    ((void)strtol(val, &ep, 10), *ep)) {
506 					jail_warnx(j,
507 					    "%s: unknown boolean value \"%s\"",
508 					    p->name, val);
509 					error = -1;
510 				}
511 			} else {
512 				(void)strtol(val, &ep, 10);
513 				if (ep == val || *ep) {
514 					jail_warnx(j,
515 					    "%s: non-integer value \"%s\"",
516 					    p->name, val);
517 					error = -1;
518 				}
519 			}
520 		}
521 	}
522 
523 #if defined(INET) || defined(INET6)
524 	/*
525 	 * The ip_hostname parameter looks up the hostname, and adds parameters
526 	 * for any IP addresses it finds.
527 	 */
528 	if (((j->flags & JF_OP_MASK) != JF_STOP ||
529 	    j->intparams[IP_INTERFACE] != NULL) &&
530 	    bool_param(j->intparams[IP_IP_HOSTNAME]) &&
531 	    (hostname = string_param(j->intparams[KP_HOST_HOSTNAME]))) {
532 		j->intparams[IP_IP_HOSTNAME] = NULL;
533 		/*
534 		 * Silently ignore unsupported address families from
535 		 * DNS lookups.
536 		 */
537 #ifdef INET
538 		ip4ok = feature_present("inet");
539 #endif
540 #ifdef INET6
541 		ip6ok = feature_present("inet6");
542 #endif
543 		if (
544 #if defined(INET) && defined(INET6)
545 		    ip4ok || ip6ok
546 #elif defined(INET)
547 		    ip4ok
548 #elif defined(INET6)
549 		    ip6ok
550 #endif
551 			 ) {
552 			/* Look up the hostname (or get the address) */
553 			memset(&hints, 0, sizeof(hints));
554 			hints.ai_socktype = SOCK_STREAM;
555 			hints.ai_family =
556 #if defined(INET) && defined(INET6)
557 			    ip4ok ? (ip6ok ? PF_UNSPEC : PF_INET) :  PF_INET6;
558 #elif defined(INET)
559 			    PF_INET;
560 #elif defined(INET6)
561 			    PF_INET6;
562 #endif
563 			gicode = getaddrinfo(hostname, NULL, &hints, &ai0);
564 			if (gicode != 0) {
565 				jail_warnx(j, "host.hostname %s: %s", hostname,
566 				    gai_strerror(gicode));
567 				error = -1;
568 			} else {
569 				/*
570 				 * Convert the addresses to ASCII so jailparam
571 				 * can convert them back.  Errors are not
572 				 * expected here.
573 				 */
574 				for (ai = ai0; ai; ai = ai->ai_next)
575 					switch (ai->ai_family) {
576 #ifdef INET
577 					case AF_INET:
578 						memcpy(&addr4,
579 						    &((struct sockaddr_in *)
580 						    (void *)ai->ai_addr)->
581 						    sin_addr, sizeof(addr4));
582 						if (inet_ntop(AF_INET,
583 						    &addr4, avalue4,
584 						    INET_ADDRSTRLEN) == NULL)
585 							err(1, "inet_ntop");
586 						add_param(j, NULL, KP_IP4_ADDR,
587 						    avalue4);
588 						break;
589 #endif
590 #ifdef INET6
591 					case AF_INET6:
592 						memcpy(&addr6,
593 						    &((struct sockaddr_in6 *)
594 						    (void *)ai->ai_addr)->
595 						    sin6_addr, sizeof(addr6));
596 						if (inet_ntop(AF_INET6,
597 						    &addr6, avalue6,
598 						    INET6_ADDRSTRLEN) == NULL)
599 							err(1, "inet_ntop");
600 						add_param(j, NULL, KP_IP6_ADDR,
601 						    avalue6);
602 						break;
603 #endif
604 					}
605 				freeaddrinfo(ai0);
606 			}
607 		}
608 	}
609 
610 	/*
611 	 * IP addresses may include an interface to set that address on,
612 	 * a netmask/suffix for that address and options for ifconfig.
613 	 * These are copied to an internal command parameter and then stripped
614 	 * so they won't be passed on to jailparam_set.
615 	 */
616 	defif = string_param(j->intparams[IP_INTERFACE]) != NULL;
617 #ifdef INET
618 	if (j->intparams[KP_IP4_ADDR] != NULL) {
619 		TAILQ_FOREACH(s, &j->intparams[KP_IP4_ADDR]->val, tq) {
620 			cs = strchr(s->s, '|');
621 			if (cs || defif)
622 				add_param(j, NULL, IP__IP4_IFADDR, s->s);
623 			if (cs) {
624 				s->len -= cs + 1 - s->s;
625 				memmove(s->s, cs + 1, s->len + 1);
626 			}
627 			if ((cs = strchr(s->s, '/')) != NULL) {
628 				*cs = '\0';
629 				s->len = cs - s->s;
630 			}
631 			if ((cs = strchr(s->s, ' ')) != NULL) {
632 				*cs = '\0';
633 				s->len = cs - s->s;
634 			}
635 		}
636 	}
637 #endif
638 #ifdef INET6
639 	if (j->intparams[KP_IP6_ADDR] != NULL) {
640 		TAILQ_FOREACH(s, &j->intparams[KP_IP6_ADDR]->val, tq) {
641 			cs = strchr(s->s, '|');
642 			if (cs || defif)
643 				add_param(j, NULL, IP__IP6_IFADDR, s->s);
644 			if (cs) {
645 				s->len -= cs + 1 - s->s;
646 				memmove(s->s, cs + 1, s->len + 1);
647 			}
648 			if ((cs = strchr(s->s, '/')) != NULL) {
649 				*cs = '\0';
650 				s->len = cs - s->s;
651 			}
652 			if ((cs = strchr(s->s, ' ')) != NULL) {
653 				*cs = '\0';
654 				s->len = cs - s->s;
655 			}
656 		}
657 	}
658 #endif
659 #endif
660 
661 	/*
662 	 * Read mount.fstab file(s), and treat each line as its own mount
663 	 * parameter.
664 	 */
665 	if (j->intparams[IP_MOUNT_FSTAB] != NULL) {
666 		TAILQ_FOREACH(s, &j->intparams[IP_MOUNT_FSTAB]->val, tq) {
667 			if (s->len == 0)
668 				continue;
669 			f = fopen(s->s, "r");
670 			if (f == NULL) {
671 				jail_warnx(j, "mount.fstab: %s: %s",
672 				    s->s, strerror(errno));
673 				error = -1;
674 				continue;
675 			}
676 			while ((ln = fgetln(f, &lnlen))) {
677 				if ((cs = memchr(ln, '#', lnlen - 1)))
678 					lnlen = cs - ln + 1;
679 				if (ln[lnlen - 1] == '\n' ||
680 				    ln[lnlen - 1] == '#')
681 					ln[lnlen - 1] = '\0';
682 				else {
683 					cs = alloca(lnlen + 1);
684 					strlcpy(cs, ln, lnlen + 1);
685 					ln = cs;
686 				}
687 				add_param(j, NULL, IP__MOUNT_FROM_FSTAB, ln);
688 			}
689 			fclose(f);
690 		}
691 	}
692 	if (error)
693 		failed(j);
694 	return error;
695 }
696 
697 /*
698  * Import parameters into libjail's binary jailparam format.
699  */
700 int
701 import_params(struct cfjail *j)
702 {
703 	struct cfparam *p;
704 	struct cfstring *s, *ts;
705 	struct jailparam *jp;
706 	char *value, *cs;
707 	size_t vallen;
708 	int error;
709 
710 	error = 0;
711 	j->njp = 0;
712 	TAILQ_FOREACH(p, &j->params, tq)
713 		if (!(p->flags & PF_INTERNAL))
714 			j->njp++;
715 	j->jp = jp = emalloc(j->njp * sizeof(struct jailparam));
716 	TAILQ_FOREACH(p, &j->params, tq) {
717 		if (p->flags & PF_INTERNAL)
718 			continue;
719 		if (jailparam_init(jp, p->name) < 0) {
720 			error = -1;
721 			jail_warnx(j, "%s", jail_errmsg);
722 			jp++;
723 			continue;
724 		}
725 		if (TAILQ_EMPTY(&p->val))
726 			value = NULL;
727 		else if (!jp->jp_elemlen ||
728 			 !TAILQ_NEXT(TAILQ_FIRST(&p->val), tq)) {
729 			/*
730 			 * Scalar parameters silently discard multiple (array)
731 			 * values, keeping only the last value added.  This
732 			 * lets values added from the command line append to
733 			 * arrays wthout pre-checking the type.
734 			 */
735 			value = TAILQ_LAST(&p->val, cfstrings)->s;
736 		} else {
737 			/*
738 			 * Convert arrays into comma-separated strings, which
739 			 * jailparam_import will then convert back into arrays.
740 			 */
741 			vallen = 0;
742 			TAILQ_FOREACH(s, &p->val, tq)
743 				vallen += s->len + 1;
744 			value = alloca(vallen);
745 			cs = value;
746 			TAILQ_FOREACH_SAFE(s, &p->val, tq, ts) {
747 				memcpy(cs, s->s, s->len);
748 				cs += s->len + 1;
749 				cs[-1] = ',';
750 			}
751 			value[vallen - 1] = '\0';
752 		}
753 		if (jailparam_import(jp, value) < 0) {
754 			error = -1;
755 			jail_warnx(j, "%s", jail_errmsg);
756 		}
757 		jp++;
758 	}
759 	if (error) {
760 		jailparam_free(j->jp, j->njp);
761 		free(j->jp);
762 		j->jp = NULL;
763 		failed(j);
764 	}
765 	return error;
766 }
767 
768 /*
769  * Check if options are equal (with or without the "no" prefix).
770  */
771 int
772 equalopts(const char *opt1, const char *opt2)
773 {
774 	char *p;
775 
776 	/* "opt" vs. "opt" or "noopt" vs. "noopt" */
777 	if (strcmp(opt1, opt2) == 0)
778 		return (1);
779 	/* "noopt" vs. "opt" */
780 	if (strncmp(opt1, "no", 2) == 0 && strcmp(opt1 + 2, opt2) == 0)
781 		return (1);
782 	/* "opt" vs. "noopt" */
783 	if (strncmp(opt2, "no", 2) == 0 && strcmp(opt1, opt2 + 2) == 0)
784 		return (1);
785 	while ((p = strchr(opt1, '.')) != NULL &&
786 	    !strncmp(opt1, opt2, ++p - opt1)) {
787 		opt2 += p - opt1;
788 		opt1 = p;
789 		/* "foo.noopt" vs. "foo.opt" */
790 		if (strncmp(opt1, "no", 2) == 0 && strcmp(opt1 + 2, opt2) == 0)
791 			return (1);
792 		/* "foo.opt" vs. "foo.noopt" */
793 		if (strncmp(opt2, "no", 2) == 0 && strcmp(opt1, opt2 + 2) == 0)
794 			return (1);
795 	}
796 	return (0);
797 }
798 
799 /*
800  * See if a jail name matches a wildcard.
801  */
802 int
803 wild_jail_match(const char *jname, const char *wname)
804 {
805 	const char *jc, *jd, *wc, *wd;
806 
807 	/*
808 	 * A non-final "*" component in the wild name matches a single jail
809 	 * component, and a final "*" matches one or more jail components.
810 	 */
811 	for (jc = jname, wc = wname;
812 	     (jd = strchr(jc, '.')) && (wd = strchr(wc, '.'));
813 	     jc = jd + 1, wc = wd + 1)
814 		if (strncmp(jc, wc, jd - jc + 1) && strncmp(wc, "*.", 2))
815 			return 0;
816 	return (!strcmp(jc, wc) || !strcmp(wc, "*"));
817 }
818 
819 /*
820  * Return if a jail name is a wildcard.
821  */
822 int
823 wild_jail_name(const char *wname)
824 {
825 	const char *wc;
826 
827 	for (wc = strchr(wname, '*'); wc; wc = strchr(wc + 1, '*'))
828 		if ((wc == wname || wc[-1] == '.') &&
829 		    (wc[1] == '\0' || wc[1] == '.'))
830 			return 1;
831 	return 0;
832 }
833 
834 /*
835  * Free a parameter record and all its strings and variables.
836  */
837 static void
838 free_param(struct cfparams *pp, struct cfparam *p)
839 {
840 	free(p->name);
841 	free_param_strings(p);
842 	TAILQ_REMOVE(pp, p, tq);
843 	free(p);
844 }
845 
846 static void
847 free_param_strings(struct cfparam *p)
848 {
849 	struct cfstring *s;
850 	struct cfvar *v;
851 
852 	while ((s = TAILQ_FIRST(&p->val))) {
853 		free(s->s);
854 		while ((v = STAILQ_FIRST(&s->vars))) {
855 			free(v->name);
856 			STAILQ_REMOVE_HEAD(&s->vars, tq);
857 			free(v);
858 		}
859 		TAILQ_REMOVE(&p->val, s, tq);
860 		free(s);
861 	}
862 }
863