config.c revision 256387
1139743Simp/*-
239212Sgibbs * Copyright (c) 2011 James Gritton
339212Sgibbs * All rights reserved.
439212Sgibbs *
539212Sgibbs * Redistribution and use in source and binary forms, with or without
639212Sgibbs * modification, are permitted provided that the following conditions
739212Sgibbs * are met:
839212Sgibbs * 1. Redistributions of source code must retain the above copyright
939212Sgibbs *    notice, this list of conditions and the following disclaimer.
1039212Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
1139212Sgibbs *    notice, this list of conditions and the following disclaimer in the
1239212Sgibbs *    documentation and/or other materials provided with the distribution.
1339212Sgibbs *
1439212Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1539212Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1639212Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1739212Sgibbs * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1839212Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1939212Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2039212Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2139212Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2239212Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2339212Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2439212Sgibbs * SUCH DAMAGE.
2539212Sgibbs */
2639212Sgibbs
2739212Sgibbs#include <sys/cdefs.h>
2850477Speter__FBSDID("$FreeBSD: stable/10/usr.sbin/jail/config.c 256387 2013-10-12 17:46:13Z hrs $");
2939212Sgibbs
3039212Sgibbs#include <sys/types.h>
3139212Sgibbs#include <sys/errno.h>
3239212Sgibbs#include <sys/socket.h>
3339212Sgibbs#include <sys/sysctl.h>
3439212Sgibbs
3539212Sgibbs#include <arpa/inet.h>
3647412Sgibbs#include <netinet/in.h>
37114216Skan
3855206Speter#include <err.h>
3939212Sgibbs#include <netdb.h>
4039212Sgibbs#include <stdio.h>
4139212Sgibbs#include <stdlib.h>
4239212Sgibbs#include <string.h>
43195534Sscottl#include <unistd.h>
4439212Sgibbs
4539212Sgibbs#include "jailp.h"
4639212Sgibbs
4739212Sgibbsstruct ipspec {
4839212Sgibbs	const char	*name;
4939212Sgibbs	unsigned	flags;
5039212Sgibbs};
5139212Sgibbs
5239212Sgibbsextern FILE *yyin;
5339212Sgibbsextern int yynerrs;
5439212Sgibbs
5539212Sgibbsextern int yyparse(void);
5639212Sgibbs
5739212Sgibbsstruct cfjails cfjails = TAILQ_HEAD_INITIALIZER(cfjails);
5839212Sgibbs
5939212Sgibbsstatic void free_param(struct cfparams *pp, struct cfparam *p);
6039212Sgibbsstatic void free_param_strings(struct cfparam *p);
6139212Sgibbs
6263455Sgibbsstatic const struct ipspec intparams[] = {
6363455Sgibbs    [IP_ALLOW_DYING] =		{"allow.dying",		PF_INTERNAL | PF_BOOL},
6463455Sgibbs    [IP_COMMAND] =		{"command",		PF_INTERNAL},
6563455Sgibbs    [IP_DEPEND] =		{"depend",		PF_INTERNAL},
66246713Skib    [IP_EXEC_CLEAN] =		{"exec.clean",		PF_INTERNAL | PF_BOOL},
6739212Sgibbs    [IP_EXEC_CONSOLELOG] =	{"exec.consolelog",	PF_INTERNAL},
68216088Sken    [IP_EXEC_FIB] =		{"exec.fib",		PF_INTERNAL | PF_INT},
6939212Sgibbs    [IP_EXEC_JAIL_USER] =	{"exec.jail_user",	PF_INTERNAL},
7039212Sgibbs    [IP_EXEC_POSTSTART] =	{"exec.poststart",	PF_INTERNAL},
7139212Sgibbs    [IP_EXEC_POSTSTOP] =	{"exec.poststop",	PF_INTERNAL},
7239212Sgibbs    [IP_EXEC_PRESTART] =	{"exec.prestart",	PF_INTERNAL},
73246713Skib    [IP_EXEC_PRESTOP] =		{"exec.prestop",	PF_INTERNAL},
74246713Skib    [IP_EXEC_START] =		{"exec.start",		PF_INTERNAL},
75246713Skib    [IP_EXEC_STOP] =		{"exec.stop",		PF_INTERNAL},
76246713Skib    [IP_EXEC_SYSTEM_JAIL_USER]=	{"exec.system_jail_user",
77246713Skib							PF_INTERNAL | PF_BOOL},
78246713Skib    [IP_EXEC_SYSTEM_USER] =	{"exec.system_user",	PF_INTERNAL},
7939212Sgibbs    [IP_EXEC_TIMEOUT] =		{"exec.timeout",	PF_INTERNAL | PF_INT},
8039212Sgibbs#if defined(INET) || defined(INET6)
8139212Sgibbs    [IP_INTERFACE] =		{"interface",		PF_INTERNAL},
8239212Sgibbs    [IP_IP_HOSTNAME] =		{"ip_hostname",		PF_INTERNAL | PF_BOOL},
8339212Sgibbs#endif
8439212Sgibbs    [IP_MOUNT] =		{"mount",		PF_INTERNAL | PF_REV},
8539212Sgibbs    [IP_MOUNT_DEVFS] =		{"mount.devfs",		PF_INTERNAL | PF_BOOL},
8639212Sgibbs    [IP_MOUNT_FDESCFS] =	{"mount.fdescfs",	PF_INTERNAL | PF_BOOL},
8739212Sgibbs    [IP_MOUNT_FSTAB] =		{"mount.fstab",		PF_INTERNAL},
8839212Sgibbs    [IP_STOP_TIMEOUT] =		{"stop.timeout",	PF_INTERNAL | PF_INT},
8939212Sgibbs    [IP_VNET_INTERFACE] =	{"vnet.interface",	PF_INTERNAL},
9039212Sgibbs#ifdef INET
9139212Sgibbs    [IP__IP4_IFADDR] =		{"ip4.addr",	PF_INTERNAL | PF_CONV | PF_REV},
9239212Sgibbs#endif
9339212Sgibbs#ifdef INET6
9439212Sgibbs    [IP__IP6_IFADDR] =		{"ip6.addr",	PF_INTERNAL | PF_CONV | PF_REV},
9558111Sn_hibma#endif
9639212Sgibbs    [IP__MOUNT_FROM_FSTAB] =	{"mount.fstab",	PF_INTERNAL | PF_CONV | PF_REV},
9739212Sgibbs    [IP__OP] =			{NULL,			PF_CONV},
9839212Sgibbs    [KP_ALLOW_CHFLAGS] =	{"allow.chflags",	0},
9956145Smjacob    [KP_ALLOW_MOUNT] =		{"allow.mount",		0},
10056145Smjacob    [KP_ALLOW_RAW_SOCKETS] =	{"allow.raw_sockets",	0},
10156145Smjacob    [KP_ALLOW_SET_HOSTNAME]=	{"allow.set_hostname",	0},
102248520Skib    [KP_ALLOW_SOCKET_AF] =	{"allow.socket_af",	0},
10339212Sgibbs    [KP_ALLOW_SYSVIPC] =	{"allow.sysvipc",	0},
10456145Smjacob    [KP_DEVFS_RULESET] =	{"devfs_ruleset",	0},
10556145Smjacob    [KP_ENFORCE_STATFS] =	{"enforce_statfs",	0},
10656145Smjacob    [KP_HOST_HOSTNAME] =	{"host.hostname",	0},
107260387Sscottl#ifdef INET
108260387Sscottl    [KP_IP4_ADDR] =		{"ip4.addr",		0},
109260387Sscottl#endif
11039212Sgibbs#ifdef INET6
11139212Sgibbs    [KP_IP6_ADDR] =		{"ip6.addr",		0},
112255870Sscottl#endif
113255870Sscottl    [KP_JID] =			{"jid",			0},
114292348Sken    [KP_NAME] =			{"name",		0},
115292348Sken    [KP_PATH] =			{"path",		0},
116292348Sken    [KP_PERSIST] =		{"persist",		0},
117255870Sscottl    [KP_SECURELEVEL] =		{"securelevel",		0},
118255870Sscottl    [KP_VNET] =			{"vnet",		0},
11939212Sgibbs};
12039212Sgibbs
12146581Sken/*
12246581Sken * Parse the jail configuration file.
12346581Sken */
12446581Skenvoid
12546581Skenload_config(void)
12646581Sken{
12749925Sgibbs	struct cfjails wild;
12849925Sgibbs	struct cfparams opp;
12939212Sgibbs	struct cfjail *j, *tj, *wj;
13046581Sken	struct cfparam *p, *vp, *tp;
13146581Sken	struct cfstring *s, *vs, *ns;
13249925Sgibbs	struct cfvar *v;
13346581Sken	char *ep;
13446581Sken	size_t varoff;
13546581Sken	int did_self, jseq, pgen;
13646581Sken
13746581Sken	if (!strcmp(cfname, "-")) {
13846581Sken		cfname = "STDIN";
13946581Sken		yyin = stdin;
14046581Sken	} else {
141203108Smav		yyin = fopen(cfname, "r");
14246581Sken		if (!yyin)
14346581Sken			err(1, "%s", cfname);
14446581Sken	}
14546581Sken	if (yyparse() || yynerrs)
14646581Sken		exit(1);
14746581Sken
14846581Sken	/* Separate the wildcard jails out from the actual jails. */
14946581Sken	jseq = 0;
15046581Sken	TAILQ_INIT(&wild);
15146581Sken	TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) {
15246581Sken		j->seq = ++jseq;
15347412Sgibbs		if (wild_jail_name(j->name))
15447412Sgibbs			requeue(j, &wild);
15547412Sgibbs	}
15647412Sgibbs
157223081Sgibbs	TAILQ_FOREACH(j, &cfjails, tq) {
158223081Sgibbs		/* Set aside the jail's parameters. */
159260387Sscottl		TAILQ_INIT(&opp);
160260387Sscottl		TAILQ_CONCAT(&opp, &j->params, tq);
161260387Sscottl		/*
16239212Sgibbs		 * The jail name implies its "name" or "jid" parameter,
16346581Sken		 * though they may also be explicitly set later on.
16446581Sken		 */
16546581Sken		add_param(j, NULL,
16646581Sken		    strtol(j->name, &ep, 10) && !*ep ? KP_JID : KP_NAME,
16749925Sgibbs		    j->name);
16846581Sken		/*
16946581Sken		 * Collect parameters for the jail, global parameters/variables,
17046581Sken		 * and any matching wildcard jails.
17146581Sken		 */
17246581Sken		did_self = 0;
17346581Sken		TAILQ_FOREACH(wj, &wild, tq) {
17446581Sken			if (j->seq < wj->seq && !did_self) {
17546581Sken				TAILQ_FOREACH(p, &opp, tq)
17639212Sgibbs					add_param(j, p, 0, NULL);
17739212Sgibbs				did_self = 1;
17839212Sgibbs			}
17946581Sken			if (wild_jail_match(j->name, wj->name))
18046581Sken				TAILQ_FOREACH(p, &wj->params, tq)
18139212Sgibbs					add_param(j, p, 0, NULL);
18239212Sgibbs		}
18339212Sgibbs		if (!did_self)
18446581Sken			TAILQ_FOREACH(p, &opp, tq)
18546581Sken				add_param(j, p, 0, NULL);
18639212Sgibbs
18739212Sgibbs		/* Resolve any variable substitutions. */
18839212Sgibbs		pgen = 0;
18939212Sgibbs		TAILQ_FOREACH(p, &j->params, tq) {
190195534Sscottl		    p->gen = ++pgen;
191195534Sscottl		find_vars:
19239212Sgibbs		    TAILQ_FOREACH(s, &p->val, tq) {
193196008Smjacob			varoff = 0;
194196008Smjacob			while ((v = STAILQ_FIRST(&s->vars))) {
195196008Smjacob				TAILQ_FOREACH(vp, &j->params, tq)
196196008Smjacob					if (!strcmp(vp->name, v->name))
197196008Smjacob						break;
198196008Smjacob				if (!vp) {
199196008Smjacob					jail_warnx(j,
200196008Smjacob					    "%s: variable \"%s\" not found",
201196008Smjacob					    p->name, v->name);
202208582Smjacob				bad_var:
203216088Sken					j->flags |= JF_FAILED;
204216088Sken					TAILQ_FOREACH(vp, &j->params, tq)
205216088Sken						if (vp->gen == pgen)
206208582Smjacob							vp->flags |= PF_BAD;
207208582Smjacob					goto free_var;
208208582Smjacob				}
209208582Smjacob				if (vp->flags & PF_BAD)
21039212Sgibbs					goto bad_var;
21146581Sken				if (vp->gen == pgen) {
21246581Sken					jail_warnx(j, "%s: variable loop",
21374840Sken					    v->name);
21446581Sken					goto bad_var;
21539212Sgibbs				}
21639212Sgibbs				TAILQ_FOREACH(vs, &vp->val, tq)
21746581Sken					if (!STAILQ_EMPTY(&vs->vars)) {
21846581Sken						vp->gen = pgen;
21949925Sgibbs						TAILQ_REMOVE(&j->params, vp,
22046581Sken						    tq);
22146581Sken						TAILQ_INSERT_BEFORE(p, vp, tq);
22246581Sken						p = vp;
22349925Sgibbs						goto find_vars;
22446581Sken					}
22546581Sken				vs = TAILQ_FIRST(&vp->val);
226196008Smjacob				if (TAILQ_NEXT(vs, tq) != NULL &&
227196008Smjacob				    (s->s[0] != '\0' ||
228196008Smjacob				     STAILQ_NEXT(v, tq))) {
229196008Smjacob					jail_warnx(j, "%s: array cannot be "
23046581Sken					    "substituted inline",
231196008Smjacob					    p->name);
23246581Sken					goto bad_var;
233302376Struckman				}
234302376Struckman				s->s = erealloc(s->s, s->len + vs->len + 1);
23539212Sgibbs				memmove(s->s + v->pos + varoff + vs->len,
23639212Sgibbs				    s->s + v->pos + varoff,
23746581Sken				    s->len - (v->pos + varoff) + 1);
23839212Sgibbs				memcpy(s->s + v->pos + varoff, vs->s, vs->len);
23939212Sgibbs				varoff += vs->len;
24046581Sken				s->len += vs->len;
24146581Sken				while ((vs = TAILQ_NEXT(vs, tq))) {
24246581Sken					ns = emalloc(sizeof(struct cfstring));
24346581Sken					ns->s = estrdup(vs->s);
24449925Sgibbs					ns->len = vs->len;
24546581Sken					STAILQ_INIT(&ns->vars);
24646581Sken					TAILQ_INSERT_AFTER(&p->val, s, ns, tq);
24744499Sgibbs					s = ns;
24849925Sgibbs				}
24949925Sgibbs			free_var:
25049925Sgibbs				free(v->name);
25149925Sgibbs				STAILQ_REMOVE_HEAD(&s->vars, tq);
25274840Sken				free(v);
25374840Sken			}
25474840Sken		    }
25574840Sken		}
25674840Sken
25774840Sken		/* Free the jail's original parameter list and any variables. */
25874840Sken		while ((p = TAILQ_FIRST(&opp)))
259195534Sscottl			free_param(&opp, p);
260235897Smav		TAILQ_FOREACH_SAFE(p, &j->params, tq, tp)
26174840Sken			if (p->flags & PF_VAR)
26274840Sken				free_param(&j->params, p);
26374840Sken	}
26474840Sken	while ((wj = TAILQ_FIRST(&wild))) {
26574840Sken		free(wj->name);
26674840Sken		while ((p = TAILQ_FIRST(&wj->params)))
26774840Sken			free_param(&wj->params, p);
26874840Sken		TAILQ_REMOVE(&wild, wj, tq);
26974840Sken	}
27074840Sken}
271154593Smjacob
272154593Smjacob/*
273195534Sscottl * Create a new jail record.
274196352Smav */
275255915Snwhitehornstruct cfjail *
27674840Skenadd_jail(void)
27774840Sken{
278220644Smav	struct cfjail *j;
279220644Smav
280220644Smav	j = emalloc(sizeof(struct cfjail));
281220644Smav	memset(j, 0, sizeof(struct cfjail));
282220644Smav	TAILQ_INIT(&j->params);
283220644Smav	STAILQ_INIT(&j->dep[DEP_FROM]);
284220644Smav	STAILQ_INIT(&j->dep[DEP_TO]);
285220644Smav	j->queue = &cfjails;
286154593Smjacob	TAILQ_INSERT_TAIL(&cfjails, j, tq);
287154593Smjacob	return j;
288154593Smjacob}
289154593Smjacob
29074840Sken/*
29139212Sgibbs * Add a parameter to a jail.
29260938Sjake */
29360938Sjakevoid
29460938Sjakeadd_param(struct cfjail *j, const struct cfparam *p, enum intparam ipnum,
29560938Sjake    const char *value)
29639212Sgibbs{
29739212Sgibbs	struct cfstrings nss;
29839212Sgibbs	struct cfparam *dp, *np;
29939212Sgibbs	struct cfstring *s, *ns;
30039212Sgibbs	struct cfvar *v, *nv;
301168752Sscottl	const char *name;
30239212Sgibbs	char *cs, *tname;
30339212Sgibbs	unsigned flags;
30439212Sgibbs
30539212Sgibbs	if (j == NULL) {
30639212Sgibbs		/* Create a single anonymous jail if one doesn't yet exist. */
30739212Sgibbs		j = TAILQ_LAST(&cfjails, cfjails);
30839212Sgibbs		if (j == NULL)
30939212Sgibbs			j = add_jail();
31039212Sgibbs	}
31139212Sgibbs	TAILQ_INIT(&nss);
31239212Sgibbs	if (p != NULL) {
31339212Sgibbs		name = p->name;
314255870Sscottl		flags = p->flags;
315255870Sscottl		/*
316255870Sscottl		 * Make a copy of the parameter's string list,
317255870Sscottl		 * which may be freed if it's overridden later.
318255870Sscottl		 */
319255870Sscottl		TAILQ_FOREACH(s, &p->val, tq) {
32039212Sgibbs			ns = emalloc(sizeof(struct cfstring));
321130200Sscottl			ns->s = estrdup(s->s);
32239212Sgibbs			ns->len = s->len;
32339212Sgibbs			STAILQ_INIT(&ns->vars);
324130200Sscottl			STAILQ_FOREACH(v, &s->vars, tq) {
32539212Sgibbs				nv = emalloc(sizeof(struct cfvar));
32639212Sgibbs				nv->name = strdup(v->name);
327130200Sscottl				nv->pos = v->pos;
32839212Sgibbs				STAILQ_INSERT_TAIL(&ns->vars, nv, tq);
329130200Sscottl			}
330130200Sscottl			TAILQ_INSERT_TAIL(&nss, ns, tq);
33139212Sgibbs		}
33239212Sgibbs	} else {
33339212Sgibbs		flags = PF_APPEND;
334255870Sscottl		if (ipnum != IP__NULL) {
335130200Sscottl			name = intparams[ipnum].name;
336255870Sscottl			flags |= intparams[ipnum].flags;
33739212Sgibbs		} else if ((cs = strchr(value, '='))) {
33839212Sgibbs			tname = alloca(cs - value + 1);
339255870Sscottl			strlcpy(tname, value, cs - value + 1);
340255870Sscottl			name = tname;
341255870Sscottl			value = cs + 1;
34239212Sgibbs		} else {
34339212Sgibbs			name = value;
34439212Sgibbs			value = NULL;
34539212Sgibbs		}
34639212Sgibbs		if (value != NULL) {
347195534Sscottl			ns = emalloc(sizeof(struct cfstring));
34856145Smjacob			ns->s = estrdup(value);
349195534Sscottl			ns->len = strlen(value);
35039212Sgibbs			STAILQ_INIT(&ns->vars);
351199178Smav			TAILQ_INSERT_TAIL(&nss, ns, tq);
35239212Sgibbs		}
35339212Sgibbs	}
35439212Sgibbs
35547412Sgibbs	/* See if this parameter has already been added. */
35647412Sgibbs	if (ipnum != IP__NULL)
35747412Sgibbs		dp = j->intparams[ipnum];
35847412Sgibbs	else
35947412Sgibbs		TAILQ_FOREACH(dp, &j->params, tq)
360273078Smav			if (!(dp->flags & PF_CONV) && equalopts(dp->name, name))
361273078Smav				break;
36247412Sgibbs	if (dp != NULL) {
36347412Sgibbs		/* Found it - append or replace. */
36447412Sgibbs		if (strcmp(dp->name, name)) {
36547412Sgibbs			free(dp->name);
36647434Sgibbs			dp->name = estrdup(name);
36747434Sgibbs		}
36847434Sgibbs		if (!(flags & PF_APPEND) || TAILQ_EMPTY(&nss))
36947434Sgibbs			free_param_strings(dp);
37047434Sgibbs		TAILQ_CONCAT(&dp->val, &nss, tq);
37147412Sgibbs		dp->flags |= flags;
37247412Sgibbs	} else {
37339212Sgibbs		/* Not found - add it. */
37439212Sgibbs		np = emalloc(sizeof(struct cfparam));
37539212Sgibbs		np->name = estrdup(name);
37639212Sgibbs		TAILQ_INIT(&np->val);
37739212Sgibbs		TAILQ_CONCAT(&np->val, &nss, tq);
37839212Sgibbs		np->flags = flags;
37939212Sgibbs		np->gen = 0;
38039212Sgibbs		TAILQ_INSERT_TAIL(&j->params, np, tq);
38139212Sgibbs		if (ipnum != IP__NULL)
38239212Sgibbs			j->intparams[ipnum] = np;
38339212Sgibbs		else
38439212Sgibbs			for (ipnum = IP__NULL + 1; ipnum < IP_NPARAM; ipnum++)
38539212Sgibbs				if (!(intparams[ipnum].flags & PF_CONV) &&
38639212Sgibbs				    equalopts(name, intparams[ipnum].name)) {
38739212Sgibbs					j->intparams[ipnum] = np;
38839212Sgibbs					np->flags |= intparams[ipnum].flags;
38939212Sgibbs					break;
39039212Sgibbs				}
39139212Sgibbs	}
39239212Sgibbs}
39339212Sgibbs
39439212Sgibbs/*
39539212Sgibbs * Return if a boolean parameter exists and is true.
39639212Sgibbs */
39739212Sgibbsint
39839212Sgibbsbool_param(const struct cfparam *p)
39939212Sgibbs{
40039212Sgibbs	const char *cs;
40139212Sgibbs
40239212Sgibbs	if (p == NULL)
40339212Sgibbs		return 0;
40439212Sgibbs	cs = strrchr(p->name, '.');
40539212Sgibbs	return !strncmp(cs ? cs + 1 : p->name, "no", 2) ^
40639212Sgibbs	    (TAILQ_EMPTY(&p->val) ||
40739212Sgibbs	     !strcasecmp(TAILQ_LAST(&p->val, cfstrings)->s, "true") ||
40839212Sgibbs	     (strtol(TAILQ_LAST(&p->val, cfstrings)->s, NULL, 10)));
40939212Sgibbs}
41039212Sgibbs
41139212Sgibbs/*
41239212Sgibbs * Set an integer if a parameter if it exists.
41339212Sgibbs */
41439212Sgibbsint
415223081Sgibbsint_param(const struct cfparam *p, int *ip)
41639212Sgibbs{
41739212Sgibbs	if (p == NULL || TAILQ_EMPTY(&p->val))
41839212Sgibbs		return 0;
419223081Sgibbs	*ip = strtol(TAILQ_LAST(&p->val, cfstrings)->s, NULL, 10);
420223081Sgibbs	return 1;
421223081Sgibbs}
422223081Sgibbs
423223081Sgibbs/*
42439212Sgibbs * Return the string value of a scalar parameter if it exists.
425223081Sgibbs */
426223081Sgibbsconst char *
427223081Sgibbsstring_param(const struct cfparam *p)
428223081Sgibbs{
429223081Sgibbs	return (p && !TAILQ_EMPTY(&p->val)
430223081Sgibbs	    ? TAILQ_LAST(&p->val, cfstrings)->s : NULL);
431223081Sgibbs}
432223081Sgibbs
43339212Sgibbs/*
43439212Sgibbs * Check syntax and values of internal parameters.  Set some internal
43539212Sgibbs * parameters based on the values of others.
43639212Sgibbs */
43739212Sgibbsint
43839212Sgibbscheck_intparams(struct cfjail *j)
43939212Sgibbs{
44039212Sgibbs	struct cfparam *p;
44139212Sgibbs	struct cfstring *s;
44239212Sgibbs	FILE *f;
44339212Sgibbs	const char *val;
44439212Sgibbs	char *cs, *ep, *ln;
44539212Sgibbs	size_t lnlen;
44639212Sgibbs	int error;
44739212Sgibbs#if defined(INET) || defined(INET6)
44839212Sgibbs	struct addrinfo hints;
44939212Sgibbs	struct addrinfo *ai0, *ai;
45039212Sgibbs	const char *hostname;
45139212Sgibbs	int gicode, defif, prefix;
45239212Sgibbs#endif
45339212Sgibbs#ifdef INET
45439212Sgibbs	struct in_addr addr4;
45539212Sgibbs	int ip4ok;
45639212Sgibbs	char avalue4[INET_ADDRSTRLEN];
45739212Sgibbs#endif
45839212Sgibbs#ifdef INET6
45939212Sgibbs	struct in6_addr addr6;
46039212Sgibbs	int ip6ok;
46139212Sgibbs	char avalue6[INET6_ADDRSTRLEN];
46239212Sgibbs#endif
46339212Sgibbs
46439212Sgibbs	error = 0;
46539212Sgibbs	/* Check format of boolan and integer values. */
46639212Sgibbs	TAILQ_FOREACH(p, &j->params, tq) {
46739212Sgibbs		if (!TAILQ_EMPTY(&p->val) && (p->flags & (PF_BOOL | PF_INT))) {
46839212Sgibbs			val = TAILQ_LAST(&p->val, cfstrings)->s;
46939212Sgibbs			if (p->flags & PF_BOOL) {
47039212Sgibbs				if (strcasecmp(val, "false") &&
47139212Sgibbs				    strcasecmp(val, "true") &&
47239212Sgibbs				    ((void)strtol(val, &ep, 10), *ep)) {
47339212Sgibbs					jail_warnx(j,
47439212Sgibbs					    "%s: unknown boolean value \"%s\"",
47539212Sgibbs					    p->name, val);
47639212Sgibbs					error = -1;
47746581Sken				}
47846581Sken			} else {
47946581Sken				(void)strtol(val, &ep, 10);
48046581Sken				if (ep == val || *ep) {
48146581Sken					jail_warnx(j,
48239212Sgibbs					    "%s: non-integer value \"%s\"",
48339212Sgibbs					    p->name, val);
48439212Sgibbs					error = -1;
48539212Sgibbs				}
486195534Sscottl			}
48739212Sgibbs		}
488195534Sscottl	}
48946581Sken
49039212Sgibbs#if defined(INET) || defined(INET6)
49139212Sgibbs	/*
49239212Sgibbs	 * The ip_hostname parameter looks up the hostname, and adds parameters
49339212Sgibbs	 * for any IP addresses it finds.
49439212Sgibbs	 */
49539212Sgibbs	if (((j->flags & JF_OP_MASK) != JF_STOP ||
49639212Sgibbs	    j->intparams[IP_INTERFACE] != NULL) &&
49739212Sgibbs	    bool_param(j->intparams[IP_IP_HOSTNAME]) &&
49839212Sgibbs	    (hostname = string_param(j->intparams[KP_HOST_HOSTNAME]))) {
49939212Sgibbs		j->intparams[IP_IP_HOSTNAME] = NULL;
50039212Sgibbs		/*
50139212Sgibbs		 * Silently ignore unsupported address families from
50239212Sgibbs		 * DNS lookups.
50339212Sgibbs		 */
50439212Sgibbs#ifdef INET
50539212Sgibbs		ip4ok = feature_present("inet");
50639212Sgibbs#endif
50739212Sgibbs#ifdef INET6
50839212Sgibbs		ip6ok = feature_present("inet6");
50939212Sgibbs#endif
51039212Sgibbs		if (
51139212Sgibbs#if defined(INET) && defined(INET6)
51239212Sgibbs		    ip4ok || ip6ok
51339212Sgibbs#elif defined(INET)
51439212Sgibbs		    ip4ok
51539212Sgibbs#elif defined(INET6)
51639212Sgibbs		    ip6ok
51739212Sgibbs#endif
51839212Sgibbs			 ) {
51939212Sgibbs			/* Look up the hostname (or get the address) */
52039212Sgibbs			memset(&hints, 0, sizeof(hints));
52139212Sgibbs			hints.ai_socktype = SOCK_STREAM;
52239212Sgibbs			hints.ai_family =
52339212Sgibbs#if defined(INET) && defined(INET6)
52439212Sgibbs			    ip4ok ? (ip6ok ? PF_UNSPEC : PF_INET) :  PF_INET6;
52539212Sgibbs#elif defined(INET)
52639212Sgibbs			    PF_INET;
52739212Sgibbs#elif defined(INET6)
52839212Sgibbs			    PF_INET6;
52939212Sgibbs#endif
53039212Sgibbs			gicode = getaddrinfo(hostname, NULL, &hints, &ai0);
53139212Sgibbs			if (gicode != 0) {
53239212Sgibbs				jail_warnx(j, "host.hostname %s: %s", hostname,
53339212Sgibbs				    gai_strerror(gicode));
53439212Sgibbs				error = -1;
53539212Sgibbs			} else {
53639212Sgibbs				/*
53739212Sgibbs				 * Convert the addresses to ASCII so jailparam
53839212Sgibbs				 * can convert them back.  Errors are not
53939212Sgibbs				 * expected here.
54039212Sgibbs				 */
54139212Sgibbs				for (ai = ai0; ai; ai = ai->ai_next)
54239212Sgibbs					switch (ai->ai_family) {
54339212Sgibbs#ifdef INET
54439212Sgibbs					case AF_INET:
54539212Sgibbs						memcpy(&addr4,
54639212Sgibbs						    &((struct sockaddr_in *)
54739212Sgibbs						    (void *)ai->ai_addr)->
54839212Sgibbs						    sin_addr, sizeof(addr4));
54939212Sgibbs						if (inet_ntop(AF_INET,
55039212Sgibbs						    &addr4, avalue4,
55139212Sgibbs						    INET_ADDRSTRLEN) == NULL)
55239212Sgibbs							err(1, "inet_ntop");
55339212Sgibbs						add_param(j, NULL, KP_IP4_ADDR,
55439212Sgibbs						    avalue4);
55539212Sgibbs						break;
55639212Sgibbs#endif
55739212Sgibbs#ifdef INET6
55839212Sgibbs					case AF_INET6:
55939212Sgibbs						memcpy(&addr6,
56039212Sgibbs						    &((struct sockaddr_in6 *)
56139212Sgibbs						    (void *)ai->ai_addr)->
56239212Sgibbs						    sin6_addr, sizeof(addr6));
563255870Sscottl						if (inet_ntop(AF_INET6,
56439212Sgibbs						    &addr6, avalue6,
56539212Sgibbs						    INET6_ADDRSTRLEN) == NULL)
56639212Sgibbs							err(1, "inet_ntop");
56739212Sgibbs						add_param(j, NULL, KP_IP6_ADDR,
56839212Sgibbs						    avalue6);
56939212Sgibbs						break;
57039212Sgibbs#endif
571195534Sscottl					}
57239212Sgibbs				freeaddrinfo(ai0);
57353258Sken			}
57439212Sgibbs		}
57539212Sgibbs	}
57639212Sgibbs
57739212Sgibbs	/*
57839212Sgibbs	 * IP addresses may include an interface to set that address on,
57939212Sgibbs	 * and a netmask/suffix for that address.
58039212Sgibbs	 */
58139212Sgibbs	defif = string_param(j->intparams[IP_INTERFACE]) != NULL;
58253258Sken#ifdef INET
58339212Sgibbs	if (j->intparams[KP_IP4_ADDR] != NULL) {
58439212Sgibbs		TAILQ_FOREACH(s, &j->intparams[KP_IP4_ADDR]->val, tq) {
58539212Sgibbs			cs = strchr(s->s, '|');
586255870Sscottl			if (cs || defif)
58739212Sgibbs				add_param(j, NULL, IP__IP4_IFADDR, s->s);
58839212Sgibbs			if (cs) {
58941644Sgibbs				strcpy(s->s, cs + 1);
590118105Snjl				s->len -= cs + 1 - s->s;
591159311Smjacob			}
592248519Skib			if ((cs = strchr(s->s, '/'))) {
593248519Skib				prefix = strtol(cs + 1, &ep, 10);
594253549Sken				if (*ep == '.'
59539212Sgibbs				    ? inet_pton(AF_INET, cs + 1, &addr4) != 1
59639212Sgibbs				    : *ep || prefix < 0 || prefix > 32) {
59739212Sgibbs					jail_warnx(j,
59874840Sken					    "ip4.addr: bad netmask \"%s\"", cs);
59974840Sken					error = -1;
60074840Sken				}
601196008Smjacob				*cs = '\0';
60277708Smjacob				s->len = cs - s->s;
60377708Smjacob			}
60477708Smjacob		}
60577708Smjacob	}
60677708Smjacob#endif
60777708Smjacob#ifdef INET6
608196008Smjacob	if (j->intparams[KP_IP6_ADDR] != NULL) {
609154593Smjacob		TAILQ_FOREACH(s, &j->intparams[KP_IP6_ADDR]->val, tq) {
610154593Smjacob			cs = strchr(s->s, '|');
611154593Smjacob			if (cs || defif)
61277708Smjacob				add_param(j, NULL, IP__IP6_IFADDR, s->s);
61374840Sken			if (cs) {
61439212Sgibbs				strcpy(s->s, cs + 1);
61539212Sgibbs				s->len -= cs + 1 - s->s;
61639212Sgibbs			}
61739212Sgibbs			if ((cs = strchr(s->s, '/'))) {
618255870Sscottl				prefix = strtol(cs + 1, &ep, 10);
619255870Sscottl				if (*ep || prefix < 0 || prefix > 128) {
62039212Sgibbs					jail_warnx(j,
62139212Sgibbs					    "ip6.addr: bad prefixlen \"%s\"",
62239212Sgibbs					    cs);
62339212Sgibbs					error = -1;
62439212Sgibbs				}
62539212Sgibbs				*cs = '\0';
62639212Sgibbs				s->len = cs - s->s;
62739212Sgibbs			}
62839212Sgibbs		}
62939212Sgibbs	}
63039212Sgibbs#endif
63139212Sgibbs#endif
63239212Sgibbs
63346581Sken	/*
63474840Sken	 * Read mount.fstab file(s), and treat each line as its own mount
63574840Sken	 * parameter.
63674840Sken	 */
63774840Sken	if (j->intparams[IP_MOUNT_FSTAB] != NULL) {
63874840Sken		TAILQ_FOREACH(s, &j->intparams[IP_MOUNT_FSTAB]->val, tq) {
63974840Sken			if (s->len == 0)
64077708Smjacob				continue;
641154593Smjacob			f = fopen(s->s, "r");
64277708Smjacob			if (f == NULL) {
64374840Sken				jail_warnx(j, "mount.fstab: %s: %s",
644195534Sscottl				    s->s, strerror(errno));
645210471Smav				error = -1;
646210471Smav				continue;
647210471Smav			}
648210471Smav			while ((ln = fgetln(f, &lnlen))) {
64939212Sgibbs				if ((cs = memchr(ln, '#', lnlen - 1)))
65039212Sgibbs					lnlen = cs - ln + 1;
65147412Sgibbs				if (ln[lnlen - 1] == '\n' ||
65247412Sgibbs				    ln[lnlen - 1] == '#')
65347412Sgibbs					ln[lnlen - 1] = '\0';
65447412Sgibbs				else {
65547412Sgibbs					cs = alloca(lnlen + 1);
65647412Sgibbs					strlcpy(cs, ln, lnlen + 1);
657216088Sken					ln = cs;
658216088Sken				}
659216088Sken				add_param(j, NULL, IP__MOUNT_FROM_FSTAB, ln);
660216088Sken			}
661216088Sken			fclose(f);
662216088Sken		}
663216088Sken	}
664216088Sken	if (error)
665216088Sken		failed(j);
666216088Sken	return error;
667216088Sken}
668216088Sken
669216088Sken/*
670216088Sken * Import parameters into libjail's binary jailparam format.
671216088Sken */
672216088Skenint
673216088Skenimport_params(struct cfjail *j)
674216088Sken{
675216088Sken	struct cfparam *p;
676216088Sken	struct cfstring *s, *ts;
677216088Sken	struct jailparam *jp;
678216088Sken	char *value, *cs;
679216088Sken	size_t vallen;
680216088Sken	int error;
681216088Sken
682216088Sken	error = 0;
68339212Sgibbs	j->njp = 0;
68439212Sgibbs	TAILQ_FOREACH(p, &j->params, tq)
68539212Sgibbs		if (!(p->flags & PF_INTERNAL))
68639212Sgibbs			j->njp++;
68739212Sgibbs	j->jp = jp = emalloc(j->njp * sizeof(struct jailparam));
68839212Sgibbs	TAILQ_FOREACH(p, &j->params, tq) {
68939212Sgibbs		if (p->flags & PF_INTERNAL)
69039212Sgibbs			continue;
69139212Sgibbs		if (jailparam_init(jp, p->name) < 0) {
69239212Sgibbs			error = -1;
69339212Sgibbs			jail_warnx(j, "%s", jail_errmsg);
69439212Sgibbs			jp++;
69539212Sgibbs			continue;
69639212Sgibbs		}
69739212Sgibbs		if (TAILQ_EMPTY(&p->val))
69839212Sgibbs			value = NULL;
69939212Sgibbs		else if (!jp->jp_elemlen ||
70039212Sgibbs			 !TAILQ_NEXT(TAILQ_FIRST(&p->val), tq)) {
70139212Sgibbs			/*
70239212Sgibbs			 * Scalar parameters silently discard multiple (array)
70339212Sgibbs			 * values, keeping only the last value added.  This
70439212Sgibbs			 * lets values added from the command line append to
70539212Sgibbs			 * arrays wthout pre-checking the type.
70639212Sgibbs			 */
70739212Sgibbs			value = TAILQ_LAST(&p->val, cfstrings)->s;
70839212Sgibbs		} else {
70939212Sgibbs			/*
71039212Sgibbs			 * Convert arrays into comma-separated strings, which
71139212Sgibbs			 * jailparam_import will then convert back into arrays.
71239212Sgibbs			 */
71339212Sgibbs			vallen = 0;
71439212Sgibbs			TAILQ_FOREACH(s, &p->val, tq)
71539212Sgibbs				vallen += s->len + 1;
71639212Sgibbs			value = alloca(vallen);
71739212Sgibbs			cs = value;
71839212Sgibbs			TAILQ_FOREACH_SAFE(s, &p->val, tq, ts) {
71939212Sgibbs				memcpy(cs, s->s, s->len);
72040417Sgibbs				cs += s->len + 1;
72140417Sgibbs				cs[-1] = ',';
72240417Sgibbs			}
72340417Sgibbs			value[vallen - 1] = '\0';
72440417Sgibbs		}
72540417Sgibbs		if (jailparam_import(jp, value) < 0) {
72649925Sgibbs			error = -1;
72749925Sgibbs			jail_warnx(j, "%s", jail_errmsg);
72839212Sgibbs		}
72939212Sgibbs		jp++;
730312850Smav	}
731312850Smav	if (error) {
732312850Smav		jailparam_free(j->jp, j->njp);
733312850Smav		free(j->jp);
734312850Smav		j->jp = NULL;
735312850Smav		failed(j);
736312850Smav	}
737195534Sscottl	return error;
738195534Sscottl}
739195534Sscottl
740195534Sscottl/*
741195534Sscottl * Check if options are equal (with or without the "no" prefix).
742195534Sscottl */
743195534Sscottlint
744195534Sscottlequalopts(const char *opt1, const char *opt2)
745195534Sscottl{
746195534Sscottl	char *p;
747195534Sscottl
748195534Sscottl	/* "opt" vs. "opt" or "noopt" vs. "noopt" */
749195534Sscottl	if (strcmp(opt1, opt2) == 0)
750195534Sscottl		return (1);
751195534Sscottl	/* "noopt" vs. "opt" */
752195534Sscottl	if (strncmp(opt1, "no", 2) == 0 && strcmp(opt1 + 2, opt2) == 0)
753195534Sscottl		return (1);
754195534Sscottl	/* "opt" vs. "noopt" */
755195534Sscottl	if (strncmp(opt2, "no", 2) == 0 && strcmp(opt1, opt2 + 2) == 0)
756195534Sscottl		return (1);
757195534Sscottl	while ((p = strchr(opt1, '.')) != NULL &&
758195534Sscottl	    !strncmp(opt1, opt2, ++p - opt1)) {
75939212Sgibbs		opt2 += p - opt1;
76039212Sgibbs		opt1 = p;
76139212Sgibbs		/* "foo.noopt" vs. "foo.opt" */
76239212Sgibbs		if (strncmp(opt1, "no", 2) == 0 && strcmp(opt1 + 2, opt2) == 0)
76339212Sgibbs			return (1);
76456145Smjacob		/* "foo.opt" vs. "foo.noopt" */
76555328Smjacob		if (strncmp(opt2, "no", 2) == 0 && strcmp(opt1, opt2 + 2) == 0)
76655328Smjacob			return (1);
76756145Smjacob	}
76839212Sgibbs	return (0);
76939212Sgibbs}
770312845Smav
771312845Smav/*
772312845Smav * See if a jail name matches a wildcard.
773312845Smav */
774312845Smavint
775312845Smavwild_jail_match(const char *jname, const char *wname)
776312845Smav{
77739212Sgibbs	const char *jc, *jd, *wc, *wd;
77839212Sgibbs
77939212Sgibbs	/*
78039212Sgibbs	 * A non-final "*" component in the wild name matches a single jail
78139212Sgibbs	 * component, and a final "*" matches one or more jail components.
78239212Sgibbs	 */
78339212Sgibbs	for (jc = jname, wc = wname;
78439212Sgibbs	     (jd = strchr(jc, '.')) && (wd = strchr(wc, '.'));
78539212Sgibbs	     jc = jd + 1, wc = wd + 1)
786203108Smav		if (strncmp(jc, wc, jd - jc + 1) && strncmp(wc, "*.", 2))
78739212Sgibbs			return 0;
78839212Sgibbs	return (!strcmp(jc, wc) || !strcmp(wc, "*"));
78939212Sgibbs}
79039212Sgibbs
79139212Sgibbs/*
79239212Sgibbs * Return if a jail name is a wildcard.
79339212Sgibbs */
794238886Smavint
795223081Sgibbswild_jail_name(const char *wname)
796196008Smjacob{
79739212Sgibbs	const char *wc;
79839212Sgibbs
79939212Sgibbs	for (wc = strchr(wname, '*'); wc; wc = strchr(wc + 1, '*'))
80039212Sgibbs		if ((wc == wname || wc[-1] == '.') &&
80139212Sgibbs		    (wc[1] == '\0' || wc[1] == '.'))
80239212Sgibbs			return 1;
80339212Sgibbs	return 0;
80439212Sgibbs}
80539212Sgibbs
80639212Sgibbs/*
80739212Sgibbs * Free a parameter record and all its strings and variables.
80839212Sgibbs */
80939212Sgibbsstatic void
81039212Sgibbsfree_param(struct cfparams *pp, struct cfparam *p)
81139212Sgibbs{
81239212Sgibbs	free(p->name);
813196008Smjacob	free_param_strings(p);
814196008Smjacob	TAILQ_REMOVE(pp, p, tq);
815196008Smjacob	free(p);
816196008Smjacob}
817196008Smjacob
818196008Smjacobstatic void
819196008Smjacobfree_param_strings(struct cfparam *p)
820196008Smjacob{
821196008Smjacob	struct cfstring *s;
822196008Smjacob	struct cfvar *v;
823196008Smjacob
824196008Smjacob	while ((s = TAILQ_FIRST(&p->val))) {
825196008Smjacob		free(s->s);
826196008Smjacob		while ((v = STAILQ_FIRST(&s->vars))) {
827196008Smjacob			free(v->name);
828196008Smjacob			STAILQ_REMOVE_HEAD(&s->vars, tq);
829196008Smjacob			free(v);
830196008Smjacob		}
831196008Smjacob		TAILQ_REMOVE(&p->val, s, tq);
832196008Smjacob		free(s);
83339212Sgibbs	}
83439212Sgibbs}
83539212Sgibbs