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