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