Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/jail/config.c
Show All 32 Lines | |||||
#include <sys/errno.h> | #include <sys/errno.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <arpa/inet.h> | #include <arpa/inet.h> | ||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#include <err.h> | #include <err.h> | ||||
#include <glob.h> | |||||
#include <netdb.h> | #include <netdb.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include "jailp.h" | #include "jailp.h" | ||||
struct ipspec { | struct ipspec { | ||||
const char *name; | const char *name; | ||||
unsigned flags; | unsigned flags; | ||||
}; | }; | ||||
extern FILE *yyin; | extern int yylex_init_extra(struct cflex *extra, void *scanner); | ||||
extern int yynerrs; | extern int yylex_destroy(void *scanner); | ||||
extern int yyparse(void *scanner); | |||||
extern int yyset_in(FILE *fp, void *scanner); | |||||
extern int yyparse(void); | |||||
struct cfjails cfjails = TAILQ_HEAD_INITIALIZER(cfjails); | struct cfjails cfjails = TAILQ_HEAD_INITIALIZER(cfjails); | ||||
static void parse_config(const char *fname, int is_stdin, | |||||
struct cfjail *injail); | |||||
static void free_param(struct cfparams *pp, struct cfparam *p); | static void free_param(struct cfparams *pp, struct cfparam *p); | ||||
static void free_param_strings(struct cfparam *p); | |||||
static const struct ipspec intparams[] = { | static const struct ipspec intparams[] = { | ||||
[IP_ALLOW_DYING] = {"allow.dying", PF_INTERNAL | PF_BOOL}, | [IP_ALLOW_DYING] = {"allow.dying", PF_INTERNAL | PF_BOOL}, | ||||
[IP_COMMAND] = {"command", PF_INTERNAL}, | [IP_COMMAND] = {"command", PF_INTERNAL}, | ||||
[IP_DEPEND] = {"depend", PF_INTERNAL}, | [IP_DEPEND] = {"depend", PF_INTERNAL}, | ||||
[IP_EXEC_CLEAN] = {"exec.clean", PF_INTERNAL | PF_BOOL}, | [IP_EXEC_CLEAN] = {"exec.clean", PF_INTERNAL | PF_BOOL}, | ||||
[IP_EXEC_CONSOLELOG] = {"exec.consolelog", PF_INTERNAL}, | [IP_EXEC_CONSOLELOG] = {"exec.consolelog", PF_INTERNAL}, | ||||
[IP_EXEC_FIB] = {"exec.fib", PF_INTERNAL | PF_INT}, | [IP_EXEC_FIB] = {"exec.fib", PF_INTERNAL | PF_INT}, | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | #endif | ||||
[KP_NAME] = {"name", PF_IMMUTABLE}, | [KP_NAME] = {"name", PF_IMMUTABLE}, | ||||
[KP_PATH] = {"path", 0}, | [KP_PATH] = {"path", 0}, | ||||
[KP_PERSIST] = {"persist", 0}, | [KP_PERSIST] = {"persist", 0}, | ||||
[KP_SECURELEVEL] = {"securelevel", 0}, | [KP_SECURELEVEL] = {"securelevel", 0}, | ||||
[KP_VNET] = {"vnet", 0}, | [KP_VNET] = {"vnet", 0}, | ||||
}; | }; | ||||
/* | /* | ||||
* Parse the jail configuration file. | * Parse a jail config file, either initially from main, or from | ||||
* an include within another config file. | |||||
*/ | */ | ||||
void | void | ||||
load_config(void) | load_config(const char *cfname) | ||||
{ | { | ||||
struct cfjails wild; | struct cfjails wild; | ||||
struct cfparams opp; | struct cfparams opp; | ||||
struct cfjail *j, *tj, *wj; | struct cfjail *j, *tj, *wj; | ||||
struct cfparam *p, *vp, *tp; | struct cfparam *p, *vp, *tp; | ||||
struct cfstring *s, *vs, *ns; | struct cfstring *s, *vs, *ns; | ||||
struct cfvar *v, *vv; | struct cfvar *v, *vv; | ||||
char *ep; | char *ep; | ||||
int did_self, jseq, pgen; | int did_self, jseq, pgen; | ||||
if (!strcmp(cfname, "-")) { | parse_config(cfname, !strcmp(cfname, "-"), NULL); | ||||
cfname = "STDIN"; | |||||
yyin = stdin; | |||||
} else { | |||||
yyin = fopen(cfname, "r"); | |||||
if (!yyin) | |||||
err(1, "%s", cfname); | |||||
} | |||||
if (yyparse() || yynerrs) | |||||
exit(1); | |||||
/* Separate the wildcard jails out from the actual jails. */ | /* Separate the wildcard jails out from the actual jails. */ | ||||
jseq = 0; | jseq = 0; | ||||
TAILQ_INIT(&wild); | TAILQ_INIT(&wild); | ||||
TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) { | TAILQ_FOREACH_SAFE(j, &cfjails, tq, tj) { | ||||
j->seq = ++jseq; | j->seq = ++jseq; | ||||
if (wild_jail_name(j->name)) | if (wild_jail_name(j->name)) | ||||
requeue(j, &wild); | requeue(j, &wild); | ||||
▲ Show 20 Lines • Show All 110 Lines • ▼ Show 20 Lines | load_config(const char *cfname) | ||||
while ((wj = TAILQ_FIRST(&wild))) { | while ((wj = TAILQ_FIRST(&wild))) { | ||||
free(wj->name); | free(wj->name); | ||||
while ((p = TAILQ_FIRST(&wj->params))) | while ((p = TAILQ_FIRST(&wj->params))) | ||||
free_param(&wj->params, p); | free_param(&wj->params, p); | ||||
TAILQ_REMOVE(&wild, wj, tq); | TAILQ_REMOVE(&wild, wj, tq); | ||||
} | } | ||||
} | } | ||||
void | |||||
include_config(const char *cfname, struct cflex *cflex, int from_stdin) | |||||
{ | |||||
static unsigned int depth; | |||||
meka_tilda.center: Initialize all glob_t vars to zero/NULL. | |||||
glob_t g; | |||||
const char *slash; | |||||
char *fullpath = NULL; | |||||
/* Basic sanity check for include loops. */ | |||||
if (++depth > 32) | |||||
errx(1, "maximum include depth exceeded"); | |||||
/* Base relative pathnames on the current config file. */ | |||||
if (!from_stdin && cfname[0] != '/' && | |||||
(slash = strrchr(cflex->cfname, '/')) != NULL) { | |||||
size_t dirlen = (slash - cflex->cfname) + 1; | |||||
fullpath = emalloc(dirlen + strlen(cfname) + 1); | |||||
strncpy(fullpath, cflex->cfname, dirlen); | |||||
strcpy(fullpath + dirlen, cfname); | |||||
cfname = fullpath; | |||||
} | |||||
/* | /* | ||||
* Check if the include statement had a filename glob. | |||||
* Globbing doesn't need to catch any files, but a non-glob | |||||
* file needs to exist (enforced by parse_config). | |||||
Done Inline ActionsChecking if the file was already included would need to happen somewhere here. ihor_antonovs.family: Checking if the file was already included would need to happen somewhere here. | |||||
*/ | |||||
if (glob(cfname, GLOB_NOCHECK, NULL, &g) != 0) | |||||
errx(1, "%s: filename glob failed", cfname); | |||||
if (g.gl_flags & GLOB_MAGCHAR) { | |||||
for (size_t gi = 0; gi < g.gl_matchc; gi++) | |||||
parse_config(g.gl_pathv[gi], 0, cflex->injail); | |||||
} else | |||||
parse_config(cfname, 0, cflex->injail); | |||||
if (fullpath) | |||||
free(fullpath); | |||||
--depth; | |||||
} | |||||
static void | |||||
parse_config(const char *cfname, int is_stdin, struct cfjail *injail) | |||||
{ | |||||
struct cflex cflex = {.cfname = cfname, .injail = injail, .error = 0}; | |||||
void *scanner; | |||||
yylex_init_extra(&cflex, &scanner); | |||||
if (is_stdin) { | |||||
yyset_in(stdin, scanner); | |||||
} else { | |||||
FILE *cfp = fopen(cfname, "r"); | |||||
if (!cfp) | |||||
err(1, "%s", cfname); | |||||
yyset_in(cfp, scanner); | |||||
} | |||||
if (yyparse(scanner) || cflex.error) | |||||
exit(1); | |||||
yylex_destroy(scanner); | |||||
} | |||||
/* | |||||
* Create a new jail record. | * Create a new jail record. | ||||
*/ | */ | ||||
struct cfjail * | struct cfjail * | ||||
add_jail(void) | add_jail(void) | ||||
{ | { | ||||
struct cfjail *j; | struct cfjail *j; | ||||
j = emalloc(sizeof(struct cfjail)); | j = emalloc(sizeof(struct cfjail)); | ||||
▲ Show 20 Lines • Show All 545 Lines • ▼ Show 20 Lines | |||||
free_param(struct cfparams *pp, struct cfparam *p) | free_param(struct cfparams *pp, struct cfparam *p) | ||||
{ | { | ||||
free(p->name); | free(p->name); | ||||
free_param_strings(p); | free_param_strings(p); | ||||
TAILQ_REMOVE(pp, p, tq); | TAILQ_REMOVE(pp, p, tq); | ||||
free(p); | free(p); | ||||
} | } | ||||
static void | void | ||||
free_param_strings(struct cfparam *p) | free_param_strings(struct cfparam *p) | ||||
{ | { | ||||
struct cfstring *s; | struct cfstring *s; | ||||
struct cfvar *v; | struct cfvar *v; | ||||
while ((s = TAILQ_FIRST(&p->val))) { | while ((s = TAILQ_FIRST(&p->val))) { | ||||
free(s->s); | free(s->s); | ||||
while ((v = STAILQ_FIRST(&s->vars))) { | while ((v = STAILQ_FIRST(&s->vars))) { | ||||
free(v->name); | free(v->name); | ||||
STAILQ_REMOVE_HEAD(&s->vars, tq); | STAILQ_REMOVE_HEAD(&s->vars, tq); | ||||
free(v); | free(v); | ||||
} | } | ||||
TAILQ_REMOVE(&p->val, s, tq); | TAILQ_REMOVE(&p->val, s, tq); | ||||
free(s); | free(s); | ||||
} | } | ||||
} | } |
Initialize all glob_t vars to zero/NULL.