Deleted Added
full compact
config.c (214117) config.c (214423)
1/*-
2 * Copyright (c) 2010 James Gritton
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2010 James Gritton
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: projects/jailconf/usr.sbin/jail/config.c 214117 2010-10-20 20:42:33Z jamie $");
28__FBSDID("$FreeBSD: projects/jailconf/usr.sbin/jail/config.c 214423 2010-10-27 16:22:54Z jamie $");
29
30#include <sys/types.h>
31#include <sys/socket.h>
32#include <sys/sysctl.h>
33
34#include <arpa/inet.h>
35#include <netinet/in.h>
36
37#include <err.h>
38#include <netdb.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42
43#include "jailp.h"
44
45struct ipspec {
46 const char *name;
29
30#include <sys/types.h>
31#include <sys/socket.h>
32#include <sys/sysctl.h>
33
34#include <arpa/inet.h>
35#include <netinet/in.h>
36
37#include <err.h>
38#include <netdb.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42
43#include "jailp.h"
44
45struct ipspec {
46 const char *name;
47 enum intparam ipnum;
48 unsigned flags;
49};
50
51extern FILE *yyin;
52extern int yynerrs;
53
54struct cfjails cfjails = TAILQ_HEAD_INITIALIZER(cfjails);
55
47 unsigned flags;
48};
49
50extern FILE *yyin;
51extern int yynerrs;
52
53struct cfjails cfjails = TAILQ_HEAD_INITIALIZER(cfjails);
54
56static int cmp_intparam(const void *a, const void *b);
57static void free_param(struct cfparams *pp, struct cfparam *p);
58static void free_param_strings(struct cfparam *p);
59
55static void free_param(struct cfparams *pp, struct cfparam *p);
56static void free_param_strings(struct cfparam *p);
57
60/* Note these must be in sort order */
61static const struct ipspec intparams[] = {
58static const struct ipspec intparams[] = {
62 {"allow.dying", IP_ALLOW_DYING, PF_INTERNAL | PF_BOOL },
63 {"allow.nodying", IP_ALLOW_DYING, PF_INTERNAL | PF_BOOL },
64 {"command", IP_COMMAND, PF_INTERNAL },
65 {"depend", IP_DEPEND, PF_INTERNAL },
66 {"exec.clean", IP_EXEC_CLEAN, PF_INTERNAL | PF_BOOL },
67 {"exec.consolelog", IP_EXEC_CONSOLELOG, PF_INTERNAL },
68 {"exec.fib", IP_EXEC_FIB, PF_INTERNAL | PF_INT },
69 {"exec.jail_user", IP_EXEC_JAIL_USER, PF_INTERNAL },
70 {"exec.noclean", IP_EXEC_CLEAN, PF_INTERNAL | PF_BOOL },
71 {"exec.nosystem_jail_user",IP_EXEC_SYSTEM_JAIL_USER,PF_INTERNAL | PF_BOOL },
72 {"exec.poststart", IP_EXEC_POSTSTART, PF_INTERNAL },
73 {"exec.poststop", IP_EXEC_POSTSTOP, PF_INTERNAL },
74 {"exec.prestart", IP_EXEC_PRESTART, PF_INTERNAL },
75 {"exec.prestop", IP_EXEC_PRESTOP, PF_INTERNAL },
76 {"exec.start", IP_EXEC_START, PF_INTERNAL },
77 {"exec.stop", IP_EXEC_STOP, PF_INTERNAL },
78 {"exec.system_jail_user", IP_EXEC_SYSTEM_JAIL_USER, PF_INTERNAL | PF_BOOL },
79 {"exec.system_user", IP_EXEC_SYSTEM_USER, PF_INTERNAL },
80 {"exec.timeout", IP_EXEC_TIMEOUT, PF_INTERNAL | PF_INT },
81 {"host.hostname", KP_HOSTNAME, 0 },
82 {"interface", IP_INTERFACE, PF_INTERNAL },
83 {"ip4.addr", KP_IP4_ADDR, 0 },
59 [IP_ALLOW_DYING] = {"allow.dying", PF_INTERNAL | PF_BOOL},
60 [IP_COMMAND] = {"command", PF_INTERNAL},
61 [IP_DEPEND] = {"depend", PF_INTERNAL},
62 [IP_EXEC_CLEAN] = {"exec.clean", PF_INTERNAL | PF_BOOL},
63 [IP_EXEC_CONSOLELOG] = {"exec.consolelog", PF_INTERNAL},
64 [IP_EXEC_FIB] = {"exec.fib", PF_INTERNAL | PF_INT},
65 [IP_EXEC_JAIL_USER] = {"exec.jail_user", PF_INTERNAL},
66 [IP_EXEC_POSTSTART] = {"exec.poststart", PF_INTERNAL},
67 [IP_EXEC_POSTSTOP] = {"exec.poststop", PF_INTERNAL},
68 [IP_EXEC_PRESTART] = {"exec.prestart", PF_INTERNAL},
69 [IP_EXEC_PRESTOP] = {"exec.prestop", PF_INTERNAL},
70 [IP_EXEC_START] = {"exec.start", PF_INTERNAL},
71 [IP_EXEC_STOP] = {"exec.stop", PF_INTERNAL},
72 [IP_EXEC_SYSTEM_JAIL_USER]= {"exec.system_jail_user",
73 PF_INTERNAL | PF_BOOL},
74 [IP_EXEC_SYSTEM_USER] = {"exec.system_user", PF_INTERNAL},
75 [IP_EXEC_TIMEOUT] = {"exec.timeout", PF_INTERNAL | PF_INT},
76 [IP_INTERFACE] = {"interface", PF_INTERNAL},
77 [IP_IP_HOSTNAME] = {"ip_hostname", PF_INTERNAL | PF_BOOL},
78 [IP_MOUNT] = {"mount", PF_INTERNAL},
79 [IP_MOUNT_DEVFS] = {"mount.devfs", PF_INTERNAL | PF_BOOL},
80 [IP_MOUNT_DEVFS_RULESET]= {"mount.devfs.ruleset", PF_INTERNAL},
81 [IP_MOUNT_FSTAB] = {"mount.fstab", PF_INTERNAL},
82 [IP_STOP_TIMEOUT] = {"stop.timeout", PF_INTERNAL | PF_INT},
83 [IP_VNET_INTERFACE] = {"vnet.interface", PF_INTERNAL},
84 [IP__IP4_IFADDR] = {"ip4.addr", PF_INTERNAL | PF_CONV},
84#ifdef INET6
85#ifdef INET6
85 {"ip6.addr", KP_IP6_ADDR, 0 },
86 [IP__IP6_IFADDR] = {"ip6.addr", PF_INTERNAL | PF_CONV},
86#endif
87#endif
87 {"ip_hostname", IP_IP_HOSTNAME, PF_INTERNAL | PF_BOOL },
88 {"jid", KP_JID, PF_INT },
89 {"mount", IP_MOUNT, PF_INTERNAL },
90 {"mount.devfs", IP_MOUNT_DEVFS, PF_INTERNAL | PF_BOOL },
91 {"mount.devfs.ruleset", IP_MOUNT_DEVFS_RULESET, PF_INTERNAL },
92 {"mount.fstab", IP_MOUNT_FSTAB, PF_INTERNAL },
93 {"mount.nodevfs", IP_MOUNT_DEVFS, PF_INTERNAL | PF_BOOL },
94 {"name", KP_NAME, 0 },
95 {"noip_hostname", IP_IP_HOSTNAME, PF_INTERNAL | PF_BOOL },
96 {"nopersist", KP_PERSIST, PF_BOOL },
97 {"path", KP_PATH, 0 },
98 {"persist", KP_PERSIST, PF_BOOL },
99 {"stop.timeout", IP_STOP_TIMEOUT, PF_INTERNAL | PF_INT },
100 {"vnet", KP_VNET, 0 },
101 {"vnet.interface", IP_VNET_INTERFACE, PF_INTERNAL },
88 [KP_ALLOW_CHFLAGS] = {"allow.chflags", 0},
89 [KP_ALLOW_MOUNT] = {"allow.mount", 0},
90 [KP_ALLOW_RAW_SOCKETS] = {"allow.raw_sockets", 0},
91 [KP_ALLOW_SET_HOSTNAME]= {"allow.set_hostname", 0},
92 [KP_ALLOW_SOCKET_AF] = {"allow.socket_af", 0},
93 [KP_ALLOW_SYSVIPC] = {"allow.sysvipc", 0},
94 [KP_ENFORCE_STATFS] = {"enforce_statfs", 0},
95 [KP_HOST_HOSTNAME] = {"host.hostname", 0},
96 [KP_IP4_ADDR] = {"ip4.addr", 0},
97#ifdef INET6
98 [KP_IP6_ADDR] = {"ip6.addr", 0},
99#endif
100 [KP_JID] = {"jid", 0},
101 [KP_NAME] = {"name", 0},
102 [KP_PATH] = {"path", 0},
103 [KP_PERSIST] = {"persist", 0},
104 [KP_SECURELEVEL] = {"securelevel", 0},
105 [KP_VNET] = {"vnet", 0},
102};
103
104/*
105 * Parse the jail configuration file.
106 */
107void
108load_config(void)
109{
110 struct cfjails wild;
111 struct cfparams opp;
112 struct cfjail *j, *tj, *wj;
113 struct cfparam *p, *vp, *tp;
114 struct cfstring *s, *vs, *ns;
115 struct cfvar *v;
116 char *ep;
117 size_t varoff;
118 int did_self, jseq, pgen;
119
120 if (!strcmp(cfname, "-")) {
121 cfname = "STDIN";
122 yyin = stdin;
123 } else {
124 yyin = fopen(cfname, "r");
125 if (!yyin)
126 err(1, "%s", cfname);
127 }
128 if (yyparse() || yynerrs)
129 exit(1);
130
131 /* Separate the wildcard jails out from the actual jails. */
132 jseq = 0;
133 TAILQ_INIT(&wild);
134 TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) {
135 j->seq = ++jseq;
136 if (wild_jail_name(j->name))
137 requeue(j, &wild);
138 }
139
140 TAILQ_FOREACH(j, &cfjails, tq) {
141 /* Set aside the jail's parameters. */
142 TAILQ_INIT(&opp);
143 TAILQ_CONCAT(&opp, &j->params, tq);
144 /*
145 * The jail name implies its "name" or "jid" parameter,
146 * though they may also be explicitly set later on.
147 */
148 add_param(j, NULL,
106};
107
108/*
109 * Parse the jail configuration file.
110 */
111void
112load_config(void)
113{
114 struct cfjails wild;
115 struct cfparams opp;
116 struct cfjail *j, *tj, *wj;
117 struct cfparam *p, *vp, *tp;
118 struct cfstring *s, *vs, *ns;
119 struct cfvar *v;
120 char *ep;
121 size_t varoff;
122 int did_self, jseq, pgen;
123
124 if (!strcmp(cfname, "-")) {
125 cfname = "STDIN";
126 yyin = stdin;
127 } else {
128 yyin = fopen(cfname, "r");
129 if (!yyin)
130 err(1, "%s", cfname);
131 }
132 if (yyparse() || yynerrs)
133 exit(1);
134
135 /* Separate the wildcard jails out from the actual jails. */
136 jseq = 0;
137 TAILQ_INIT(&wild);
138 TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) {
139 j->seq = ++jseq;
140 if (wild_jail_name(j->name))
141 requeue(j, &wild);
142 }
143
144 TAILQ_FOREACH(j, &cfjails, tq) {
145 /* Set aside the jail's parameters. */
146 TAILQ_INIT(&opp);
147 TAILQ_CONCAT(&opp, &j->params, tq);
148 /*
149 * The jail name implies its "name" or "jid" parameter,
150 * though they may also be explicitly set later on.
151 */
152 add_param(j, NULL,
149 strtol(j->name, &ep, 10) && !*ep ? "jid" : "name",
153 strtol(j->name, &ep, 10) && !*ep ? KP_JID : KP_NAME,
150 j->name);
151 /*
152 * Collect parameters for the jail, global parameters/variables,
153 * and any matching wildcard jails.
154 */
155 did_self = 0;
156 TAILQ_FOREACH(wj, &wild, tq) {
157 if (j->seq < wj->seq && !did_self) {
158 TAILQ_FOREACH(p, &opp, tq)
154 j->name);
155 /*
156 * Collect parameters for the jail, global parameters/variables,
157 * and any matching wildcard jails.
158 */
159 did_self = 0;
160 TAILQ_FOREACH(wj, &wild, tq) {
161 if (j->seq < wj->seq && !did_self) {
162 TAILQ_FOREACH(p, &opp, tq)
159 add_param(j, p, NULL, NULL);
163 add_param(j, p, 0, NULL);
160 did_self = 1;
161 }
162 if (wild_jail_match(j->name, wj->name))
163 TAILQ_FOREACH(p, &wj->params, tq)
164 did_self = 1;
165 }
166 if (wild_jail_match(j->name, wj->name))
167 TAILQ_FOREACH(p, &wj->params, tq)
164 add_param(j, p, NULL, NULL);
168 add_param(j, p, 0, NULL);
165 }
166 if (!did_self)
167 TAILQ_FOREACH(p, &opp, tq)
169 }
170 if (!did_self)
171 TAILQ_FOREACH(p, &opp, tq)
168 add_param(j, p, NULL, NULL);
172 add_param(j, p, 0, NULL);
169
170 /* Resolve any variable substitutions. */
171 pgen = 0;
172 TAILQ_FOREACH(p, &j->params, tq) {
173 p->gen = ++pgen;
174 find_vars:
175 STAILQ_FOREACH(s, &p->val, tq) {
176 varoff = 0;
177 while ((v = STAILQ_FIRST(&s->vars))) {
178 TAILQ_FOREACH(vp, &j->params, tq)
179 if (!strcmp(vp->name, v->name))
180 break;
181 if (!vp) {
182 jail_warnx(j,
183 "%s: variable \"%s\" not found",
184 p->name, v->name);
185 bad_var:
186 j->flags |= JF_FAILED;
187 TAILQ_FOREACH(vp, &j->params, tq)
188 if (vp->gen == pgen)
189 vp->flags |= PF_BAD;
190 goto free_var;
191 }
192 if (vp->flags & PF_BAD)
193 goto bad_var;
194 if (vp->gen == pgen) {
195 jail_warnx(j, "%s: variable loop",
196 v->name);
197 goto bad_var;
198 }
199 STAILQ_FOREACH(vs, &vp->val, tq)
200 if (!STAILQ_EMPTY(&vs->vars)) {
201 vp->gen = pgen;
202 TAILQ_REMOVE(&j->params, vp,
203 tq);
204 TAILQ_INSERT_BEFORE(p, vp, tq);
205 p = vp;
206 goto find_vars;
207 }
208 vs = STAILQ_FIRST(&vp->val);
209 if (STAILQ_NEXT(vs, tq) != NULL &&
210 (s->s[0] != '\0' ||
211 STAILQ_NEXT(v, tq))) {
212 jail_warnx(j, "%s: array cannot be "
213 "substituted inline",
214 p->name);
215 goto bad_var;
216 }
217 s->s = erealloc(s->s, s->len + vs->len + 1);
218 memmove(s->s + v->pos + varoff + vs->len,
219 s->s + v->pos + varoff,
220 s->len - (v->pos + varoff) + 1);
221 memcpy(s->s + v->pos + varoff, vs->s, vs->len);
222 varoff += vs->len;
223 s->len += vs->len;
224 while ((vs = STAILQ_NEXT(vs, tq))) {
225 ns = emalloc(sizeof(struct cfstring));
226 ns->s = estrdup(vs->s);
227 ns->len = vs->len;
228 STAILQ_INIT(&ns->vars);
229 STAILQ_INSERT_AFTER(&p->val, s, ns, tq);
230 s = ns;
231 }
232 free_var:
233 free(v->name);
234 STAILQ_REMOVE_HEAD(&s->vars, tq);
235 free(v);
236 }
237 }
238 }
239
240 /* Free the jail's original parameter list and any variables. */
241 while ((p = TAILQ_FIRST(&opp)))
242 free_param(&opp, p);
243 TAILQ_FOREACH_SAFE(p, &j->params, tq, tp)
244 if (p->flags & PF_VAR)
245 free_param(&j->params, p);
246 }
247 while ((wj = TAILQ_FIRST(&wild))) {
248 free(wj->name);
249 while ((p = TAILQ_FIRST(&wj->params)))
250 free_param(&wj->params, p);
251 TAILQ_REMOVE(&wild, wj, tq);
252 }
253}
254
255/*
256 * Create a new jail record.
257 */
258struct cfjail *
259add_jail(void)
260{
261 struct cfjail *j;
262
263 j = emalloc(sizeof(struct cfjail));
264 memset(j, 0, sizeof(struct cfjail));
265 TAILQ_INIT(&j->params);
266 STAILQ_INIT(&j->dep[DEP_FROM]);
267 STAILQ_INIT(&j->dep[DEP_TO]);
268 j->queue = &cfjails;
269 TAILQ_INSERT_TAIL(&cfjails, j, tq);
270 return j;
271}
272
273/*
274 * Add a parameter to a jail.
275 */
276void
173
174 /* Resolve any variable substitutions. */
175 pgen = 0;
176 TAILQ_FOREACH(p, &j->params, tq) {
177 p->gen = ++pgen;
178 find_vars:
179 STAILQ_FOREACH(s, &p->val, tq) {
180 varoff = 0;
181 while ((v = STAILQ_FIRST(&s->vars))) {
182 TAILQ_FOREACH(vp, &j->params, tq)
183 if (!strcmp(vp->name, v->name))
184 break;
185 if (!vp) {
186 jail_warnx(j,
187 "%s: variable \"%s\" not found",
188 p->name, v->name);
189 bad_var:
190 j->flags |= JF_FAILED;
191 TAILQ_FOREACH(vp, &j->params, tq)
192 if (vp->gen == pgen)
193 vp->flags |= PF_BAD;
194 goto free_var;
195 }
196 if (vp->flags & PF_BAD)
197 goto bad_var;
198 if (vp->gen == pgen) {
199 jail_warnx(j, "%s: variable loop",
200 v->name);
201 goto bad_var;
202 }
203 STAILQ_FOREACH(vs, &vp->val, tq)
204 if (!STAILQ_EMPTY(&vs->vars)) {
205 vp->gen = pgen;
206 TAILQ_REMOVE(&j->params, vp,
207 tq);
208 TAILQ_INSERT_BEFORE(p, vp, tq);
209 p = vp;
210 goto find_vars;
211 }
212 vs = STAILQ_FIRST(&vp->val);
213 if (STAILQ_NEXT(vs, tq) != NULL &&
214 (s->s[0] != '\0' ||
215 STAILQ_NEXT(v, tq))) {
216 jail_warnx(j, "%s: array cannot be "
217 "substituted inline",
218 p->name);
219 goto bad_var;
220 }
221 s->s = erealloc(s->s, s->len + vs->len + 1);
222 memmove(s->s + v->pos + varoff + vs->len,
223 s->s + v->pos + varoff,
224 s->len - (v->pos + varoff) + 1);
225 memcpy(s->s + v->pos + varoff, vs->s, vs->len);
226 varoff += vs->len;
227 s->len += vs->len;
228 while ((vs = STAILQ_NEXT(vs, tq))) {
229 ns = emalloc(sizeof(struct cfstring));
230 ns->s = estrdup(vs->s);
231 ns->len = vs->len;
232 STAILQ_INIT(&ns->vars);
233 STAILQ_INSERT_AFTER(&p->val, s, ns, tq);
234 s = ns;
235 }
236 free_var:
237 free(v->name);
238 STAILQ_REMOVE_HEAD(&s->vars, tq);
239 free(v);
240 }
241 }
242 }
243
244 /* Free the jail's original parameter list and any variables. */
245 while ((p = TAILQ_FIRST(&opp)))
246 free_param(&opp, p);
247 TAILQ_FOREACH_SAFE(p, &j->params, tq, tp)
248 if (p->flags & PF_VAR)
249 free_param(&j->params, p);
250 }
251 while ((wj = TAILQ_FIRST(&wild))) {
252 free(wj->name);
253 while ((p = TAILQ_FIRST(&wj->params)))
254 free_param(&wj->params, p);
255 TAILQ_REMOVE(&wild, wj, tq);
256 }
257}
258
259/*
260 * Create a new jail record.
261 */
262struct cfjail *
263add_jail(void)
264{
265 struct cfjail *j;
266
267 j = emalloc(sizeof(struct cfjail));
268 memset(j, 0, sizeof(struct cfjail));
269 TAILQ_INIT(&j->params);
270 STAILQ_INIT(&j->dep[DEP_FROM]);
271 STAILQ_INIT(&j->dep[DEP_TO]);
272 j->queue = &cfjails;
273 TAILQ_INSERT_TAIL(&cfjails, j, tq);
274 return j;
275}
276
277/*
278 * Add a parameter to a jail.
279 */
280void
277add_param(struct cfjail *j, const struct cfparam *p, const char *name,
281add_param(struct cfjail *j, const struct cfparam *p, enum intparam ipnum,
278 const char *value)
279{
280 struct cfstrings nss;
281 struct cfparam *dp, *np;
282 struct cfstring *s, *ns;
283 struct cfvar *v, *nv;
282 const char *value)
283{
284 struct cfstrings nss;
285 struct cfparam *dp, *np;
286 struct cfstring *s, *ns;
287 struct cfvar *v, *nv;
288 struct ipspec *ips;
289 const char *name;
290 char *cs, *tname;
284 unsigned flags;
285
286 if (j == NULL) {
287 /* Create a single anonymous jail if one doesn't yet exist. */
288 j = TAILQ_LAST(&cfjails, cfjails);
289 if (j == NULL)
290 j = add_jail();
291 }
292 STAILQ_INIT(&nss);
293 if (p != NULL) {
294 name = p->name;
295 flags = p->flags;
296 /*
297 * Make a copy of the parameter's string list,
298 * which may be freed if it's overridden later.
299 */
300 STAILQ_FOREACH(s, &p->val, tq) {
301 ns = emalloc(sizeof(struct cfstring));
302 ns->s = estrdup(s->s);
303 ns->len = s->len;
304 STAILQ_INIT(&ns->vars);
305 STAILQ_FOREACH(v, &s->vars, tq) {
306 nv = emalloc(sizeof(struct cfvar));
307 nv->name = strdup(v->name);
308 nv->pos = v->pos;
309 STAILQ_INSERT_TAIL(&ns->vars, nv, tq);
310 }
311 STAILQ_INSERT_TAIL(&nss, ns, tq);
312 }
313 } else {
314 flags = PF_APPEND;
291 unsigned flags;
292
293 if (j == NULL) {
294 /* Create a single anonymous jail if one doesn't yet exist. */
295 j = TAILQ_LAST(&cfjails, cfjails);
296 if (j == NULL)
297 j = add_jail();
298 }
299 STAILQ_INIT(&nss);
300 if (p != NULL) {
301 name = p->name;
302 flags = p->flags;
303 /*
304 * Make a copy of the parameter's string list,
305 * which may be freed if it's overridden later.
306 */
307 STAILQ_FOREACH(s, &p->val, tq) {
308 ns = emalloc(sizeof(struct cfstring));
309 ns->s = estrdup(s->s);
310 ns->len = s->len;
311 STAILQ_INIT(&ns->vars);
312 STAILQ_FOREACH(v, &s->vars, tq) {
313 nv = emalloc(sizeof(struct cfvar));
314 nv->name = strdup(v->name);
315 nv->pos = v->pos;
316 STAILQ_INSERT_TAIL(&ns->vars, nv, tq);
317 }
318 STAILQ_INSERT_TAIL(&nss, ns, tq);
319 }
320 } else {
321 flags = PF_APPEND;
322 if (ipnum != 0) {
323 name = intparams[ipnum].name;
324 flags |= intparams[ipnum].flags;
325 } else if ((cs = strchr(value, '='))) {
326 tname = alloca(cs - value + 1);
327 strlcpy(tname, value, cs - value + 1);
328 name = tname;
329 value = cs + 1;
330 } else {
331 name = value;
332 value = NULL;
333 }
315 if (value != NULL) {
316 ns = emalloc(sizeof(struct cfstring));
317 ns->s = estrdup(value);
318 ns->len = strlen(value);
319 STAILQ_INIT(&ns->vars);
320 STAILQ_INSERT_TAIL(&nss, ns, tq);
321 }
322 }
323
324 /* See if this parameter has already been added. */
334 if (value != NULL) {
335 ns = emalloc(sizeof(struct cfstring));
336 ns->s = estrdup(value);
337 ns->len = strlen(value);
338 STAILQ_INIT(&ns->vars);
339 STAILQ_INSERT_TAIL(&nss, ns, tq);
340 }
341 }
342
343 /* See if this parameter has already been added. */
325 TAILQ_FOREACH(dp, &j->params, tq) {
326 if (equalopts(dp->name, name)) {
327 /* Found it - append or replace. */
328 if (strcmp(dp->name, name)) {
329 free(dp->name);
330 dp->name = estrdup(name);
331 }
332 if (!(flags & PF_APPEND) || STAILQ_EMPTY(&nss))
333 free_param_strings(dp);
334 STAILQ_CONCAT(&dp->val, &nss);
335 dp->flags |= flags;
336 break;
344 if (ipnum != 0)
345 dp = j->intparams[ipnum];
346 else
347 TAILQ_FOREACH(dp, &j->params, tq)
348 if (!(dp->flags & PF_CONV) && equalopts(dp->name, name))
349 break;
350 if (dp != NULL) {
351 /* Found it - append or replace. */
352 if (strcmp(dp->name, name)) {
353 free(dp->name);
354 dp->name = estrdup(name);
337 }
355 }
338 }
339 if (dp == NULL) {
356 if (!(flags & PF_APPEND) || STAILQ_EMPTY(&nss))
357 free_param_strings(dp);
358 STAILQ_CONCAT(&dp->val, &nss);
359 dp->flags |= flags;
360 } else {
340 /* Not found - add it. */
341 np = emalloc(sizeof(struct cfparam));
342 np->name = estrdup(name);
343 STAILQ_INIT(&np->val);
344 STAILQ_CONCAT(&np->val, &nss);
345 np->flags = flags;
346 np->gen = 0;
347 TAILQ_INSERT_TAIL(&j->params, np, tq);
361 /* Not found - add it. */
362 np = emalloc(sizeof(struct cfparam));
363 np->name = estrdup(name);
364 STAILQ_INIT(&np->val);
365 STAILQ_CONCAT(&np->val, &nss);
366 np->flags = flags;
367 np->gen = 0;
368 TAILQ_INSERT_TAIL(&j->params, np, tq);
369 if (ipnum != 0)
370 j->intparams[ipnum] = np;
371 else
372 for (ipnum = 1; ipnum < IP_NPARAM; ipnum++)
373 if (!(intparams[ipnum].flags & PF_CONV) &&
374 equalopts(name, intparams[ipnum].name)) {
375 j->intparams[ipnum] = np;
376 np->flags |= intparams[ipnum].flags;
377 break;
378 }
348 }
349}
350
351/*
379 }
380}
381
382/*
352 * Find internal or known parameters.
353 */
354void
355find_intparams(void)
356{
357 struct cfjail *j;
358 struct cfparam *p;
359 struct ipspec *ip;
360
361 TAILQ_FOREACH(j, &cfjails, tq) {
362 TAILQ_FOREACH(p, &j->params, tq) {
363 ip = bsearch(p->name, intparams,
364 sizeof(intparams) / sizeof(intparams[0]),
365 sizeof(struct ipspec), cmp_intparam);
366 if (ip != NULL) {
367 j->intparams[ip->ipnum] = p;
368 p->flags |= ip->flags;
369 }
370 }
371 }
372}
373
374/*
375 * Check syntax of internal parameters.
376 */
377int
378check_intparams(struct cfjail *j)
379{
380 struct cfparam *p;
381 const char *val;
382 char *ep;
383 int error;
384
385 error = 0;
386 TAILQ_FOREACH(p, &j->params, tq) {
387 if (!STAILQ_EMPTY(&p->val) &&
388 (p->flags & (PF_BOOL | PF_INT))) {
389 val = STAILQ_LAST(&p->val, cfstring, tq)->s;
390 if (p->flags & PF_BOOL) {
391 if (strcasecmp(val, "false") &&
392 strcasecmp(val, "true") &&
393 ((void)strtol(val, &ep, 10), *ep)) {
394 jail_warnx(j,
395 "%s: unknown boolean value \"%s\"",
396 p->name, val);
397 error = -1;
398 }
399 } else {
400 (void)strtol(val, &ep, 10);
401 if (ep == val || *ep) {
402 jail_warnx(j,
403 "%s: non-integer value \"%s\"",
404 p->name, val);
405 error = -1;
406 }
407 }
408 }
409 }
410 return error;
411}
412
413/*
414 * Return if a boolean parameter exists and is true.
415 */
416int
417bool_param(const struct cfparam *p)
418{
419 const char *cs;
420
421 if (p == NULL)
422 return 0;
423 cs = strrchr(p->name, '.');
424 return !strncmp(cs ? cs + 1 : p->name, "no", 2) ^
425 (STAILQ_EMPTY(&p->val) ||
426 !strcasecmp(STAILQ_LAST(&p->val, cfstring, tq)->s, "true") ||
427 (strtol(STAILQ_LAST(&p->val, cfstring, tq)->s, NULL, 10)));
428}
429
430/*
431 * Set an integer if a parameter if it exists.
432 */
433int
434int_param(const struct cfparam *p, int *ip)
435{
436 if (p == NULL || STAILQ_EMPTY(&p->val))
437 return 0;
438 *ip = strtol(STAILQ_LAST(&p->val, cfstring, tq)->s, NULL, 10);
439 return 1;
440}
441
442/*
443 * Return the string value of a scalar parameter if it exists.
444 */
445const char *
446string_param(const struct cfparam *p)
447{
448 return (p && !STAILQ_EMPTY(&p->val)
449 ? STAILQ_LAST(&p->val, cfstring, tq)->s : NULL);
450}
451
452/*
453 * Look up extra IP addresses from the hostname and save interface and netmask.
454 */
455int
456ip_params(struct cfjail *j)
457{
458 struct in_addr addr4;
459 struct addrinfo hints, *ai0, *ai;
383 * Check syntax of internal parameters.
384 */
385int
386check_intparams(struct cfjail *j)
387{
388 struct cfparam *p;
389 const char *val;
390 char *ep;
391 int error;
392
393 error = 0;
394 TAILQ_FOREACH(p, &j->params, tq) {
395 if (!STAILQ_EMPTY(&p->val) &&
396 (p->flags & (PF_BOOL | PF_INT))) {
397 val = STAILQ_LAST(&p->val, cfstring, tq)->s;
398 if (p->flags & PF_BOOL) {
399 if (strcasecmp(val, "false") &&
400 strcasecmp(val, "true") &&
401 ((void)strtol(val, &ep, 10), *ep)) {
402 jail_warnx(j,
403 "%s: unknown boolean value \"%s\"",
404 p->name, val);
405 error = -1;
406 }
407 } else {
408 (void)strtol(val, &ep, 10);
409 if (ep == val || *ep) {
410 jail_warnx(j,
411 "%s: non-integer value \"%s\"",
412 p->name, val);
413 error = -1;
414 }
415 }
416 }
417 }
418 return error;
419}
420
421/*
422 * Return if a boolean parameter exists and is true.
423 */
424int
425bool_param(const struct cfparam *p)
426{
427 const char *cs;
428
429 if (p == NULL)
430 return 0;
431 cs = strrchr(p->name, '.');
432 return !strncmp(cs ? cs + 1 : p->name, "no", 2) ^
433 (STAILQ_EMPTY(&p->val) ||
434 !strcasecmp(STAILQ_LAST(&p->val, cfstring, tq)->s, "true") ||
435 (strtol(STAILQ_LAST(&p->val, cfstring, tq)->s, NULL, 10)));
436}
437
438/*
439 * Set an integer if a parameter if it exists.
440 */
441int
442int_param(const struct cfparam *p, int *ip)
443{
444 if (p == NULL || STAILQ_EMPTY(&p->val))
445 return 0;
446 *ip = strtol(STAILQ_LAST(&p->val, cfstring, tq)->s, NULL, 10);
447 return 1;
448}
449
450/*
451 * Return the string value of a scalar parameter if it exists.
452 */
453const char *
454string_param(const struct cfparam *p)
455{
456 return (p && !STAILQ_EMPTY(&p->val)
457 ? STAILQ_LAST(&p->val, cfstring, tq)->s : NULL);
458}
459
460/*
461 * Look up extra IP addresses from the hostname and save interface and netmask.
462 */
463int
464ip_params(struct cfjail *j)
465{
466 struct in_addr addr4;
467 struct addrinfo hints, *ai0, *ai;
460 struct cfparam *np;
461 struct cfstring *s, *ns;
462 char *cs, *ep;
463 const char *hostname;
464 size_t size;
465 int error, ip4ok, defif, prefix;
466 int mib[4];
467 char avalue4[INET_ADDRSTRLEN];
468#ifdef INET6
469 struct in6_addr addr6;
470 int ip6ok, isip6;
471 char avalue6[INET6_ADDRSTRLEN];
472#endif
473
474 error = 0;
475 /*
476 * The ip_hostname parameter looks up the hostname, and adds parameters
477 * for any IP addresses it finds.
478 */
479 if (bool_param(j->intparams[IP_IP_HOSTNAME]) &&
468 struct cfstring *s, *ns;
469 char *cs, *ep;
470 const char *hostname;
471 size_t size;
472 int error, ip4ok, defif, prefix;
473 int mib[4];
474 char avalue4[INET_ADDRSTRLEN];
475#ifdef INET6
476 struct in6_addr addr6;
477 int ip6ok, isip6;
478 char avalue6[INET6_ADDRSTRLEN];
479#endif
480
481 error = 0;
482 /*
483 * The ip_hostname parameter looks up the hostname, and adds parameters
484 * for any IP addresses it finds.
485 */
486 if (bool_param(j->intparams[IP_IP_HOSTNAME]) &&
480 (hostname = string_param(j->intparams[KP_HOSTNAME]))) {
487 (hostname = string_param(j->intparams[KP_HOST_HOSTNAME]))) {
481 j->intparams[IP_IP_HOSTNAME] = NULL;
482 /*
483 * Silently ignore unsupported address families from
484 * DNS lookups.
485 */
486 size = 4;
487 ip4ok = sysctlnametomib("security.jail.param.ip4", mib, &size)
488 == 0;
489#ifdef INET6
490 size = 4;
491 ip6ok = sysctlnametomib("security.jail.param.ip6", mib, &size)
492 == 0;
493#endif
494 if (ip4ok
495#ifdef INET6
496 || ip6ok
497#endif
498 ) {
499 /* Look up the hostname (or get the address) */
500 memset(&hints, 0, sizeof(hints));
501 hints.ai_socktype = SOCK_STREAM;
502 hints.ai_family =
503#ifdef INET6
504 ip6ok ? (ip4ok ? PF_UNSPEC : PF_INET6) :
505#endif
506 PF_INET;
507 error = getaddrinfo(hostname, NULL, &hints, &ai0);
508 if (error != 0) {
509 jail_warnx(j, "host.hostname %s: %s", hostname,
510 gai_strerror(error));
511 error = -1;
512 } else {
513 /*
514 * Convert the addresses to ASCII so jailparam
515 * can convert them back. Errors are not
516 * expected here.
517 */
518 for (ai = ai0; ai; ai = ai->ai_next)
519 switch (ai->ai_family) {
520 case AF_INET:
521 memcpy(&addr4,
522 &((struct sockaddr_in *)
523 (void *)ai->ai_addr)->
524 sin_addr, sizeof(addr4));
525 if (inet_ntop(AF_INET,
526 &addr4, avalue4,
527 INET_ADDRSTRLEN) == NULL)
528 err(1, "inet_ntop");
488 j->intparams[IP_IP_HOSTNAME] = NULL;
489 /*
490 * Silently ignore unsupported address families from
491 * DNS lookups.
492 */
493 size = 4;
494 ip4ok = sysctlnametomib("security.jail.param.ip4", mib, &size)
495 == 0;
496#ifdef INET6
497 size = 4;
498 ip6ok = sysctlnametomib("security.jail.param.ip6", mib, &size)
499 == 0;
500#endif
501 if (ip4ok
502#ifdef INET6
503 || ip6ok
504#endif
505 ) {
506 /* Look up the hostname (or get the address) */
507 memset(&hints, 0, sizeof(hints));
508 hints.ai_socktype = SOCK_STREAM;
509 hints.ai_family =
510#ifdef INET6
511 ip6ok ? (ip4ok ? PF_UNSPEC : PF_INET6) :
512#endif
513 PF_INET;
514 error = getaddrinfo(hostname, NULL, &hints, &ai0);
515 if (error != 0) {
516 jail_warnx(j, "host.hostname %s: %s", hostname,
517 gai_strerror(error));
518 error = -1;
519 } else {
520 /*
521 * Convert the addresses to ASCII so jailparam
522 * can convert them back. Errors are not
523 * expected here.
524 */
525 for (ai = ai0; ai; ai = ai->ai_next)
526 switch (ai->ai_family) {
527 case AF_INET:
528 memcpy(&addr4,
529 &((struct sockaddr_in *)
530 (void *)ai->ai_addr)->
531 sin_addr, sizeof(addr4));
532 if (inet_ntop(AF_INET,
533 &addr4, avalue4,
534 INET_ADDRSTRLEN) == NULL)
535 err(1, "inet_ntop");
529 add_param(j, NULL, "ip4.addr",
536 add_param(j, NULL, KP_IP4_ADDR,
530 avalue4);
531 break;
532#ifdef INET6
533 case AF_INET6:
534 memcpy(&addr6,
535 &((struct sockaddr_in6 *)
536 (void *)ai->ai_addr)->
537 sin6_addr, sizeof(addr6));
538 if (inet_ntop(AF_INET6,
539 &addr6, avalue6,
540 INET6_ADDRSTRLEN) == NULL)
541 err(1, "inet_ntop");
537 avalue4);
538 break;
539#ifdef INET6
540 case AF_INET6:
541 memcpy(&addr6,
542 &((struct sockaddr_in6 *)
543 (void *)ai->ai_addr)->
544 sin6_addr, sizeof(addr6));
545 if (inet_ntop(AF_INET6,
546 &addr6, avalue6,
547 INET6_ADDRSTRLEN) == NULL)
548 err(1, "inet_ntop");
542 add_param(j, NULL, "ip6.addr",
549 add_param(j, NULL, KP_IP6_ADDR,
543 avalue6);
544 break;
545#endif
546 }
547 freeaddrinfo(ai0);
548 }
549 }
550 }
551 /*
552 * IP addresses may include an interface to set that address on,
553 * and a netmask/suffix for that address.
554 */
555 defif = string_param(j->intparams[IP_INTERFACE]) != NULL;
556#ifdef INET6
557 for (isip6 = 0; isip6 <= 1; isip6++)
558#else
559#define isip6 0
560 do
561#endif
562 {
563 if (j->intparams[KP_IP4_ADDR + isip6] == NULL)
564 continue;
550 avalue6);
551 break;
552#endif
553 }
554 freeaddrinfo(ai0);
555 }
556 }
557 }
558 /*
559 * IP addresses may include an interface to set that address on,
560 * and a netmask/suffix for that address.
561 */
562 defif = string_param(j->intparams[IP_INTERFACE]) != NULL;
563#ifdef INET6
564 for (isip6 = 0; isip6 <= 1; isip6++)
565#else
566#define isip6 0
567 do
568#endif
569 {
570 if (j->intparams[KP_IP4_ADDR + isip6] == NULL)
571 continue;
565 np = j->intparams[IP__IP4_IFADDR + isip6];
566 STAILQ_FOREACH(s, &j->intparams[KP_IP4_ADDR + isip6]->val, tq) {
567 cs = strchr(s->s, '|');
572 STAILQ_FOREACH(s, &j->intparams[KP_IP4_ADDR + isip6]->val, tq) {
573 cs = strchr(s->s, '|');
568 if (cs || defif) {
569 if (np == NULL) {
570 np = j->intparams[IP__IP4_IFADDR +
571 isip6] =
572 emalloc(sizeof(struct cfparam));
573 np->name = estrdup(j->intparams
574 [KP_IP4_ADDR + isip6]->name);
575 STAILQ_INIT(&np->val);
576 np->flags = PF_INTERNAL;
577 }
578 ns = emalloc(sizeof(struct cfstring));
579 ns->s = estrdup(s->s);
580 ns->len = s->len;
581 STAILQ_INIT(&ns->vars);
582 STAILQ_INSERT_TAIL(&np->val, ns, tq);
583 if (cs != NULL) {
584 strcpy(s->s, cs + 1);
585 s->len -= cs - s->s + 1;
586 }
574 if (cs || defif)
575 add_param(j, NULL, IP__IP4_IFADDR + isip6,
576 s->s);
577 if (cs) {
578 strcpy(s->s, cs + 1);
579 s->len -= cs + 1 - s->s;
587 }
588 if ((cs = strchr(s->s, '/'))) {
589 prefix = strtol(cs + 1, &ep, 10);
590 if (!isip6 && *ep == '.'
591 ? inet_pton(AF_INET, cs + 1, &addr4) != 1
592 : *ep || prefix < 0 || prefix >
593 (isip6 ? 128 : 32)) {
594 jail_warnx(j, isip6
595 ? "ip6.addr: bad prefixlen \"%s\""
596 : "ip4.addr: bad netmask \"%s\"",
597 cs);
598 error = -1;
599 }
600 *cs = '\0';
601 s->len = cs - s->s + 1;
602 }
603 }
604 }
605#ifndef INET6
606 while (0);
607#endif
608 return error;
609}
610
611/*
612 * Import parameters into libjail's binary jailparam format.
613 */
614int
615import_params(struct cfjail *j)
616{
617 struct cfparam *p;
618 struct cfstring *s, *ts;
619 struct jailparam *jp;
620 char *value, *cs;
621 size_t vallen;
622 int error;
623
624 error = 0;
625 j->njp = 0;
626 TAILQ_FOREACH(p, &j->params, tq)
627 if (!(p->flags & PF_INTERNAL))
628 j->njp++;
629 j->jp = jp = emalloc(j->njp * sizeof(struct jailparam));
630 TAILQ_FOREACH(p, &j->params, tq) {
631 if (p->flags & PF_INTERNAL)
632 continue;
633 if (jailparam_init(jp, p->name) < 0) {
634 error = -1;
635 jail_warnx(j, "%s", jail_errmsg);
636 continue;
637 }
638 if (STAILQ_EMPTY(&p->val))
639 value = NULL;
640 else if (!jp->jp_elemlen ||
641 !STAILQ_NEXT(STAILQ_FIRST(&p->val), tq)) {
642 /*
643 * Scalar parameters silently discard multiple (array)
644 * values, keeping only the last value added. This
645 * lets values added from the command line append to
646 * arrays wthout pre-checking the type.
647 */
648 value = STAILQ_LAST(&p->val, cfstring, tq)->s;
649 } else {
650 /*
651 * Convert arrays into comma-separated strings, which
652 * jailparam_import will then convert back into arrays.
653 */
654 vallen = 0;
655 STAILQ_FOREACH(s, &p->val, tq)
656 vallen += s->len + 1;
657 value = alloca(vallen);
658 cs = value;
659 STAILQ_FOREACH_SAFE(s, &p->val, tq, ts) {
660 strcpy(cs, s->s);
661 if (ts != NULL) {
662 cs += s->len + 1;
663 cs[-1] = ',';
664 }
665 }
666 }
667 if (jailparam_import(jp, value) < 0) {
668 error = -1;
669 jail_warnx(j, "%s", jail_errmsg);
670 }
671 jp++;
672 }
673 if (error) {
674 jailparam_free(j->jp, j->njp);
675 free(j->jp);
676 j->jp = NULL;
677 failed(j);
678 }
679 return error;
680}
681
682/*
683 * Check if options are equal (with or without the "no" prefix).
684 */
685int
686equalopts(const char *opt1, const char *opt2)
687{
688 char *p;
689
690 /* "opt" vs. "opt" or "noopt" vs. "noopt" */
691 if (strcmp(opt1, opt2) == 0)
692 return (1);
693 /* "noopt" vs. "opt" */
694 if (strncmp(opt1, "no", 2) == 0 && strcmp(opt1 + 2, opt2) == 0)
695 return (1);
696 /* "opt" vs. "noopt" */
697 if (strncmp(opt2, "no", 2) == 0 && strcmp(opt1, opt2 + 2) == 0)
698 return (1);
699 while ((p = strchr(opt1, '.')) != NULL &&
700 !strncmp(opt1, opt2, ++p - opt1)) {
701 opt2 += p - opt1;
702 opt1 = p;
703 /* "foo.noopt" vs. "foo.opt" */
704 if (strncmp(opt1, "no", 2) == 0 && strcmp(opt1 + 2, opt2) == 0)
705 return (1);
706 /* "foo.opt" vs. "foo.noopt" */
707 if (strncmp(opt2, "no", 2) == 0 && strcmp(opt1, opt2 + 2) == 0)
708 return (1);
709 }
710 return (0);
711}
712
713/*
714 * See if a jail name matches a wildcard.
715 */
716int
717wild_jail_match(const char *jname, const char *wname)
718{
719 const char *jc, *jd, *wc, *wd;
720
721 /*
722 * A non-final "*" component in the wild name matches a single jail
723 * component, and a final "*" matches one or more jail components.
724 */
725 for (jc = jname, wc = wname;
726 (jd = strchr(jc, '.')) && (wd = strchr(wc, '.'));
727 jc = jd + 1, wc = wd + 1)
728 if (strncmp(jc, wc, jd - jc + 1) && strncmp(wc, "*.", 2))
729 return 0;
730 return (!strcmp(jc, wc) || !strcmp(wc, "*"));
731}
732
733/*
734 * Return if a jail name is a wildcard.
735 */
736int
737wild_jail_name(const char *wname)
738{
739 const char *wc;
740
741 for (wc = strchr(wname, '*'); wc; wc = strchr(wc + 1, '*'))
742 if ((wc == wname || wc[-1] == '.') &&
743 (wc[1] == '\0' || wc[1] == '.'))
744 return 1;
745 return 0;
746}
747
748/*
580 }
581 if ((cs = strchr(s->s, '/'))) {
582 prefix = strtol(cs + 1, &ep, 10);
583 if (!isip6 && *ep == '.'
584 ? inet_pton(AF_INET, cs + 1, &addr4) != 1
585 : *ep || prefix < 0 || prefix >
586 (isip6 ? 128 : 32)) {
587 jail_warnx(j, isip6
588 ? "ip6.addr: bad prefixlen \"%s\""
589 : "ip4.addr: bad netmask \"%s\"",
590 cs);
591 error = -1;
592 }
593 *cs = '\0';
594 s->len = cs - s->s + 1;
595 }
596 }
597 }
598#ifndef INET6
599 while (0);
600#endif
601 return error;
602}
603
604/*
605 * Import parameters into libjail's binary jailparam format.
606 */
607int
608import_params(struct cfjail *j)
609{
610 struct cfparam *p;
611 struct cfstring *s, *ts;
612 struct jailparam *jp;
613 char *value, *cs;
614 size_t vallen;
615 int error;
616
617 error = 0;
618 j->njp = 0;
619 TAILQ_FOREACH(p, &j->params, tq)
620 if (!(p->flags & PF_INTERNAL))
621 j->njp++;
622 j->jp = jp = emalloc(j->njp * sizeof(struct jailparam));
623 TAILQ_FOREACH(p, &j->params, tq) {
624 if (p->flags & PF_INTERNAL)
625 continue;
626 if (jailparam_init(jp, p->name) < 0) {
627 error = -1;
628 jail_warnx(j, "%s", jail_errmsg);
629 continue;
630 }
631 if (STAILQ_EMPTY(&p->val))
632 value = NULL;
633 else if (!jp->jp_elemlen ||
634 !STAILQ_NEXT(STAILQ_FIRST(&p->val), tq)) {
635 /*
636 * Scalar parameters silently discard multiple (array)
637 * values, keeping only the last value added. This
638 * lets values added from the command line append to
639 * arrays wthout pre-checking the type.
640 */
641 value = STAILQ_LAST(&p->val, cfstring, tq)->s;
642 } else {
643 /*
644 * Convert arrays into comma-separated strings, which
645 * jailparam_import will then convert back into arrays.
646 */
647 vallen = 0;
648 STAILQ_FOREACH(s, &p->val, tq)
649 vallen += s->len + 1;
650 value = alloca(vallen);
651 cs = value;
652 STAILQ_FOREACH_SAFE(s, &p->val, tq, ts) {
653 strcpy(cs, s->s);
654 if (ts != NULL) {
655 cs += s->len + 1;
656 cs[-1] = ',';
657 }
658 }
659 }
660 if (jailparam_import(jp, value) < 0) {
661 error = -1;
662 jail_warnx(j, "%s", jail_errmsg);
663 }
664 jp++;
665 }
666 if (error) {
667 jailparam_free(j->jp, j->njp);
668 free(j->jp);
669 j->jp = NULL;
670 failed(j);
671 }
672 return error;
673}
674
675/*
676 * Check if options are equal (with or without the "no" prefix).
677 */
678int
679equalopts(const char *opt1, const char *opt2)
680{
681 char *p;
682
683 /* "opt" vs. "opt" or "noopt" vs. "noopt" */
684 if (strcmp(opt1, opt2) == 0)
685 return (1);
686 /* "noopt" vs. "opt" */
687 if (strncmp(opt1, "no", 2) == 0 && strcmp(opt1 + 2, opt2) == 0)
688 return (1);
689 /* "opt" vs. "noopt" */
690 if (strncmp(opt2, "no", 2) == 0 && strcmp(opt1, opt2 + 2) == 0)
691 return (1);
692 while ((p = strchr(opt1, '.')) != NULL &&
693 !strncmp(opt1, opt2, ++p - opt1)) {
694 opt2 += p - opt1;
695 opt1 = p;
696 /* "foo.noopt" vs. "foo.opt" */
697 if (strncmp(opt1, "no", 2) == 0 && strcmp(opt1 + 2, opt2) == 0)
698 return (1);
699 /* "foo.opt" vs. "foo.noopt" */
700 if (strncmp(opt2, "no", 2) == 0 && strcmp(opt1, opt2 + 2) == 0)
701 return (1);
702 }
703 return (0);
704}
705
706/*
707 * See if a jail name matches a wildcard.
708 */
709int
710wild_jail_match(const char *jname, const char *wname)
711{
712 const char *jc, *jd, *wc, *wd;
713
714 /*
715 * A non-final "*" component in the wild name matches a single jail
716 * component, and a final "*" matches one or more jail components.
717 */
718 for (jc = jname, wc = wname;
719 (jd = strchr(jc, '.')) && (wd = strchr(wc, '.'));
720 jc = jd + 1, wc = wd + 1)
721 if (strncmp(jc, wc, jd - jc + 1) && strncmp(wc, "*.", 2))
722 return 0;
723 return (!strcmp(jc, wc) || !strcmp(wc, "*"));
724}
725
726/*
727 * Return if a jail name is a wildcard.
728 */
729int
730wild_jail_name(const char *wname)
731{
732 const char *wc;
733
734 for (wc = strchr(wname, '*'); wc; wc = strchr(wc + 1, '*'))
735 if ((wc == wname || wc[-1] == '.') &&
736 (wc[1] == '\0' || wc[1] == '.'))
737 return 1;
738 return 0;
739}
740
741/*
749 * Compare strings and intparams for bsearch.
750 */
751
752static int
753cmp_intparam(const void *a, const void *b)
754{
755 return strcmp((const char *)a, ((const struct ipspec *)b)->name);
756}
757
758/*
759 * Free a parameter record and all its strings and variables.
760 */
761static void
762free_param(struct cfparams *pp, struct cfparam *p)
763{
764 free(p->name);
765 free_param_strings(p);
766 TAILQ_REMOVE(pp, p, tq);
767 free(p);
768}
769
770static void
771free_param_strings(struct cfparam *p)
772{
773 struct cfstring *s;
774 struct cfvar *v;
775
776 while ((s = STAILQ_FIRST(&p->val))) {
777 free(s->s);
778 while ((v = STAILQ_FIRST(&s->vars))) {
779 free(v->name);
780 STAILQ_REMOVE_HEAD(&s->vars, tq);
781 free(v);
782 }
783 STAILQ_REMOVE_HEAD(&p->val, tq);
784 free(s);
785 }
786}
742 * Free a parameter record and all its strings and variables.
743 */
744static void
745free_param(struct cfparams *pp, struct cfparam *p)
746{
747 free(p->name);
748 free_param_strings(p);
749 TAILQ_REMOVE(pp, p, tq);
750 free(p);
751}
752
753static void
754free_param_strings(struct cfparam *p)
755{
756 struct cfstring *s;
757 struct cfvar *v;
758
759 while ((s = STAILQ_FIRST(&p->val))) {
760 free(s->s);
761 while ((v = STAILQ_FIRST(&s->vars))) {
762 free(v->name);
763 STAILQ_REMOVE_HEAD(&s->vars, tq);
764 free(v);
765 }
766 STAILQ_REMOVE_HEAD(&p->val, tq);
767 free(s);
768 }
769}