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