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