config.c revision 269805
138061Smsmith/*- 255939Snsouch * Copyright (c) 2011 James Gritton 370608Snsouch * All rights reserved. 438061Smsmith * 538061Smsmith * Redistribution and use in source and binary forms, with or without 638061Smsmith * modification, are permitted provided that the following conditions 738061Smsmith * are met: 838061Smsmith * 1. Redistributions of source code must retain the above copyright 938061Smsmith * notice, this list of conditions and the following disclaimer. 1038061Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1138061Smsmith * notice, this list of conditions and the following disclaimer in the 1238061Smsmith * documentation and/or other materials provided with the distribution. 1338061Smsmith * 1438061Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1538061Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1638061Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1738061Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1838061Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1938061Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2038061Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2138061Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2238061Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2338061Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2438061Smsmith * SUCH DAMAGE. 2538061Smsmith */ 2638061Smsmith 2738061Smsmith#include <sys/cdefs.h> 2838061Smsmith__FBSDID("$FreeBSD: stable/10/usr.sbin/jail/config.c 269805 2014-08-11 08:58:35Z smh $"); 2938061Smsmith 30119418Sobrien#include <sys/types.h> 31119418Sobrien#include <sys/errno.h> 32119418Sobrien#include <sys/socket.h> 3355205Speter#include <sys/sysctl.h> 3438061Smsmith 3538061Smsmith#include <arpa/inet.h> 3655939Snsouch#include <netinet/in.h> 3755939Snsouch 3838061Smsmith#include <err.h> 3938061Smsmith#include <netdb.h> 4038061Smsmith#include <stdio.h> 4155205Speter#include <stdlib.h> 4238061Smsmith#include <string.h> 4342475Snsouch#include <unistd.h> 4442475Snsouch 4555939Snsouch#include "jailp.h" 4638061Smsmith 4738061Smsmithstruct ipspec { 4838061Smsmith const char *name; 4938061Smsmith unsigned flags; 5055939Snsouch}; 5155939Snsouch 5238061Smsmithextern FILE *yyin; 5338061Smsmithextern int yynerrs; 5438061Smsmith 5538061Smsmithextern int yyparse(void); 5638061Smsmith 5738061Smsmithstruct cfjails cfjails = TAILQ_HEAD_INITIALIZER(cfjails); 5838061Smsmith 5938061Smsmithstatic void free_param(struct cfparams *pp, struct cfparam *p); 6038061Smsmithstatic void free_param_strings(struct cfparam *p); 6138061Smsmith 6238061Smsmithstatic const struct ipspec intparams[] = { 6338061Smsmith [IP_ALLOW_DYING] = {"allow.dying", PF_INTERNAL | PF_BOOL}, 6438061Smsmith [IP_COMMAND] = {"command", PF_INTERNAL}, 6538061Smsmith [IP_DEPEND] = {"depend", PF_INTERNAL}, 6638061Smsmith [IP_EXEC_CLEAN] = {"exec.clean", PF_INTERNAL | PF_BOOL}, 6738061Smsmith [IP_EXEC_CONSOLELOG] = {"exec.consolelog", PF_INTERNAL}, 6838061Smsmith [IP_EXEC_FIB] = {"exec.fib", PF_INTERNAL | PF_INT}, 6938061Smsmith [IP_EXEC_JAIL_USER] = {"exec.jail_user", PF_INTERNAL}, 7038061Smsmith [IP_EXEC_POSTSTART] = {"exec.poststart", PF_INTERNAL}, 7138061Smsmith [IP_EXEC_POSTSTOP] = {"exec.poststop", PF_INTERNAL}, 7238061Smsmith [IP_EXEC_PRESTART] = {"exec.prestart", PF_INTERNAL}, 7338061Smsmith [IP_EXEC_PRESTOP] = {"exec.prestop", PF_INTERNAL}, 7438061Smsmith [IP_EXEC_START] = {"exec.start", PF_INTERNAL}, 7538061Smsmith [IP_EXEC_STOP] = {"exec.stop", PF_INTERNAL}, 7638061Smsmith [IP_EXEC_SYSTEM_JAIL_USER]= {"exec.system_jail_user", 7738061Smsmith PF_INTERNAL | PF_BOOL}, 7838061Smsmith [IP_EXEC_SYSTEM_USER] = {"exec.system_user", PF_INTERNAL}, 7938061Smsmith [IP_EXEC_TIMEOUT] = {"exec.timeout", PF_INTERNAL | PF_INT}, 8038061Smsmith#if defined(INET) || defined(INET6) 8138061Smsmith [IP_INTERFACE] = {"interface", PF_INTERNAL}, 8238061Smsmith [IP_IP_HOSTNAME] = {"ip_hostname", PF_INTERNAL | PF_BOOL}, 8338061Smsmith#endif 8439134Snsouch [IP_MOUNT] = {"mount", PF_INTERNAL | PF_REV}, 8539134Snsouch [IP_MOUNT_DEVFS] = {"mount.devfs", PF_INTERNAL | PF_BOOL}, 8638061Smsmith [IP_MOUNT_FDESCFS] = {"mount.fdescfs", PF_INTERNAL | PF_BOOL}, 8738061Smsmith [IP_MOUNT_FSTAB] = {"mount.fstab", PF_INTERNAL}, 8838061Smsmith [IP_STOP_TIMEOUT] = {"stop.timeout", PF_INTERNAL | PF_INT}, 8938061Smsmith [IP_VNET_INTERFACE] = {"vnet.interface", PF_INTERNAL}, 9038061Smsmith#ifdef INET 9138061Smsmith [IP__IP4_IFADDR] = {"ip4.addr", PF_INTERNAL | PF_CONV | PF_REV}, 9238061Smsmith#endif 9338061Smsmith#ifdef INET6 9438061Smsmith [IP__IP6_IFADDR] = {"ip6.addr", PF_INTERNAL | PF_CONV | PF_REV}, 9538061Smsmith#endif 9638061Smsmith [IP__MOUNT_FROM_FSTAB] = {"mount.fstab", PF_INTERNAL | PF_CONV | PF_REV}, 9738061Smsmith [IP__OP] = {NULL, PF_CONV}, 9838061Smsmith [KP_ALLOW_CHFLAGS] = {"allow.chflags", 0}, 9978645Snsouch [KP_ALLOW_MOUNT] = {"allow.mount", 0}, 10078645Snsouch [KP_ALLOW_RAW_SOCKETS] = {"allow.raw_sockets", 0}, 10178645Snsouch [KP_ALLOW_SET_HOSTNAME]= {"allow.set_hostname", 0}, 10278645Snsouch [KP_ALLOW_SOCKET_AF] = {"allow.socket_af", 0}, 10378645Snsouch [KP_ALLOW_SYSVIPC] = {"allow.sysvipc", 0}, 10478645Snsouch [KP_DEVFS_RULESET] = {"devfs_ruleset", 0}, 10578645Snsouch [KP_ENFORCE_STATFS] = {"enforce_statfs", 0}, 10678645Snsouch [KP_HOST_HOSTNAME] = {"host.hostname", 0}, 10778645Snsouch#ifdef INET 10878645Snsouch [KP_IP4_ADDR] = {"ip4.addr", 0}, 10978645Snsouch#endif 11078645Snsouch#ifdef INET6 11178645Snsouch [KP_IP6_ADDR] = {"ip6.addr", 0}, 11278645Snsouch#endif 11378645Snsouch [KP_JID] = {"jid", 0}, 11439134Snsouch [KP_NAME] = {"name", 0}, 11539134Snsouch [KP_PATH] = {"path", 0}, 11639134Snsouch [KP_PERSIST] = {"persist", 0}, 11739134Snsouch [KP_SECURELEVEL] = {"securelevel", 0}, 11845342Speter [KP_VNET] = {"vnet", 0}, 11939134Snsouch}; 12045342Speter 12139134Snsouch/* 12239134Snsouch * Parse the jail configuration file. 12339134Snsouch */ 12439134Snsouchvoid 12539134Snsouchload_config(void) 12638061Smsmith{ 12738061Smsmith struct cfjails wild; 12838061Smsmith struct cfparams opp; 12938061Smsmith struct cfjail *j, *tj, *wj; 13038061Smsmith struct cfparam *p, *vp, *tp; 13138061Smsmith struct cfstring *s, *vs, *ns; 13238061Smsmith struct cfvar *v; 13339134Snsouch char *ep; 13439134Snsouch size_t varoff; 13538061Smsmith int did_self, jseq, pgen; 13638061Smsmith 13738061Smsmith if (!strcmp(cfname, "-")) { 13838061Smsmith cfname = "STDIN"; 13938061Smsmith yyin = stdin; 14038061Smsmith } else { 14138061Smsmith yyin = fopen(cfname, "r"); 14239134Snsouch if (!yyin) 14338061Smsmith err(1, "%s", cfname); 14438061Smsmith } 14538061Smsmith if (yyparse() || yynerrs) 14638061Smsmith exit(1); 14739134Snsouch 14838061Smsmith /* Separate the wildcard jails out from the actual jails. */ 14938061Smsmith jseq = 0; 15038061Smsmith TAILQ_INIT(&wild); 15138061Smsmith TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) { 15239134Snsouch j->seq = ++jseq; 15338061Smsmith if (wild_jail_name(j->name)) 15438061Smsmith requeue(j, &wild); 15538061Smsmith } 15638061Smsmith 15738061Smsmith TAILQ_FOREACH(j, &cfjails, tq) { 15838061Smsmith /* Set aside the jail's parameters. */ 15938061Smsmith TAILQ_INIT(&opp); 16038061Smsmith TAILQ_CONCAT(&opp, &j->params, tq); 16138061Smsmith /* 16238061Smsmith * The jail name implies its "name" or "jid" parameter, 16338061Smsmith * though they may also be explicitly set later on. 16438061Smsmith */ 16538061Smsmith add_param(j, NULL, 16638061Smsmith strtol(j->name, &ep, 10) && !*ep ? KP_JID : KP_NAME, 16738061Smsmith j->name); 16838061Smsmith /* 16938061Smsmith * Collect parameters for the jail, global parameters/variables, 17038061Smsmith * and any matching wildcard jails. 17138061Smsmith */ 17238061Smsmith did_self = 0; 17378645Snsouch TAILQ_FOREACH(wj, &wild, tq) { 17478645Snsouch if (j->seq < wj->seq && !did_self) { 17578645Snsouch TAILQ_FOREACH(p, &opp, tq) 17678645Snsouch add_param(j, p, 0, NULL); 17738061Smsmith did_self = 1; 17838061Smsmith } 17938061Smsmith if (wild_jail_match(j->name, wj->name)) 18038061Smsmith TAILQ_FOREACH(p, &wj->params, tq) 18138061Smsmith add_param(j, p, 0, NULL); 18238061Smsmith } 18338061Smsmith if (!did_self) 18478645Snsouch TAILQ_FOREACH(p, &opp, tq) 18578645Snsouch add_param(j, p, 0, NULL); 18678645Snsouch 18778645Snsouch /* Resolve any variable substitutions. */ 18878645Snsouch pgen = 0; 18978645Snsouch TAILQ_FOREACH(p, &j->params, tq) { 19078645Snsouch p->gen = ++pgen; 19178645Snsouch find_vars: 19278645Snsouch TAILQ_FOREACH(s, &p->val, tq) { 19378645Snsouch varoff = 0; 19478645Snsouch while ((v = STAILQ_FIRST(&s->vars))) { 19578645Snsouch TAILQ_FOREACH(vp, &j->params, tq) 19678645Snsouch if (!strcmp(vp->name, v->name)) 19778645Snsouch break; 19838061Smsmith if (!vp) { 19938061Smsmith jail_warnx(j, 20038061Smsmith "%s: variable \"%s\" not found", 20138061Smsmith p->name, v->name); 20239134Snsouch bad_var: 20338061Smsmith j->flags |= JF_FAILED; 20438061Smsmith TAILQ_FOREACH(vp, &j->params, tq) 20538061Smsmith if (vp->gen == pgen) 20638061Smsmith vp->flags |= PF_BAD; 20738061Smsmith goto free_var; 20838061Smsmith } 20943433Snsouch if (vp->flags & PF_BAD) 21038061Smsmith goto bad_var; 21138061Smsmith if (vp->gen == pgen) { 21238061Smsmith jail_warnx(j, "%s: variable loop", 21338061Smsmith v->name); 21438061Smsmith goto bad_var; 21538061Smsmith } 21638061Smsmith TAILQ_FOREACH(vs, &vp->val, tq) 21738061Smsmith if (!STAILQ_EMPTY(&vs->vars)) { 21839134Snsouch vp->gen = pgen; 21938061Smsmith TAILQ_REMOVE(&j->params, vp, 22038061Smsmith tq); 221185003Sjhb TAILQ_INSERT_BEFORE(p, vp, tq); 22238061Smsmith p = vp; 22338061Smsmith goto find_vars; 22438061Smsmith } 22543433Snsouch vs = TAILQ_FIRST(&vp->val); 22638061Smsmith if (TAILQ_NEXT(vs, tq) != NULL && 22738061Smsmith (s->s[0] != '\0' || 22838061Smsmith STAILQ_NEXT(v, tq))) { 22938061Smsmith jail_warnx(j, "%s: array cannot be " 23038061Smsmith "substituted inline", 23138061Smsmith p->name); 23239134Snsouch goto bad_var; 23338061Smsmith } 23438061Smsmith s->s = erealloc(s->s, s->len + vs->len + 1); 23538061Smsmith memmove(s->s + v->pos + varoff + vs->len, 236185003Sjhb s->s + v->pos + varoff, 23743433Snsouch s->len - (v->pos + varoff) + 1); 23843433Snsouch memcpy(s->s + v->pos + varoff, vs->s, vs->len); 23938061Smsmith varoff += vs->len; 24038061Smsmith s->len += vs->len; 24138061Smsmith while ((vs = TAILQ_NEXT(vs, tq))) { 24238061Smsmith ns = emalloc(sizeof(struct cfstring)); 24338061Smsmith ns->s = estrdup(vs->s); 24438061Smsmith ns->len = vs->len; 24538061Smsmith STAILQ_INIT(&ns->vars); 24638061Smsmith TAILQ_INSERT_AFTER(&p->val, s, ns, tq); 24739134Snsouch s = ns; 24838061Smsmith } 24938061Smsmith free_var: 25038061Smsmith free(v->name); 251185003Sjhb STAILQ_REMOVE_HEAD(&s->vars, tq); 25243433Snsouch free(v); 25343433Snsouch } 25438061Smsmith } 25538061Smsmith } 25638061Smsmith 25738061Smsmith /* Free the jail's original parameter list and any variables. */ 25838061Smsmith while ((p = TAILQ_FIRST(&opp))) 25938061Smsmith free_param(&opp, p); 26038061Smsmith TAILQ_FOREACH_SAFE(p, &j->params, tq, tp) 26138061Smsmith if (p->flags & PF_VAR) 26239134Snsouch free_param(&j->params, p); 26339134Snsouch } 26439134Snsouch while ((wj = TAILQ_FIRST(&wild))) { 26539134Snsouch free(wj->name); 26643433Snsouch while ((p = TAILQ_FIRST(&wj->params))) 26739134Snsouch free_param(&wj->params, p); 26843433Snsouch TAILQ_REMOVE(&wild, wj, tq); 26939134Snsouch } 27039520Snsouch} 27139134Snsouch 27239520Snsouch/* 27339134Snsouch * Create a new jail record. 27439134Snsouch */ 27538061Smsmithstruct cfjail * 27638061Smsmithadd_jail(void) 27738061Smsmith{ 27855939Snsouch struct cfjail *j; 27938061Smsmith 28038061Smsmith j = emalloc(sizeof(struct cfjail)); 28155939Snsouch memset(j, 0, sizeof(struct cfjail)); 28255939Snsouch TAILQ_INIT(&j->params); 28338061Smsmith STAILQ_INIT(&j->dep[DEP_FROM]); 28438061Smsmith STAILQ_INIT(&j->dep[DEP_TO]); 28538061Smsmith j->queue = &cfjails; 28638061Smsmith TAILQ_INSERT_TAIL(&cfjails, j, tq); 28738061Smsmith return j; 28838061Smsmith} 28938061Smsmith 29038061Smsmith/* 29155939Snsouch * Add a parameter to a jail. 29238061Smsmith */ 29338061Smsmithvoid 29438061Smsmithadd_param(struct cfjail *j, const struct cfparam *p, enum intparam ipnum, 29555939Snsouch const char *value) 29642475Snsouch{ 29742475Snsouch struct cfstrings nss; 29887599Sobrien struct cfparam *dp, *np; 29942475Snsouch struct cfstring *s, *ns; 300185003Sjhb struct cfvar *v, *nv; 30142475Snsouch const char *name; 30238061Smsmith char *cs, *tname; 30355939Snsouch unsigned flags; 30455939Snsouch 30538061Smsmith if (j == NULL) { 30655939Snsouch /* Create a single anonymous jail if one doesn't yet exist. */ 30738061Smsmith j = TAILQ_LAST(&cfjails, cfjails); 30838061Smsmith if (j == NULL) 30938061Smsmith j = add_jail(); 31038061Smsmith } 31138061Smsmith TAILQ_INIT(&nss); 31239134Snsouch if (p != NULL) { 31338061Smsmith name = p->name; 31439134Snsouch flags = p->flags; 31538061Smsmith /* 31639134Snsouch * Make a copy of the parameter's string list, 317185003Sjhb * which may be freed if it's overridden later. 31838061Smsmith */ 31955939Snsouch TAILQ_FOREACH(s, &p->val, tq) { 32039134Snsouch ns = emalloc(sizeof(struct cfstring)); 32138061Smsmith ns->s = estrdup(s->s); 32239134Snsouch ns->len = s->len; 32338061Smsmith STAILQ_INIT(&ns->vars); 32439134Snsouch STAILQ_FOREACH(v, &s->vars, tq) { 32538061Smsmith nv = emalloc(sizeof(struct cfvar)); 32639134Snsouch nv->name = strdup(v->name); 32739134Snsouch nv->pos = v->pos; 32839134Snsouch STAILQ_INSERT_TAIL(&ns->vars, nv, tq); 32939134Snsouch } 33039134Snsouch TAILQ_INSERT_TAIL(&nss, ns, tq); 33139134Snsouch } 33238061Smsmith } else { 33339134Snsouch flags = PF_APPEND; 33455939Snsouch if (ipnum != IP__NULL) { 33539134Snsouch name = intparams[ipnum].name; 33639134Snsouch flags |= intparams[ipnum].flags; 33738061Smsmith } else if ((cs = strchr(value, '='))) { 33838061Smsmith tname = alloca(cs - value + 1); 33938061Smsmith strlcpy(tname, value, cs - value + 1); 34039134Snsouch name = tname; 34138061Smsmith value = cs + 1; 34239134Snsouch } else { 34339134Snsouch name = value; 34438061Smsmith value = NULL; 34555939Snsouch } 34639134Snsouch if (value != NULL) { 34738061Smsmith ns = emalloc(sizeof(struct cfstring)); 34855939Snsouch ns->s = estrdup(value); 34938061Smsmith ns->len = strlen(value); 35039134Snsouch STAILQ_INIT(&ns->vars); 35138061Smsmith TAILQ_INSERT_TAIL(&nss, ns, tq); 35238061Smsmith } 35338061Smsmith } 35438061Smsmith 35538061Smsmith /* See if this parameter has already been added. */ 35638061Smsmith if (ipnum != IP__NULL) 35738061Smsmith dp = j->intparams[ipnum]; 35839134Snsouch else 35938061Smsmith TAILQ_FOREACH(dp, &j->params, tq) 36038061Smsmith if (!(dp->flags & PF_CONV) && equalopts(dp->name, name)) 36155939Snsouch break; 36239520Snsouch if (dp != NULL) { 36338061Smsmith /* Found it - append or replace. */ 36439520Snsouch if (strcmp(dp->name, name)) { 36555939Snsouch free(dp->name); 366185003Sjhb dp->name = estrdup(name); 36739520Snsouch } 36878645Snsouch if (!(flags & PF_APPEND) || TAILQ_EMPTY(&nss)) 36955939Snsouch free_param_strings(dp); 37039520Snsouch TAILQ_CONCAT(&dp->val, &nss, tq); 37170608Snsouch dp->flags |= flags; 37270608Snsouch } else { 37370608Snsouch /* Not found - add it. */ 37470608Snsouch np = emalloc(sizeof(struct cfparam)); 37555939Snsouch np->name = estrdup(name); 37670608Snsouch TAILQ_INIT(&np->val); 37739520Snsouch TAILQ_CONCAT(&np->val, &nss, tq); 37870608Snsouch np->flags = flags; 37970608Snsouch np->gen = 0; 38070608Snsouch TAILQ_INSERT_TAIL(&j->params, np, tq); 38139520Snsouch if (ipnum != IP__NULL) 38270608Snsouch j->intparams[ipnum] = np; 38370608Snsouch else 38470608Snsouch for (ipnum = IP__NULL + 1; ipnum < IP_NPARAM; ipnum++) 38570608Snsouch if (!(intparams[ipnum].flags & PF_CONV) && 38670608Snsouch equalopts(name, intparams[ipnum].name)) { 38739520Snsouch j->intparams[ipnum] = np; 38870608Snsouch np->flags |= intparams[ipnum].flags; 38970608Snsouch break; 39070608Snsouch } 39170608Snsouch } 39270608Snsouch} 39370608Snsouch 39470608Snsouch/* 39570608Snsouch * Return if a boolean parameter exists and is true. 39670608Snsouch */ 39770608Snsouchint 39855939Snsouchbool_param(const struct cfparam *p) 39970608Snsouch{ 40070608Snsouch const char *cs; 40139520Snsouch 402184130Sjhb if (p == NULL) 403184130Sjhb return 0; 40439520Snsouch cs = strrchr(p->name, '.'); 40539520Snsouch return !strncmp(cs ? cs + 1 : p->name, "no", 2) ^ 40655939Snsouch (TAILQ_EMPTY(&p->val) || 40739520Snsouch !strcasecmp(TAILQ_LAST(&p->val, cfstrings)->s, "true") || 40839520Snsouch (strtol(TAILQ_LAST(&p->val, cfstrings)->s, NULL, 10))); 40939520Snsouch} 41070608Snsouch 41170608Snsouch/* 41238061Smsmith * Set an integer if a parameter if it exists. 41338061Smsmith */ 41438061Smsmithint 41538061Smsmithint_param(const struct cfparam *p, int *ip) 41638061Smsmith{ 41755939Snsouch if (p == NULL || TAILQ_EMPTY(&p->val)) 41838061Smsmith return 0; 419185003Sjhb *ip = strtol(TAILQ_LAST(&p->val, cfstrings)->s, NULL, 10); 42039134Snsouch return 1; 42170608Snsouch} 42239520Snsouch 423184130Sjhb/* 424184130Sjhb * Return the string value of a scalar parameter if it exists. 42539520Snsouch */ 42639520Snsouchconst char * 42738061Smsmithstring_param(const struct cfparam *p) 42855939Snsouch{ 42938061Smsmith return (p && !TAILQ_EMPTY(&p->val) 43039520Snsouch ? TAILQ_LAST(&p->val, cfstrings)->s : NULL); 43139520Snsouch} 43255939Snsouch 43339520Snsouch/* 43438061Smsmith * Check syntax and values of internal parameters. Set some internal 43538061Smsmith * parameters based on the values of others. 43638061Smsmith */ 43738061Smsmithint 43838061Smsmithcheck_intparams(struct cfjail *j) 43938061Smsmith{ 44038061Smsmith struct cfparam *p; 44138061Smsmith struct cfstring *s; 44255939Snsouch FILE *f; 44338061Smsmith const char *val; 44438061Smsmith char *cs, *ep, *ln; 44555939Snsouch size_t lnlen; 44645342Speter int error; 44738061Smsmith#if defined(INET) || defined(INET6) 44855939Snsouch struct addrinfo hints; 44938061Smsmith struct addrinfo *ai0, *ai; 45038061Smsmith const char *hostname; 45138061Smsmith int gicode, defif, prefix; 45238061Smsmith#endif 45338061Smsmith#ifdef INET 45438061Smsmith struct in_addr addr4; 45538061Smsmith int ip4ok; 45638061Smsmith char avalue4[INET_ADDRSTRLEN]; 45738061Smsmith#endif 45838061Smsmith#ifdef INET6 45955939Snsouch struct in6_addr addr6; 46038061Smsmith int ip6ok; 46138061Smsmith char avalue6[INET6_ADDRSTRLEN]; 46255939Snsouch#endif 46345342Speter 46438061Smsmith error = 0; 46555939Snsouch /* Check format of boolan and integer values. */ 46638061Smsmith TAILQ_FOREACH(p, &j->params, tq) { 46738061Smsmith if (!TAILQ_EMPTY(&p->val) && (p->flags & (PF_BOOL | PF_INT))) { 46838061Smsmith val = TAILQ_LAST(&p->val, cfstrings)->s; 46938061Smsmith if (p->flags & PF_BOOL) { 47038061Smsmith if (strcasecmp(val, "false") && 47138061Smsmith strcasecmp(val, "true") && 47238061Smsmith ((void)strtol(val, &ep, 10), *ep)) { 47355939Snsouch jail_warnx(j, 47438061Smsmith "%s: unknown boolean value \"%s\"", 47538061Smsmith p->name, val); 47638061Smsmith error = -1; 47738061Smsmith } 47838061Smsmith } else { 47938061Smsmith (void)strtol(val, &ep, 10); 48038061Smsmith if (ep == val || *ep) { 48138061Smsmith jail_warnx(j, 48238061Smsmith "%s: non-integer value \"%s\"", 48338061Smsmith p->name, val); 48438061Smsmith error = -1; 48538061Smsmith } 48638061Smsmith } 48738061Smsmith } 48838061Smsmith } 48938061Smsmith 49038061Smsmith#if defined(INET) || defined(INET6) 49138061Smsmith /* 49243433Snsouch * The ip_hostname parameter looks up the hostname, and adds parameters 49343433Snsouch * for any IP addresses it finds. 49438061Smsmith */ 49538061Smsmith if (((j->flags & JF_OP_MASK) != JF_STOP || 49638061Smsmith j->intparams[IP_INTERFACE] != NULL) && 49738061Smsmith bool_param(j->intparams[IP_IP_HOSTNAME]) && 49838061Smsmith (hostname = string_param(j->intparams[KP_HOST_HOSTNAME]))) { 49938061Smsmith j->intparams[IP_IP_HOSTNAME] = NULL; 50038061Smsmith /* 50138061Smsmith * Silently ignore unsupported address families from 502185003Sjhb * DNS lookups. 50355939Snsouch */ 50438061Smsmith#ifdef INET 50538061Smsmith ip4ok = feature_present("inet"); 50638061Smsmith#endif 50738061Smsmith#ifdef INET6 50838061Smsmith ip6ok = feature_present("inet6"); 50938061Smsmith#endif 51038061Smsmith if ( 51138061Smsmith#if defined(INET) && defined(INET6) 51238061Smsmith ip4ok || ip6ok 51338061Smsmith#elif defined(INET) 51438061Smsmith ip4ok 51538061Smsmith#elif defined(INET6) 51638061Smsmith ip6ok 51738061Smsmith#endif 51838061Smsmith ) { 51938061Smsmith /* Look up the hostname (or get the address) */ 52038061Smsmith memset(&hints, 0, sizeof(hints)); 52178645Snsouch hints.ai_socktype = SOCK_STREAM; 52278645Snsouch hints.ai_family = 52355939Snsouch#if defined(INET) && defined(INET6) 52478645Snsouch ip4ok ? (ip6ok ? PF_UNSPEC : PF_INET) : PF_INET6; 52538061Smsmith#elif defined(INET) 52638061Smsmith PF_INET; 52755939Snsouch#elif defined(INET6) 52838061Smsmith PF_INET6; 52938061Smsmith#endif 53055939Snsouch gicode = getaddrinfo(hostname, NULL, &hints, &ai0); 53138061Smsmith if (gicode != 0) { 53238061Smsmith jail_warnx(j, "host.hostname %s: %s", hostname, 53338061Smsmith gai_strerror(gicode)); 53438061Smsmith error = -1; 53538061Smsmith } else { 53638061Smsmith /* 53738061Smsmith * Convert the addresses to ASCII so jailparam 53838061Smsmith * can convert them back. Errors are not 53938061Smsmith * expected here. 54038061Smsmith */ 54178645Snsouch for (ai = ai0; ai; ai = ai->ai_next) 54278645Snsouch switch (ai->ai_family) { 54378645Snsouch#ifdef INET 54478645Snsouch case AF_INET: 54578645Snsouch memcpy(&addr4, 54678645Snsouch &((struct sockaddr_in *) 54778645Snsouch (void *)ai->ai_addr)-> 548185003Sjhb sin_addr, sizeof(addr4)); 54978645Snsouch if (inet_ntop(AF_INET, 55078645Snsouch &addr4, avalue4, 55138061Smsmith INET_ADDRSTRLEN) == NULL) 55238061Smsmith err(1, "inet_ntop"); 55338061Smsmith add_param(j, NULL, KP_IP4_ADDR, 55438061Smsmith avalue4); 55538061Smsmith break; 55638061Smsmith#endif 55738061Smsmith#ifdef INET6 55838061Smsmith case AF_INET6: 55955939Snsouch memcpy(&addr6, 56055939Snsouch &((struct sockaddr_in6 *) 56138061Smsmith (void *)ai->ai_addr)-> 56255939Snsouch sin6_addr, sizeof(addr6)); 56338061Smsmith if (inet_ntop(AF_INET6, 56438061Smsmith &addr6, avalue6, 56555939Snsouch INET6_ADDRSTRLEN) == NULL) 56638061Smsmith err(1, "inet_ntop"); 56739134Snsouch add_param(j, NULL, KP_IP6_ADDR, 56839134Snsouch avalue6); 56939134Snsouch break; 57039134Snsouch#endif 57139134Snsouch } 57238061Smsmith freeaddrinfo(ai0); 57355939Snsouch } 57455939Snsouch } 57538061Smsmith } 57638061Smsmith 57755939Snsouch /* 57838061Smsmith * IP addresses may include an interface to set that address on, 57938061Smsmith * a netmask/suffix for that address and options for ifconfig. 58038061Smsmith * These are copied to an internal command parameter and then stripped 58138061Smsmith * so they won't be passed on to jailparam_set. 58238061Smsmith */ 58338061Smsmith defif = string_param(j->intparams[IP_INTERFACE]) != NULL; 58438061Smsmith#ifdef INET 58538061Smsmith if (j->intparams[KP_IP4_ADDR] != NULL) { 58638061Smsmith TAILQ_FOREACH(s, &j->intparams[KP_IP4_ADDR]->val, tq) { 58738061Smsmith cs = strchr(s->s, '|'); 58838061Smsmith if (cs || defif) 589185003Sjhb add_param(j, NULL, IP__IP4_IFADDR, s->s); 59055939Snsouch if (cs) { 59170608Snsouch strcpy(s->s, cs + 1); 59238061Smsmith s->len -= cs + 1 - s->s; 59338061Smsmith } 59438061Smsmith if ((cs = strchr(s->s, '/'))) { 59538061Smsmith prefix = strtol(cs + 1, &ep, 10); 59638061Smsmith if (*ep == '.' 59755939Snsouch ? inet_pton(AF_INET, cs + 1, &addr4) != 1 59838061Smsmith : *ep || prefix < 0 || prefix > 32) { 59938061Smsmith jail_warnx(j, 60038061Smsmith "ip4.addr: bad netmask \"%s\"", cs); 60138061Smsmith error = -1; 60238061Smsmith } 60378645Snsouch *cs = '\0'; 60478645Snsouch s->len = cs - s->s; 60578645Snsouch } 60678645Snsouch if ((cs = strchr(s->s, ' ')) != NULL) { 607185003Sjhb *cs = '\0'; 60838061Smsmith s->len = cs - s->s; 60938061Smsmith } 61038061Smsmith } 61138061Smsmith } 612187576Sjhb#endif 61370608Snsouch#ifdef INET6 61470608Snsouch if (j->intparams[KP_IP6_ADDR] != NULL) { 61538061Smsmith TAILQ_FOREACH(s, &j->intparams[KP_IP6_ADDR]->val, tq) { 61670608Snsouch cs = strchr(s->s, '|'); 61770608Snsouch if (cs || defif) 61870608Snsouch add_param(j, NULL, IP__IP6_IFADDR, s->s); 61970608Snsouch if (cs) { 62070608Snsouch strcpy(s->s, cs + 1); 621184130Sjhb s->len -= cs + 1 - s->s; 62270608Snsouch } 62370608Snsouch if ((cs = strchr(s->s, '/'))) { 62455939Snsouch prefix = strtol(cs + 1, &ep, 10); 62555939Snsouch if (*ep || prefix < 0 || prefix > 128) { 626184130Sjhb jail_warnx(j, 62770608Snsouch "ip6.addr: bad prefixlen \"%s\"", 62870608Snsouch cs); 62970608Snsouch error = -1; 63070608Snsouch } 631184130Sjhb *cs = '\0'; 63270608Snsouch s->len = cs - s->s; 63370608Snsouch } 63470608Snsouch if ((cs = strchr(s->s, ' ')) != NULL) { 63538061Smsmith *cs = '\0'; 63638061Smsmith s->len = cs - s->s; 63755939Snsouch } 63838061Smsmith } 63970608Snsouch } 640187576Sjhb#endif 64170608Snsouch#endif 64238061Smsmith 64338061Smsmith /* 64438061Smsmith * Read mount.fstab file(s), and treat each line as its own mount 64538061Smsmith * parameter. 64638061Smsmith */ 64738061Smsmith if (j->intparams[IP_MOUNT_FSTAB] != NULL) { 64838061Smsmith TAILQ_FOREACH(s, &j->intparams[IP_MOUNT_FSTAB]->val, tq) { 64938061Smsmith if (s->len == 0) 65038061Smsmith continue; 65138061Smsmith f = fopen(s->s, "r"); 65239520Snsouch if (f == NULL) { 65342475Snsouch jail_warnx(j, "mount.fstab: %s: %s", 65442475Snsouch s->s, strerror(errno)); 65587599Sobrien error = -1; 65642475Snsouch continue; 65738061Smsmith } 65838061Smsmith while ((ln = fgetln(f, &lnlen))) { 65938061Smsmith if ((cs = memchr(ln, '#', lnlen - 1))) 66038061Smsmith lnlen = cs - ln + 1; 66138061Smsmith if (ln[lnlen - 1] == '\n' || 66238061Smsmith ln[lnlen - 1] == '#') 66338061Smsmith ln[lnlen - 1] = '\0'; 66438061Smsmith else { 66538061Smsmith cs = alloca(lnlen + 1); 66638061Smsmith strlcpy(cs, ln, lnlen + 1); 66738061Smsmith ln = cs; 66838061Smsmith } 66938061Smsmith add_param(j, NULL, IP__MOUNT_FROM_FSTAB, ln); 67038061Smsmith } 67138061Smsmith fclose(f); 67238061Smsmith } 67338061Smsmith } 67438061Smsmith if (error) 67538061Smsmith failed(j); 67638061Smsmith return error; 677185003Sjhb} 67838061Smsmith 67938061Smsmith/* 68038061Smsmith * Import parameters into libjail's binary jailparam format. 68138061Smsmith */ 68255939Snsouchint 68338061Smsmithimport_params(struct cfjail *j) 68438061Smsmith{ 68538061Smsmith struct cfparam *p; 68638061Smsmith struct cfstring *s, *ts; 68738061Smsmith struct jailparam *jp; 68838061Smsmith char *value, *cs; 68938061Smsmith size_t vallen; 69038061Smsmith int error; 69138061Smsmith 69238061Smsmith error = 0; 69338061Smsmith j->njp = 0; 69438061Smsmith TAILQ_FOREACH(p, &j->params, tq) 69538061Smsmith if (!(p->flags & PF_INTERNAL)) 69638061Smsmith j->njp++; 69738061Smsmith j->jp = jp = emalloc(j->njp * sizeof(struct jailparam)); 69838061Smsmith TAILQ_FOREACH(p, &j->params, tq) { 69939520Snsouch if (p->flags & PF_INTERNAL) 700185003Sjhb continue; 701185003Sjhb if (jailparam_init(jp, p->name) < 0) { 70238061Smsmith error = -1; 70338061Smsmith jail_warnx(j, "%s", jail_errmsg); 70438061Smsmith jp++; 70538061Smsmith continue; 70638061Smsmith } 70738061Smsmith if (TAILQ_EMPTY(&p->val)) 70838061Smsmith value = NULL; 70938061Smsmith else if (!jp->jp_elemlen || 71038061Smsmith !TAILQ_NEXT(TAILQ_FIRST(&p->val), tq)) { 71138061Smsmith /* 71255939Snsouch * Scalar parameters silently discard multiple (array) 71338061Smsmith * values, keeping only the last value added. This 71438061Smsmith * lets values added from the command line append to 71538061Smsmith * arrays wthout pre-checking the type. 71638061Smsmith */ 71738061Smsmith value = TAILQ_LAST(&p->val, cfstrings)->s; 71838061Smsmith } else { 71938061Smsmith /* 72038061Smsmith * Convert arrays into comma-separated strings, which 72138061Smsmith * jailparam_import will then convert back into arrays. 72238061Smsmith */ 72338061Smsmith vallen = 0; 72438061Smsmith TAILQ_FOREACH(s, &p->val, tq) 725185003Sjhb vallen += s->len + 1; 726185003Sjhb value = alloca(vallen); 72738061Smsmith cs = value; 72838061Smsmith TAILQ_FOREACH_SAFE(s, &p->val, tq, ts) { 72938061Smsmith memcpy(cs, s->s, s->len); 73038061Smsmith cs += s->len + 1; 73138061Smsmith cs[-1] = ','; 73238061Smsmith } 733185003Sjhb value[vallen - 1] = '\0'; 734185003Sjhb } 73538061Smsmith if (jailparam_import(jp, value) < 0) { 73638061Smsmith error = -1; 73738061Smsmith jail_warnx(j, "%s", jail_errmsg); 73838061Smsmith } 73938061Smsmith jp++; 74038061Smsmith } 74138061Smsmith if (error) { 74238061Smsmith jailparam_free(j->jp, j->njp); 74338061Smsmith free(j->jp); 74438061Smsmith j->jp = NULL; 74538061Smsmith failed(j); 74639520Snsouch } 74739520Snsouch return error; 74839520Snsouch} 74955939Snsouch 75039520Snsouch/* 75139520Snsouch * Check if options are equal (with or without the "no" prefix). 75239520Snsouch */ 75339520Snsouchint 75439520Snsouchequalopts(const char *opt1, const char *opt2) 75538061Smsmith{ 75638061Smsmith char *p; 75738061Smsmith 75838061Smsmith /* "opt" vs. "opt" or "noopt" vs. "noopt" */ 75938061Smsmith if (strcmp(opt1, opt2) == 0) 76038061Smsmith return (1); 76138061Smsmith /* "noopt" vs. "opt" */ 76238061Smsmith if (strncmp(opt1, "no", 2) == 0 && strcmp(opt1 + 2, opt2) == 0) 76338061Smsmith return (1); 76438061Smsmith /* "opt" vs. "noopt" */ 76538061Smsmith if (strncmp(opt2, "no", 2) == 0 && strcmp(opt1, opt2 + 2) == 0) 76638061Smsmith return (1); 76738061Smsmith while ((p = strchr(opt1, '.')) != NULL && 76838061Smsmith !strncmp(opt1, opt2, ++p - opt1)) { 76938061Smsmith opt2 += p - opt1; 770185003Sjhb opt1 = p; 771185003Sjhb /* "foo.noopt" vs. "foo.opt" */ 77238061Smsmith if (strncmp(opt1, "no", 2) == 0 && strcmp(opt1 + 2, opt2) == 0) 77338061Smsmith return (1); 77438061Smsmith /* "foo.opt" vs. "foo.noopt" */ 77538061Smsmith if (strncmp(opt2, "no", 2) == 0 && strcmp(opt1, opt2 + 2) == 0) 77638061Smsmith return (1); 777185003Sjhb } 778185003Sjhb return (0); 77938061Smsmith} 78038061Smsmith 78138061Smsmith/* 78238061Smsmith * See if a jail name matches a wildcard. 78338061Smsmith */ 78438061Smsmithint 78538061Smsmithwild_jail_match(const char *jname, const char *wname) 78638061Smsmith{ 78738061Smsmith const char *jc, *jd, *wc, *wd; 788 789 /* 790 * A non-final "*" component in the wild name matches a single jail 791 * component, and a final "*" matches one or more jail components. 792 */ 793 for (jc = jname, wc = wname; 794 (jd = strchr(jc, '.')) && (wd = strchr(wc, '.')); 795 jc = jd + 1, wc = wd + 1) 796 if (strncmp(jc, wc, jd - jc + 1) && strncmp(wc, "*.", 2)) 797 return 0; 798 return (!strcmp(jc, wc) || !strcmp(wc, "*")); 799} 800 801/* 802 * Return if a jail name is a wildcard. 803 */ 804int 805wild_jail_name(const char *wname) 806{ 807 const char *wc; 808 809 for (wc = strchr(wname, '*'); wc; wc = strchr(wc + 1, '*')) 810 if ((wc == wname || wc[-1] == '.') && 811 (wc[1] == '\0' || wc[1] == '.')) 812 return 1; 813 return 0; 814} 815 816/* 817 * Free a parameter record and all its strings and variables. 818 */ 819static void 820free_param(struct cfparams *pp, struct cfparam *p) 821{ 822 free(p->name); 823 free_param_strings(p); 824 TAILQ_REMOVE(pp, p, tq); 825 free(p); 826} 827 828static void 829free_param_strings(struct cfparam *p) 830{ 831 struct cfstring *s; 832 struct cfvar *v; 833 834 while ((s = TAILQ_FIRST(&p->val))) { 835 free(s->s); 836 while ((v = STAILQ_FIRST(&s->vars))) { 837 free(v->name); 838 STAILQ_REMOVE_HEAD(&s->vars, tq); 839 free(v); 840 } 841 TAILQ_REMOVE(&p->val, s, tq); 842 free(s); 843 } 844} 845