config.c revision 256387
1139743Simp/*- 239212Sgibbs * Copyright (c) 2011 James Gritton 339212Sgibbs * All rights reserved. 439212Sgibbs * 539212Sgibbs * Redistribution and use in source and binary forms, with or without 639212Sgibbs * modification, are permitted provided that the following conditions 739212Sgibbs * are met: 839212Sgibbs * 1. Redistributions of source code must retain the above copyright 939212Sgibbs * notice, this list of conditions and the following disclaimer. 1039212Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1139212Sgibbs * notice, this list of conditions and the following disclaimer in the 1239212Sgibbs * documentation and/or other materials provided with the distribution. 1339212Sgibbs * 1439212Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1539212Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1639212Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1739212Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1839212Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1939212Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2039212Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2139212Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2239212Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2339212Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2439212Sgibbs * SUCH DAMAGE. 2539212Sgibbs */ 2639212Sgibbs 2739212Sgibbs#include <sys/cdefs.h> 2850477Speter__FBSDID("$FreeBSD: stable/10/usr.sbin/jail/config.c 256387 2013-10-12 17:46:13Z hrs $"); 2939212Sgibbs 3039212Sgibbs#include <sys/types.h> 3139212Sgibbs#include <sys/errno.h> 3239212Sgibbs#include <sys/socket.h> 3339212Sgibbs#include <sys/sysctl.h> 3439212Sgibbs 3539212Sgibbs#include <arpa/inet.h> 3647412Sgibbs#include <netinet/in.h> 37114216Skan 3855206Speter#include <err.h> 3939212Sgibbs#include <netdb.h> 4039212Sgibbs#include <stdio.h> 4139212Sgibbs#include <stdlib.h> 4239212Sgibbs#include <string.h> 43195534Sscottl#include <unistd.h> 4439212Sgibbs 4539212Sgibbs#include "jailp.h" 4639212Sgibbs 4739212Sgibbsstruct ipspec { 4839212Sgibbs const char *name; 4939212Sgibbs unsigned flags; 5039212Sgibbs}; 5139212Sgibbs 5239212Sgibbsextern FILE *yyin; 5339212Sgibbsextern int yynerrs; 5439212Sgibbs 5539212Sgibbsextern int yyparse(void); 5639212Sgibbs 5739212Sgibbsstruct cfjails cfjails = TAILQ_HEAD_INITIALIZER(cfjails); 5839212Sgibbs 5939212Sgibbsstatic void free_param(struct cfparams *pp, struct cfparam *p); 6039212Sgibbsstatic void free_param_strings(struct cfparam *p); 6139212Sgibbs 6263455Sgibbsstatic const struct ipspec intparams[] = { 6363455Sgibbs [IP_ALLOW_DYING] = {"allow.dying", PF_INTERNAL | PF_BOOL}, 6463455Sgibbs [IP_COMMAND] = {"command", PF_INTERNAL}, 6563455Sgibbs [IP_DEPEND] = {"depend", PF_INTERNAL}, 66246713Skib [IP_EXEC_CLEAN] = {"exec.clean", PF_INTERNAL | PF_BOOL}, 6739212Sgibbs [IP_EXEC_CONSOLELOG] = {"exec.consolelog", PF_INTERNAL}, 68216088Sken [IP_EXEC_FIB] = {"exec.fib", PF_INTERNAL | PF_INT}, 6939212Sgibbs [IP_EXEC_JAIL_USER] = {"exec.jail_user", PF_INTERNAL}, 7039212Sgibbs [IP_EXEC_POSTSTART] = {"exec.poststart", PF_INTERNAL}, 7139212Sgibbs [IP_EXEC_POSTSTOP] = {"exec.poststop", PF_INTERNAL}, 7239212Sgibbs [IP_EXEC_PRESTART] = {"exec.prestart", PF_INTERNAL}, 73246713Skib [IP_EXEC_PRESTOP] = {"exec.prestop", PF_INTERNAL}, 74246713Skib [IP_EXEC_START] = {"exec.start", PF_INTERNAL}, 75246713Skib [IP_EXEC_STOP] = {"exec.stop", PF_INTERNAL}, 76246713Skib [IP_EXEC_SYSTEM_JAIL_USER]= {"exec.system_jail_user", 77246713Skib PF_INTERNAL | PF_BOOL}, 78246713Skib [IP_EXEC_SYSTEM_USER] = {"exec.system_user", PF_INTERNAL}, 7939212Sgibbs [IP_EXEC_TIMEOUT] = {"exec.timeout", PF_INTERNAL | PF_INT}, 8039212Sgibbs#if defined(INET) || defined(INET6) 8139212Sgibbs [IP_INTERFACE] = {"interface", PF_INTERNAL}, 8239212Sgibbs [IP_IP_HOSTNAME] = {"ip_hostname", PF_INTERNAL | PF_BOOL}, 8339212Sgibbs#endif 8439212Sgibbs [IP_MOUNT] = {"mount", PF_INTERNAL | PF_REV}, 8539212Sgibbs [IP_MOUNT_DEVFS] = {"mount.devfs", PF_INTERNAL | PF_BOOL}, 8639212Sgibbs [IP_MOUNT_FDESCFS] = {"mount.fdescfs", PF_INTERNAL | PF_BOOL}, 8739212Sgibbs [IP_MOUNT_FSTAB] = {"mount.fstab", PF_INTERNAL}, 8839212Sgibbs [IP_STOP_TIMEOUT] = {"stop.timeout", PF_INTERNAL | PF_INT}, 8939212Sgibbs [IP_VNET_INTERFACE] = {"vnet.interface", PF_INTERNAL}, 9039212Sgibbs#ifdef INET 9139212Sgibbs [IP__IP4_IFADDR] = {"ip4.addr", PF_INTERNAL | PF_CONV | PF_REV}, 9239212Sgibbs#endif 9339212Sgibbs#ifdef INET6 9439212Sgibbs [IP__IP6_IFADDR] = {"ip6.addr", PF_INTERNAL | PF_CONV | PF_REV}, 9558111Sn_hibma#endif 9639212Sgibbs [IP__MOUNT_FROM_FSTAB] = {"mount.fstab", PF_INTERNAL | PF_CONV | PF_REV}, 9739212Sgibbs [IP__OP] = {NULL, PF_CONV}, 9839212Sgibbs [KP_ALLOW_CHFLAGS] = {"allow.chflags", 0}, 9956145Smjacob [KP_ALLOW_MOUNT] = {"allow.mount", 0}, 10056145Smjacob [KP_ALLOW_RAW_SOCKETS] = {"allow.raw_sockets", 0}, 10156145Smjacob [KP_ALLOW_SET_HOSTNAME]= {"allow.set_hostname", 0}, 102248520Skib [KP_ALLOW_SOCKET_AF] = {"allow.socket_af", 0}, 10339212Sgibbs [KP_ALLOW_SYSVIPC] = {"allow.sysvipc", 0}, 10456145Smjacob [KP_DEVFS_RULESET] = {"devfs_ruleset", 0}, 10556145Smjacob [KP_ENFORCE_STATFS] = {"enforce_statfs", 0}, 10656145Smjacob [KP_HOST_HOSTNAME] = {"host.hostname", 0}, 107260387Sscottl#ifdef INET 108260387Sscottl [KP_IP4_ADDR] = {"ip4.addr", 0}, 109260387Sscottl#endif 11039212Sgibbs#ifdef INET6 11139212Sgibbs [KP_IP6_ADDR] = {"ip6.addr", 0}, 112255870Sscottl#endif 113255870Sscottl [KP_JID] = {"jid", 0}, 114292348Sken [KP_NAME] = {"name", 0}, 115292348Sken [KP_PATH] = {"path", 0}, 116292348Sken [KP_PERSIST] = {"persist", 0}, 117255870Sscottl [KP_SECURELEVEL] = {"securelevel", 0}, 118255870Sscottl [KP_VNET] = {"vnet", 0}, 11939212Sgibbs}; 12039212Sgibbs 12146581Sken/* 12246581Sken * Parse the jail configuration file. 12346581Sken */ 12446581Skenvoid 12546581Skenload_config(void) 12646581Sken{ 12749925Sgibbs struct cfjails wild; 12849925Sgibbs struct cfparams opp; 12939212Sgibbs struct cfjail *j, *tj, *wj; 13046581Sken struct cfparam *p, *vp, *tp; 13146581Sken struct cfstring *s, *vs, *ns; 13249925Sgibbs struct cfvar *v; 13346581Sken char *ep; 13446581Sken size_t varoff; 13546581Sken int did_self, jseq, pgen; 13646581Sken 13746581Sken if (!strcmp(cfname, "-")) { 13846581Sken cfname = "STDIN"; 13946581Sken yyin = stdin; 14046581Sken } else { 141203108Smav yyin = fopen(cfname, "r"); 14246581Sken if (!yyin) 14346581Sken err(1, "%s", cfname); 14446581Sken } 14546581Sken if (yyparse() || yynerrs) 14646581Sken exit(1); 14746581Sken 14846581Sken /* Separate the wildcard jails out from the actual jails. */ 14946581Sken jseq = 0; 15046581Sken TAILQ_INIT(&wild); 15146581Sken TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) { 15246581Sken j->seq = ++jseq; 15347412Sgibbs if (wild_jail_name(j->name)) 15447412Sgibbs requeue(j, &wild); 15547412Sgibbs } 15647412Sgibbs 157223081Sgibbs TAILQ_FOREACH(j, &cfjails, tq) { 158223081Sgibbs /* Set aside the jail's parameters. */ 159260387Sscottl TAILQ_INIT(&opp); 160260387Sscottl TAILQ_CONCAT(&opp, &j->params, tq); 161260387Sscottl /* 16239212Sgibbs * The jail name implies its "name" or "jid" parameter, 16346581Sken * though they may also be explicitly set later on. 16446581Sken */ 16546581Sken add_param(j, NULL, 16646581Sken strtol(j->name, &ep, 10) && !*ep ? KP_JID : KP_NAME, 16749925Sgibbs j->name); 16846581Sken /* 16946581Sken * Collect parameters for the jail, global parameters/variables, 17046581Sken * and any matching wildcard jails. 17146581Sken */ 17246581Sken did_self = 0; 17346581Sken TAILQ_FOREACH(wj, &wild, tq) { 17446581Sken if (j->seq < wj->seq && !did_self) { 17546581Sken TAILQ_FOREACH(p, &opp, tq) 17639212Sgibbs add_param(j, p, 0, NULL); 17739212Sgibbs did_self = 1; 17839212Sgibbs } 17946581Sken if (wild_jail_match(j->name, wj->name)) 18046581Sken TAILQ_FOREACH(p, &wj->params, tq) 18139212Sgibbs add_param(j, p, 0, NULL); 18239212Sgibbs } 18339212Sgibbs if (!did_self) 18446581Sken TAILQ_FOREACH(p, &opp, tq) 18546581Sken add_param(j, p, 0, NULL); 18639212Sgibbs 18739212Sgibbs /* Resolve any variable substitutions. */ 18839212Sgibbs pgen = 0; 18939212Sgibbs TAILQ_FOREACH(p, &j->params, tq) { 190195534Sscottl p->gen = ++pgen; 191195534Sscottl find_vars: 19239212Sgibbs TAILQ_FOREACH(s, &p->val, tq) { 193196008Smjacob varoff = 0; 194196008Smjacob while ((v = STAILQ_FIRST(&s->vars))) { 195196008Smjacob TAILQ_FOREACH(vp, &j->params, tq) 196196008Smjacob if (!strcmp(vp->name, v->name)) 197196008Smjacob break; 198196008Smjacob if (!vp) { 199196008Smjacob jail_warnx(j, 200196008Smjacob "%s: variable \"%s\" not found", 201196008Smjacob p->name, v->name); 202208582Smjacob bad_var: 203216088Sken j->flags |= JF_FAILED; 204216088Sken TAILQ_FOREACH(vp, &j->params, tq) 205216088Sken if (vp->gen == pgen) 206208582Smjacob vp->flags |= PF_BAD; 207208582Smjacob goto free_var; 208208582Smjacob } 209208582Smjacob if (vp->flags & PF_BAD) 21039212Sgibbs goto bad_var; 21146581Sken if (vp->gen == pgen) { 21246581Sken jail_warnx(j, "%s: variable loop", 21374840Sken v->name); 21446581Sken goto bad_var; 21539212Sgibbs } 21639212Sgibbs TAILQ_FOREACH(vs, &vp->val, tq) 21746581Sken if (!STAILQ_EMPTY(&vs->vars)) { 21846581Sken vp->gen = pgen; 21949925Sgibbs TAILQ_REMOVE(&j->params, vp, 22046581Sken tq); 22146581Sken TAILQ_INSERT_BEFORE(p, vp, tq); 22246581Sken p = vp; 22349925Sgibbs goto find_vars; 22446581Sken } 22546581Sken vs = TAILQ_FIRST(&vp->val); 226196008Smjacob if (TAILQ_NEXT(vs, tq) != NULL && 227196008Smjacob (s->s[0] != '\0' || 228196008Smjacob STAILQ_NEXT(v, tq))) { 229196008Smjacob jail_warnx(j, "%s: array cannot be " 23046581Sken "substituted inline", 231196008Smjacob p->name); 23246581Sken goto bad_var; 233302376Struckman } 234302376Struckman s->s = erealloc(s->s, s->len + vs->len + 1); 23539212Sgibbs memmove(s->s + v->pos + varoff + vs->len, 23639212Sgibbs s->s + v->pos + varoff, 23746581Sken s->len - (v->pos + varoff) + 1); 23839212Sgibbs memcpy(s->s + v->pos + varoff, vs->s, vs->len); 23939212Sgibbs varoff += vs->len; 24046581Sken s->len += vs->len; 24146581Sken while ((vs = TAILQ_NEXT(vs, tq))) { 24246581Sken ns = emalloc(sizeof(struct cfstring)); 24346581Sken ns->s = estrdup(vs->s); 24449925Sgibbs ns->len = vs->len; 24546581Sken STAILQ_INIT(&ns->vars); 24646581Sken TAILQ_INSERT_AFTER(&p->val, s, ns, tq); 24744499Sgibbs s = ns; 24849925Sgibbs } 24949925Sgibbs free_var: 25049925Sgibbs free(v->name); 25149925Sgibbs STAILQ_REMOVE_HEAD(&s->vars, tq); 25274840Sken free(v); 25374840Sken } 25474840Sken } 25574840Sken } 25674840Sken 25774840Sken /* Free the jail's original parameter list and any variables. */ 25874840Sken while ((p = TAILQ_FIRST(&opp))) 259195534Sscottl free_param(&opp, p); 260235897Smav TAILQ_FOREACH_SAFE(p, &j->params, tq, tp) 26174840Sken if (p->flags & PF_VAR) 26274840Sken free_param(&j->params, p); 26374840Sken } 26474840Sken while ((wj = TAILQ_FIRST(&wild))) { 26574840Sken free(wj->name); 26674840Sken while ((p = TAILQ_FIRST(&wj->params))) 26774840Sken free_param(&wj->params, p); 26874840Sken TAILQ_REMOVE(&wild, wj, tq); 26974840Sken } 27074840Sken} 271154593Smjacob 272154593Smjacob/* 273195534Sscottl * Create a new jail record. 274196352Smav */ 275255915Snwhitehornstruct cfjail * 27674840Skenadd_jail(void) 27774840Sken{ 278220644Smav struct cfjail *j; 279220644Smav 280220644Smav j = emalloc(sizeof(struct cfjail)); 281220644Smav memset(j, 0, sizeof(struct cfjail)); 282220644Smav TAILQ_INIT(&j->params); 283220644Smav STAILQ_INIT(&j->dep[DEP_FROM]); 284220644Smav STAILQ_INIT(&j->dep[DEP_TO]); 285220644Smav j->queue = &cfjails; 286154593Smjacob TAILQ_INSERT_TAIL(&cfjails, j, tq); 287154593Smjacob return j; 288154593Smjacob} 289154593Smjacob 29074840Sken/* 29139212Sgibbs * Add a parameter to a jail. 29260938Sjake */ 29360938Sjakevoid 29460938Sjakeadd_param(struct cfjail *j, const struct cfparam *p, enum intparam ipnum, 29560938Sjake const char *value) 29639212Sgibbs{ 29739212Sgibbs struct cfstrings nss; 29839212Sgibbs struct cfparam *dp, *np; 29939212Sgibbs struct cfstring *s, *ns; 30039212Sgibbs struct cfvar *v, *nv; 301168752Sscottl const char *name; 30239212Sgibbs char *cs, *tname; 30339212Sgibbs unsigned flags; 30439212Sgibbs 30539212Sgibbs if (j == NULL) { 30639212Sgibbs /* Create a single anonymous jail if one doesn't yet exist. */ 30739212Sgibbs j = TAILQ_LAST(&cfjails, cfjails); 30839212Sgibbs if (j == NULL) 30939212Sgibbs j = add_jail(); 31039212Sgibbs } 31139212Sgibbs TAILQ_INIT(&nss); 31239212Sgibbs if (p != NULL) { 31339212Sgibbs name = p->name; 314255870Sscottl flags = p->flags; 315255870Sscottl /* 316255870Sscottl * Make a copy of the parameter's string list, 317255870Sscottl * which may be freed if it's overridden later. 318255870Sscottl */ 319255870Sscottl TAILQ_FOREACH(s, &p->val, tq) { 32039212Sgibbs ns = emalloc(sizeof(struct cfstring)); 321130200Sscottl ns->s = estrdup(s->s); 32239212Sgibbs ns->len = s->len; 32339212Sgibbs STAILQ_INIT(&ns->vars); 324130200Sscottl STAILQ_FOREACH(v, &s->vars, tq) { 32539212Sgibbs nv = emalloc(sizeof(struct cfvar)); 32639212Sgibbs nv->name = strdup(v->name); 327130200Sscottl nv->pos = v->pos; 32839212Sgibbs STAILQ_INSERT_TAIL(&ns->vars, nv, tq); 329130200Sscottl } 330130200Sscottl TAILQ_INSERT_TAIL(&nss, ns, tq); 33139212Sgibbs } 33239212Sgibbs } else { 33339212Sgibbs flags = PF_APPEND; 334255870Sscottl if (ipnum != IP__NULL) { 335130200Sscottl name = intparams[ipnum].name; 336255870Sscottl flags |= intparams[ipnum].flags; 33739212Sgibbs } else if ((cs = strchr(value, '='))) { 33839212Sgibbs tname = alloca(cs - value + 1); 339255870Sscottl strlcpy(tname, value, cs - value + 1); 340255870Sscottl name = tname; 341255870Sscottl value = cs + 1; 34239212Sgibbs } else { 34339212Sgibbs name = value; 34439212Sgibbs value = NULL; 34539212Sgibbs } 34639212Sgibbs if (value != NULL) { 347195534Sscottl ns = emalloc(sizeof(struct cfstring)); 34856145Smjacob ns->s = estrdup(value); 349195534Sscottl ns->len = strlen(value); 35039212Sgibbs STAILQ_INIT(&ns->vars); 351199178Smav TAILQ_INSERT_TAIL(&nss, ns, tq); 35239212Sgibbs } 35339212Sgibbs } 35439212Sgibbs 35547412Sgibbs /* See if this parameter has already been added. */ 35647412Sgibbs if (ipnum != IP__NULL) 35747412Sgibbs dp = j->intparams[ipnum]; 35847412Sgibbs else 35947412Sgibbs TAILQ_FOREACH(dp, &j->params, tq) 360273078Smav if (!(dp->flags & PF_CONV) && equalopts(dp->name, name)) 361273078Smav break; 36247412Sgibbs if (dp != NULL) { 36347412Sgibbs /* Found it - append or replace. */ 36447412Sgibbs if (strcmp(dp->name, name)) { 36547412Sgibbs free(dp->name); 36647434Sgibbs dp->name = estrdup(name); 36747434Sgibbs } 36847434Sgibbs if (!(flags & PF_APPEND) || TAILQ_EMPTY(&nss)) 36947434Sgibbs free_param_strings(dp); 37047434Sgibbs TAILQ_CONCAT(&dp->val, &nss, tq); 37147412Sgibbs dp->flags |= flags; 37247412Sgibbs } else { 37339212Sgibbs /* Not found - add it. */ 37439212Sgibbs np = emalloc(sizeof(struct cfparam)); 37539212Sgibbs np->name = estrdup(name); 37639212Sgibbs TAILQ_INIT(&np->val); 37739212Sgibbs TAILQ_CONCAT(&np->val, &nss, tq); 37839212Sgibbs np->flags = flags; 37939212Sgibbs np->gen = 0; 38039212Sgibbs TAILQ_INSERT_TAIL(&j->params, np, tq); 38139212Sgibbs if (ipnum != IP__NULL) 38239212Sgibbs j->intparams[ipnum] = np; 38339212Sgibbs else 38439212Sgibbs for (ipnum = IP__NULL + 1; ipnum < IP_NPARAM; ipnum++) 38539212Sgibbs if (!(intparams[ipnum].flags & PF_CONV) && 38639212Sgibbs equalopts(name, intparams[ipnum].name)) { 38739212Sgibbs j->intparams[ipnum] = np; 38839212Sgibbs np->flags |= intparams[ipnum].flags; 38939212Sgibbs break; 39039212Sgibbs } 39139212Sgibbs } 39239212Sgibbs} 39339212Sgibbs 39439212Sgibbs/* 39539212Sgibbs * Return if a boolean parameter exists and is true. 39639212Sgibbs */ 39739212Sgibbsint 39839212Sgibbsbool_param(const struct cfparam *p) 39939212Sgibbs{ 40039212Sgibbs const char *cs; 40139212Sgibbs 40239212Sgibbs if (p == NULL) 40339212Sgibbs return 0; 40439212Sgibbs cs = strrchr(p->name, '.'); 40539212Sgibbs return !strncmp(cs ? cs + 1 : p->name, "no", 2) ^ 40639212Sgibbs (TAILQ_EMPTY(&p->val) || 40739212Sgibbs !strcasecmp(TAILQ_LAST(&p->val, cfstrings)->s, "true") || 40839212Sgibbs (strtol(TAILQ_LAST(&p->val, cfstrings)->s, NULL, 10))); 40939212Sgibbs} 41039212Sgibbs 41139212Sgibbs/* 41239212Sgibbs * Set an integer if a parameter if it exists. 41339212Sgibbs */ 41439212Sgibbsint 415223081Sgibbsint_param(const struct cfparam *p, int *ip) 41639212Sgibbs{ 41739212Sgibbs if (p == NULL || TAILQ_EMPTY(&p->val)) 41839212Sgibbs return 0; 419223081Sgibbs *ip = strtol(TAILQ_LAST(&p->val, cfstrings)->s, NULL, 10); 420223081Sgibbs return 1; 421223081Sgibbs} 422223081Sgibbs 423223081Sgibbs/* 42439212Sgibbs * Return the string value of a scalar parameter if it exists. 425223081Sgibbs */ 426223081Sgibbsconst char * 427223081Sgibbsstring_param(const struct cfparam *p) 428223081Sgibbs{ 429223081Sgibbs return (p && !TAILQ_EMPTY(&p->val) 430223081Sgibbs ? TAILQ_LAST(&p->val, cfstrings)->s : NULL); 431223081Sgibbs} 432223081Sgibbs 43339212Sgibbs/* 43439212Sgibbs * Check syntax and values of internal parameters. Set some internal 43539212Sgibbs * parameters based on the values of others. 43639212Sgibbs */ 43739212Sgibbsint 43839212Sgibbscheck_intparams(struct cfjail *j) 43939212Sgibbs{ 44039212Sgibbs struct cfparam *p; 44139212Sgibbs struct cfstring *s; 44239212Sgibbs FILE *f; 44339212Sgibbs const char *val; 44439212Sgibbs char *cs, *ep, *ln; 44539212Sgibbs size_t lnlen; 44639212Sgibbs int error; 44739212Sgibbs#if defined(INET) || defined(INET6) 44839212Sgibbs struct addrinfo hints; 44939212Sgibbs struct addrinfo *ai0, *ai; 45039212Sgibbs const char *hostname; 45139212Sgibbs int gicode, defif, prefix; 45239212Sgibbs#endif 45339212Sgibbs#ifdef INET 45439212Sgibbs struct in_addr addr4; 45539212Sgibbs int ip4ok; 45639212Sgibbs char avalue4[INET_ADDRSTRLEN]; 45739212Sgibbs#endif 45839212Sgibbs#ifdef INET6 45939212Sgibbs struct in6_addr addr6; 46039212Sgibbs int ip6ok; 46139212Sgibbs char avalue6[INET6_ADDRSTRLEN]; 46239212Sgibbs#endif 46339212Sgibbs 46439212Sgibbs error = 0; 46539212Sgibbs /* Check format of boolan and integer values. */ 46639212Sgibbs TAILQ_FOREACH(p, &j->params, tq) { 46739212Sgibbs if (!TAILQ_EMPTY(&p->val) && (p->flags & (PF_BOOL | PF_INT))) { 46839212Sgibbs val = TAILQ_LAST(&p->val, cfstrings)->s; 46939212Sgibbs if (p->flags & PF_BOOL) { 47039212Sgibbs if (strcasecmp(val, "false") && 47139212Sgibbs strcasecmp(val, "true") && 47239212Sgibbs ((void)strtol(val, &ep, 10), *ep)) { 47339212Sgibbs jail_warnx(j, 47439212Sgibbs "%s: unknown boolean value \"%s\"", 47539212Sgibbs p->name, val); 47639212Sgibbs error = -1; 47746581Sken } 47846581Sken } else { 47946581Sken (void)strtol(val, &ep, 10); 48046581Sken if (ep == val || *ep) { 48146581Sken jail_warnx(j, 48239212Sgibbs "%s: non-integer value \"%s\"", 48339212Sgibbs p->name, val); 48439212Sgibbs error = -1; 48539212Sgibbs } 486195534Sscottl } 48739212Sgibbs } 488195534Sscottl } 48946581Sken 49039212Sgibbs#if defined(INET) || defined(INET6) 49139212Sgibbs /* 49239212Sgibbs * The ip_hostname parameter looks up the hostname, and adds parameters 49339212Sgibbs * for any IP addresses it finds. 49439212Sgibbs */ 49539212Sgibbs if (((j->flags & JF_OP_MASK) != JF_STOP || 49639212Sgibbs j->intparams[IP_INTERFACE] != NULL) && 49739212Sgibbs bool_param(j->intparams[IP_IP_HOSTNAME]) && 49839212Sgibbs (hostname = string_param(j->intparams[KP_HOST_HOSTNAME]))) { 49939212Sgibbs j->intparams[IP_IP_HOSTNAME] = NULL; 50039212Sgibbs /* 50139212Sgibbs * Silently ignore unsupported address families from 50239212Sgibbs * DNS lookups. 50339212Sgibbs */ 50439212Sgibbs#ifdef INET 50539212Sgibbs ip4ok = feature_present("inet"); 50639212Sgibbs#endif 50739212Sgibbs#ifdef INET6 50839212Sgibbs ip6ok = feature_present("inet6"); 50939212Sgibbs#endif 51039212Sgibbs if ( 51139212Sgibbs#if defined(INET) && defined(INET6) 51239212Sgibbs ip4ok || ip6ok 51339212Sgibbs#elif defined(INET) 51439212Sgibbs ip4ok 51539212Sgibbs#elif defined(INET6) 51639212Sgibbs ip6ok 51739212Sgibbs#endif 51839212Sgibbs ) { 51939212Sgibbs /* Look up the hostname (or get the address) */ 52039212Sgibbs memset(&hints, 0, sizeof(hints)); 52139212Sgibbs hints.ai_socktype = SOCK_STREAM; 52239212Sgibbs hints.ai_family = 52339212Sgibbs#if defined(INET) && defined(INET6) 52439212Sgibbs ip4ok ? (ip6ok ? PF_UNSPEC : PF_INET) : PF_INET6; 52539212Sgibbs#elif defined(INET) 52639212Sgibbs PF_INET; 52739212Sgibbs#elif defined(INET6) 52839212Sgibbs PF_INET6; 52939212Sgibbs#endif 53039212Sgibbs gicode = getaddrinfo(hostname, NULL, &hints, &ai0); 53139212Sgibbs if (gicode != 0) { 53239212Sgibbs jail_warnx(j, "host.hostname %s: %s", hostname, 53339212Sgibbs gai_strerror(gicode)); 53439212Sgibbs error = -1; 53539212Sgibbs } else { 53639212Sgibbs /* 53739212Sgibbs * Convert the addresses to ASCII so jailparam 53839212Sgibbs * can convert them back. Errors are not 53939212Sgibbs * expected here. 54039212Sgibbs */ 54139212Sgibbs for (ai = ai0; ai; ai = ai->ai_next) 54239212Sgibbs switch (ai->ai_family) { 54339212Sgibbs#ifdef INET 54439212Sgibbs case AF_INET: 54539212Sgibbs memcpy(&addr4, 54639212Sgibbs &((struct sockaddr_in *) 54739212Sgibbs (void *)ai->ai_addr)-> 54839212Sgibbs sin_addr, sizeof(addr4)); 54939212Sgibbs if (inet_ntop(AF_INET, 55039212Sgibbs &addr4, avalue4, 55139212Sgibbs INET_ADDRSTRLEN) == NULL) 55239212Sgibbs err(1, "inet_ntop"); 55339212Sgibbs add_param(j, NULL, KP_IP4_ADDR, 55439212Sgibbs avalue4); 55539212Sgibbs break; 55639212Sgibbs#endif 55739212Sgibbs#ifdef INET6 55839212Sgibbs case AF_INET6: 55939212Sgibbs memcpy(&addr6, 56039212Sgibbs &((struct sockaddr_in6 *) 56139212Sgibbs (void *)ai->ai_addr)-> 56239212Sgibbs sin6_addr, sizeof(addr6)); 563255870Sscottl if (inet_ntop(AF_INET6, 56439212Sgibbs &addr6, avalue6, 56539212Sgibbs INET6_ADDRSTRLEN) == NULL) 56639212Sgibbs err(1, "inet_ntop"); 56739212Sgibbs add_param(j, NULL, KP_IP6_ADDR, 56839212Sgibbs avalue6); 56939212Sgibbs break; 57039212Sgibbs#endif 571195534Sscottl } 57239212Sgibbs freeaddrinfo(ai0); 57353258Sken } 57439212Sgibbs } 57539212Sgibbs } 57639212Sgibbs 57739212Sgibbs /* 57839212Sgibbs * IP addresses may include an interface to set that address on, 57939212Sgibbs * and a netmask/suffix for that address. 58039212Sgibbs */ 58139212Sgibbs defif = string_param(j->intparams[IP_INTERFACE]) != NULL; 58253258Sken#ifdef INET 58339212Sgibbs if (j->intparams[KP_IP4_ADDR] != NULL) { 58439212Sgibbs TAILQ_FOREACH(s, &j->intparams[KP_IP4_ADDR]->val, tq) { 58539212Sgibbs cs = strchr(s->s, '|'); 586255870Sscottl if (cs || defif) 58739212Sgibbs add_param(j, NULL, IP__IP4_IFADDR, s->s); 58839212Sgibbs if (cs) { 58941644Sgibbs strcpy(s->s, cs + 1); 590118105Snjl s->len -= cs + 1 - s->s; 591159311Smjacob } 592248519Skib if ((cs = strchr(s->s, '/'))) { 593248519Skib prefix = strtol(cs + 1, &ep, 10); 594253549Sken if (*ep == '.' 59539212Sgibbs ? inet_pton(AF_INET, cs + 1, &addr4) != 1 59639212Sgibbs : *ep || prefix < 0 || prefix > 32) { 59739212Sgibbs jail_warnx(j, 59874840Sken "ip4.addr: bad netmask \"%s\"", cs); 59974840Sken error = -1; 60074840Sken } 601196008Smjacob *cs = '\0'; 60277708Smjacob s->len = cs - s->s; 60377708Smjacob } 60477708Smjacob } 60577708Smjacob } 60677708Smjacob#endif 60777708Smjacob#ifdef INET6 608196008Smjacob if (j->intparams[KP_IP6_ADDR] != NULL) { 609154593Smjacob TAILQ_FOREACH(s, &j->intparams[KP_IP6_ADDR]->val, tq) { 610154593Smjacob cs = strchr(s->s, '|'); 611154593Smjacob if (cs || defif) 61277708Smjacob add_param(j, NULL, IP__IP6_IFADDR, s->s); 61374840Sken if (cs) { 61439212Sgibbs strcpy(s->s, cs + 1); 61539212Sgibbs s->len -= cs + 1 - s->s; 61639212Sgibbs } 61739212Sgibbs if ((cs = strchr(s->s, '/'))) { 618255870Sscottl prefix = strtol(cs + 1, &ep, 10); 619255870Sscottl if (*ep || prefix < 0 || prefix > 128) { 62039212Sgibbs jail_warnx(j, 62139212Sgibbs "ip6.addr: bad prefixlen \"%s\"", 62239212Sgibbs cs); 62339212Sgibbs error = -1; 62439212Sgibbs } 62539212Sgibbs *cs = '\0'; 62639212Sgibbs s->len = cs - s->s; 62739212Sgibbs } 62839212Sgibbs } 62939212Sgibbs } 63039212Sgibbs#endif 63139212Sgibbs#endif 63239212Sgibbs 63346581Sken /* 63474840Sken * Read mount.fstab file(s), and treat each line as its own mount 63574840Sken * parameter. 63674840Sken */ 63774840Sken if (j->intparams[IP_MOUNT_FSTAB] != NULL) { 63874840Sken TAILQ_FOREACH(s, &j->intparams[IP_MOUNT_FSTAB]->val, tq) { 63974840Sken if (s->len == 0) 64077708Smjacob continue; 641154593Smjacob f = fopen(s->s, "r"); 64277708Smjacob if (f == NULL) { 64374840Sken jail_warnx(j, "mount.fstab: %s: %s", 644195534Sscottl s->s, strerror(errno)); 645210471Smav error = -1; 646210471Smav continue; 647210471Smav } 648210471Smav while ((ln = fgetln(f, &lnlen))) { 64939212Sgibbs if ((cs = memchr(ln, '#', lnlen - 1))) 65039212Sgibbs lnlen = cs - ln + 1; 65147412Sgibbs if (ln[lnlen - 1] == '\n' || 65247412Sgibbs ln[lnlen - 1] == '#') 65347412Sgibbs ln[lnlen - 1] = '\0'; 65447412Sgibbs else { 65547412Sgibbs cs = alloca(lnlen + 1); 65647412Sgibbs strlcpy(cs, ln, lnlen + 1); 657216088Sken ln = cs; 658216088Sken } 659216088Sken add_param(j, NULL, IP__MOUNT_FROM_FSTAB, ln); 660216088Sken } 661216088Sken fclose(f); 662216088Sken } 663216088Sken } 664216088Sken if (error) 665216088Sken failed(j); 666216088Sken return error; 667216088Sken} 668216088Sken 669216088Sken/* 670216088Sken * Import parameters into libjail's binary jailparam format. 671216088Sken */ 672216088Skenint 673216088Skenimport_params(struct cfjail *j) 674216088Sken{ 675216088Sken struct cfparam *p; 676216088Sken struct cfstring *s, *ts; 677216088Sken struct jailparam *jp; 678216088Sken char *value, *cs; 679216088Sken size_t vallen; 680216088Sken int error; 681216088Sken 682216088Sken error = 0; 68339212Sgibbs j->njp = 0; 68439212Sgibbs TAILQ_FOREACH(p, &j->params, tq) 68539212Sgibbs if (!(p->flags & PF_INTERNAL)) 68639212Sgibbs j->njp++; 68739212Sgibbs j->jp = jp = emalloc(j->njp * sizeof(struct jailparam)); 68839212Sgibbs TAILQ_FOREACH(p, &j->params, tq) { 68939212Sgibbs if (p->flags & PF_INTERNAL) 69039212Sgibbs continue; 69139212Sgibbs if (jailparam_init(jp, p->name) < 0) { 69239212Sgibbs error = -1; 69339212Sgibbs jail_warnx(j, "%s", jail_errmsg); 69439212Sgibbs jp++; 69539212Sgibbs continue; 69639212Sgibbs } 69739212Sgibbs if (TAILQ_EMPTY(&p->val)) 69839212Sgibbs value = NULL; 69939212Sgibbs else if (!jp->jp_elemlen || 70039212Sgibbs !TAILQ_NEXT(TAILQ_FIRST(&p->val), tq)) { 70139212Sgibbs /* 70239212Sgibbs * Scalar parameters silently discard multiple (array) 70339212Sgibbs * values, keeping only the last value added. This 70439212Sgibbs * lets values added from the command line append to 70539212Sgibbs * arrays wthout pre-checking the type. 70639212Sgibbs */ 70739212Sgibbs value = TAILQ_LAST(&p->val, cfstrings)->s; 70839212Sgibbs } else { 70939212Sgibbs /* 71039212Sgibbs * Convert arrays into comma-separated strings, which 71139212Sgibbs * jailparam_import will then convert back into arrays. 71239212Sgibbs */ 71339212Sgibbs vallen = 0; 71439212Sgibbs TAILQ_FOREACH(s, &p->val, tq) 71539212Sgibbs vallen += s->len + 1; 71639212Sgibbs value = alloca(vallen); 71739212Sgibbs cs = value; 71839212Sgibbs TAILQ_FOREACH_SAFE(s, &p->val, tq, ts) { 71939212Sgibbs memcpy(cs, s->s, s->len); 72040417Sgibbs cs += s->len + 1; 72140417Sgibbs cs[-1] = ','; 72240417Sgibbs } 72340417Sgibbs value[vallen - 1] = '\0'; 72440417Sgibbs } 72540417Sgibbs if (jailparam_import(jp, value) < 0) { 72649925Sgibbs error = -1; 72749925Sgibbs jail_warnx(j, "%s", jail_errmsg); 72839212Sgibbs } 72939212Sgibbs jp++; 730312850Smav } 731312850Smav if (error) { 732312850Smav jailparam_free(j->jp, j->njp); 733312850Smav free(j->jp); 734312850Smav j->jp = NULL; 735312850Smav failed(j); 736312850Smav } 737195534Sscottl return error; 738195534Sscottl} 739195534Sscottl 740195534Sscottl/* 741195534Sscottl * Check if options are equal (with or without the "no" prefix). 742195534Sscottl */ 743195534Sscottlint 744195534Sscottlequalopts(const char *opt1, const char *opt2) 745195534Sscottl{ 746195534Sscottl char *p; 747195534Sscottl 748195534Sscottl /* "opt" vs. "opt" or "noopt" vs. "noopt" */ 749195534Sscottl if (strcmp(opt1, opt2) == 0) 750195534Sscottl return (1); 751195534Sscottl /* "noopt" vs. "opt" */ 752195534Sscottl if (strncmp(opt1, "no", 2) == 0 && strcmp(opt1 + 2, opt2) == 0) 753195534Sscottl return (1); 754195534Sscottl /* "opt" vs. "noopt" */ 755195534Sscottl if (strncmp(opt2, "no", 2) == 0 && strcmp(opt1, opt2 + 2) == 0) 756195534Sscottl return (1); 757195534Sscottl while ((p = strchr(opt1, '.')) != NULL && 758195534Sscottl !strncmp(opt1, opt2, ++p - opt1)) { 75939212Sgibbs opt2 += p - opt1; 76039212Sgibbs opt1 = p; 76139212Sgibbs /* "foo.noopt" vs. "foo.opt" */ 76239212Sgibbs if (strncmp(opt1, "no", 2) == 0 && strcmp(opt1 + 2, opt2) == 0) 76339212Sgibbs return (1); 76456145Smjacob /* "foo.opt" vs. "foo.noopt" */ 76555328Smjacob if (strncmp(opt2, "no", 2) == 0 && strcmp(opt1, opt2 + 2) == 0) 76655328Smjacob return (1); 76756145Smjacob } 76839212Sgibbs return (0); 76939212Sgibbs} 770312845Smav 771312845Smav/* 772312845Smav * See if a jail name matches a wildcard. 773312845Smav */ 774312845Smavint 775312845Smavwild_jail_match(const char *jname, const char *wname) 776312845Smav{ 77739212Sgibbs const char *jc, *jd, *wc, *wd; 77839212Sgibbs 77939212Sgibbs /* 78039212Sgibbs * A non-final "*" component in the wild name matches a single jail 78139212Sgibbs * component, and a final "*" matches one or more jail components. 78239212Sgibbs */ 78339212Sgibbs for (jc = jname, wc = wname; 78439212Sgibbs (jd = strchr(jc, '.')) && (wd = strchr(wc, '.')); 78539212Sgibbs jc = jd + 1, wc = wd + 1) 786203108Smav if (strncmp(jc, wc, jd - jc + 1) && strncmp(wc, "*.", 2)) 78739212Sgibbs return 0; 78839212Sgibbs return (!strcmp(jc, wc) || !strcmp(wc, "*")); 78939212Sgibbs} 79039212Sgibbs 79139212Sgibbs/* 79239212Sgibbs * Return if a jail name is a wildcard. 79339212Sgibbs */ 794238886Smavint 795223081Sgibbswild_jail_name(const char *wname) 796196008Smjacob{ 79739212Sgibbs const char *wc; 79839212Sgibbs 79939212Sgibbs for (wc = strchr(wname, '*'); wc; wc = strchr(wc + 1, '*')) 80039212Sgibbs if ((wc == wname || wc[-1] == '.') && 80139212Sgibbs (wc[1] == '\0' || wc[1] == '.')) 80239212Sgibbs return 1; 80339212Sgibbs return 0; 80439212Sgibbs} 80539212Sgibbs 80639212Sgibbs/* 80739212Sgibbs * Free a parameter record and all its strings and variables. 80839212Sgibbs */ 80939212Sgibbsstatic void 81039212Sgibbsfree_param(struct cfparams *pp, struct cfparam *p) 81139212Sgibbs{ 81239212Sgibbs free(p->name); 813196008Smjacob free_param_strings(p); 814196008Smjacob TAILQ_REMOVE(pp, p, tq); 815196008Smjacob free(p); 816196008Smjacob} 817196008Smjacob 818196008Smjacobstatic void 819196008Smjacobfree_param_strings(struct cfparam *p) 820196008Smjacob{ 821196008Smjacob struct cfstring *s; 822196008Smjacob struct cfvar *v; 823196008Smjacob 824196008Smjacob while ((s = TAILQ_FIRST(&p->val))) { 825196008Smjacob free(s->s); 826196008Smjacob while ((v = STAILQ_FIRST(&s->vars))) { 827196008Smjacob free(v->name); 828196008Smjacob STAILQ_REMOVE_HEAD(&s->vars, tq); 829196008Smjacob free(v); 830196008Smjacob } 831196008Smjacob TAILQ_REMOVE(&p->val, s, tq); 832196008Smjacob free(s); 83339212Sgibbs } 83439212Sgibbs} 83539212Sgibbs