Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F115789554
D40188.id122676.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
16 KB
Referenced Files
None
Subscribers
None
D40188.id122676.diff
View Options
diff --git a/usr.sbin/jail/config.c b/usr.sbin/jail/config.c
--- a/usr.sbin/jail/config.c
+++ b/usr.sbin/jail/config.c
@@ -38,6 +38,7 @@
#include <netinet/in.h>
#include <err.h>
+#include <glob.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
@@ -51,15 +52,16 @@
unsigned flags;
};
-extern FILE *yyin;
-extern int yynerrs;
-
-extern int yyparse(void);
+extern int yylex_init_extra(struct cflex *extra, void *scanner);
+extern int yylex_destroy(void *scanner);
+extern int yyparse(void *scanner);
+extern int yyset_in(FILE *fp, void *scanner);
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_strings(struct cfparam *p);
static const struct ipspec intparams[] = {
[IP_ALLOW_DYING] = {"allow.dying", PF_INTERNAL | PF_BOOL},
@@ -124,10 +126,11 @@
};
/*
- * Parse the jail configuration file.
+ * Parse a jail config file, either initially from main, or from
+ * an include within another config file.
*/
void
-load_config(void)
+load_config(const char *cfname)
{
struct cfjails wild;
struct cfparams opp;
@@ -138,16 +141,7 @@
char *ep;
int did_self, jseq, pgen;
- if (!strcmp(cfname, "-")) {
- cfname = "STDIN";
- yyin = stdin;
- } else {
- yyin = fopen(cfname, "r");
- if (!yyin)
- err(1, "%s", cfname);
- }
- if (yyparse() || yynerrs)
- exit(1);
+ parse_config(cfname, !strcmp(cfname, "-"), NULL);
/* Separate the wildcard jails out from the actual jails. */
jseq = 0;
@@ -274,6 +268,64 @@
}
}
+void
+include_config(const char *cfname, struct cflex *cflex, int from_stdin)
+{
+ static unsigned int depth;
+ 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).
+ */
+ 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.
*/
@@ -836,7 +888,7 @@
free(p);
}
-static void
+void
free_param_strings(struct cfparam *p)
{
struct cfstring *s;
diff --git a/usr.sbin/jail/jail.c b/usr.sbin/jail/jail.c
--- a/usr.sbin/jail/jail.c
+++ b/usr.sbin/jail/jail.c
@@ -56,7 +56,6 @@
int rev;
};
-const char *cfname;
int iflag;
int note_remove;
int verbose;
@@ -137,6 +136,7 @@
struct stat st;
FILE *jfp;
struct cfjail *j;
+ const char *cfname;
char *JidFile;
size_t sysvallen;
unsigned op, pi;
@@ -287,7 +287,7 @@
} else if (op == JF_STOP || op == JF_SHOW) {
/* Just print list of all configured non-wildcard jails */
if (op == JF_SHOW) {
- load_config();
+ load_config(cfname);
show_jails();
exit(0);
}
@@ -300,7 +300,7 @@
usage();
if ((docf = !Rflag &&
(!strcmp(cfname, "-") || stat(cfname, &st) == 0)))
- load_config();
+ load_config(cfname);
note_remove = docf || argc > 1 || wild_jail_name(argv[0]);
} else if (argc > 1 || (argc == 1 && strchr(argv[0], '='))) {
/* Single jail specified on the command line */
@@ -348,7 +348,7 @@
/* From the config file, perhaps with a specified jail */
if (Rflag || !docf)
usage();
- load_config();
+ load_config(cfname);
}
/* Find out which jails will be run. */
diff --git a/usr.sbin/jail/jail.conf.5 b/usr.sbin/jail/jail.conf.5
--- a/usr.sbin/jail/jail.conf.5
+++ b/usr.sbin/jail/jail.conf.5
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 8, 2022
+.Dd May 20, 2023
.Dt JAIL.CONF 5
.Os
.Sh NAME
@@ -163,6 +163,14 @@
.Dq foo.bar
and
.Dq foo.bar.baz .
+.Ss Includes
+A line of the form
+.Bd -literal -offset ident
+.include "filename";
+.Ed
+.Pp
+will include another file in the configuration. The filename must be
+a literal string, and cannot contain variable expansions.
.Ss Comments
The configuration file may contain comments in the common C, C++, and
shell formats:
@@ -212,6 +220,13 @@
mount.nodevfs;
persist; // Required because there are no processes
}
+
+# Include configurations from standard locations.
+.include "/etc/jail.conf.d/*.conf";
+.include "/etc/jail.*.conf";
+.include "/usr/local/etc/jail[.]conf";
+.include "/usr/local/etc/jail.conf.d/*.conf";
+.include "/usr/local/etc/jail.*.conf";
.Ed
.Sh SEE ALSO
.Xr jail_set 2 ,
diff --git a/usr.sbin/jail/jaillex.l b/usr.sbin/jail/jaillex.l
--- a/usr.sbin/jail/jaillex.l
+++ b/usr.sbin/jail/jaillex.l
@@ -38,19 +38,22 @@
#include "jailp.h"
#include "y.tab.h"
-extern int yynerrs;
+#define YY_DECL int yylex(YYSTYPE *yylval, yyscan_t yyscanner)
+#define YY_EXTRA_TYPE struct cflex*
-static ssize_t text2lval(size_t triml, size_t trimr, int tovar);
+extern YY_DECL;
static int instr;
-static int lineno = 1;
-#define YY_DECL int yylex(void)
+static ssize_t text2lval(size_t triml, size_t trimr, int tovar,
+ YYSTYPE *yylval, yyscan_t scanner);
%}
%option noyywrap
%option noinput
%option nounput
+%option reentrant
+%option yylineno
%start _ DQ
@@ -60,18 +63,8 @@
<_>[ \t]+ instr = 0;
<_>#.* ;
<_>\/\/.* ;
-<_>\/\*([^*]|(\*+([^*\/])))*\*+\/ {
- const char *s;
-
- for (s = yytext; s < yytext + yyleng; s++)
- if (*s == '\n')
- lineno++;
- instr = 0;
- }
-<_>\n {
- lineno++;
- instr = 0;
- }
+<_>\/\*([^*]|(\*+([^*\/])))*\*+\/ instr = 0;
+<_>\n instr = 0;
/* Reserved tokens */
<_>\+= {
@@ -87,13 +80,13 @@
<_,DQ>[A-Za-z0-9_!%&()\-.:<>?@\[\]^`|~]+ |
<_,DQ>\\(.|\n|[0-7]{1,3}|x[0-9A-Fa-f]{1,2}) |
<_,DQ>[$*+/\\] {
- (void)text2lval(0, 0, 0);
+ (void)text2lval(0, 0, 0, yylval, yyscanner);
return instr ? STR1 : (instr = 1, STR);
}
/* Single and double quoted strings */
<_>'([^\'\\]|\\(.|\n))*' {
- (void)text2lval(1, 1, 0);
+ (void)text2lval(1, 1, 0, yylval, yyscanner);
return instr ? STR1 : (instr = 1, STR);
}
<_>\"([^"\\]|\\(.|\n))*\" |
@@ -102,7 +95,8 @@
ssize_t atvar;
skip = yytext[0] == '"' ? 1 : 0;
- atvar = text2lval(skip, 1, 1);
+ atvar = text2lval(skip, 1, 1, yylval,
+ yyscanner);
if (atvar < 0)
BEGIN _;
else {
@@ -120,32 +114,32 @@
/* Variables, single-word or bracketed */
<_,DQ>$[A-Za-z_][A-Za-z_0-9]* {
- (void)text2lval(1, 0, 0);
+ (void)text2lval(1, 0, 0, yylval, yyscanner);
return instr ? VAR1 : (instr = 1, VAR);
}
<_>$\{([^\n{}]|\\(.|\n))*\} |
<DQ>$\{([^\n\"{}]|\\(.|\n))*\} {
- (void)text2lval(2, 1, 0);
+ (void)text2lval(2, 1, 0, yylval, yyscanner);
return instr ? VAR1 : (instr = 1, VAR);
}
/* Partially formed bits worth complaining about */
<_>\/\*([^*]|(\*+([^*\/])))*\** {
warnx("%s line %d: unterminated comment",
- cfname, lineno);
- yynerrs++;
+ yyextra->cfname, yylineno);
+ yyextra->error = 1;
}
<_>'([^\n'\\]|\\.)* |
<_>\"([^\n\"\\]|\\.)* {
warnx("%s line %d: unterminated string",
- cfname, lineno);
- yynerrs++;
+ yyextra->cfname, yylineno);
+ yyextra->error = 1;
}
<_>$\{([^\n{}]|\\.)* |
<DQ>$\{([^\n\"{}]|\\.)* {
warnx("%s line %d: unterminated variable",
- cfname, lineno);
- yynerrs++;
+ yyextra->cfname, yylineno);
+ yyextra->error = 1;
}
/* A hack because "<0>" rules aren't allowed */
@@ -157,28 +151,19 @@
%%
-void
-yyerror(const char *s)
-{
- if (!yytext)
- warnx("%s line %d: %s", cfname, lineno, s);
- else if (!yytext[0])
- warnx("%s: unexpected EOF", cfname);
- else
- warnx("%s line %d: %s: %s", cfname, lineno, yytext, s);
-}
-
/*
* Copy string from yytext to yylval, handling backslash escapes,
* and optionally stopping at the beginning of a variable.
*/
static ssize_t
-text2lval(size_t triml, size_t trimr, int tovar)
+text2lval(size_t triml, size_t trimr, int tovar, YYSTYPE *yylval,
+ yyscan_t scanner)
{
char *d;
const char *s, *se;
- yylval.cs = d = emalloc(yyleng - trimr - triml + 1);
+ struct yyguts_t *yyg = scanner;
+ yylval->cs = d = emalloc(yyleng - trimr - triml + 1);
se = yytext + (yyleng - trimr);
for (s = yytext + triml; s < se; s++, d++) {
if (*s != '\\') {
@@ -186,8 +171,6 @@
*d = '\0';
return s - yytext;
}
- if (*s == '\n')
- lineno++;
*d = *s;
continue;
}
@@ -209,8 +192,8 @@
case 'r': *d = '\r'; break;
case 't': *d = '\t'; break;
case 'v': *d = '\v'; break;
- case '\n': d--; lineno++; break;
default: *d = *s; break;
+ case '\n': d--; break;
case 'x':
*d = 0;
if (s + 1 >= se)
diff --git a/usr.sbin/jail/jailp.h b/usr.sbin/jail/jailp.h
--- a/usr.sbin/jail/jailp.h
+++ b/usr.sbin/jail/jailp.h
@@ -45,15 +45,16 @@
#define DF_LIGHT 0x02 /* Implied dependency on jail existence only */
#define DF_NOFAIL 0x04 /* Don't propagate failed jails */
-#define PF_VAR 0x01 /* This is a variable, not a true parameter */
-#define PF_APPEND 0x02 /* Append to existing parameter list */
-#define PF_BAD 0x04 /* Unable to resolve parameter value */
-#define PF_INTERNAL 0x08 /* Internal parameter, not passed to kernel */
-#define PF_BOOL 0x10 /* Boolean parameter */
-#define PF_INT 0x20 /* Integer parameter */
-#define PF_CONV 0x40 /* Parameter duplicated in converted form */
-#define PF_REV 0x80 /* Run commands in reverse order on stopping */
-#define PF_IMMUTABLE 0x100 /* Immutable parameter */
+#define PF_VAR 0x0001 /* This is a variable, not a true parameter */
+#define PF_APPEND 0x0002 /* Append to existing parameter list */
+#define PF_BAD 0x0004 /* Unable to resolve parameter value */
+#define PF_INTERNAL 0x0008 /* Internal parameter, not passed to kernel */
+#define PF_BOOL 0x0010 /* Boolean parameter */
+#define PF_INT 0x0020 /* Integer parameter */
+#define PF_CONV 0x0040 /* Parameter duplicated in converted form */
+#define PF_REV 0x0080 /* Run commands in reverse order on stopping */
+#define PF_IMMUTABLE 0x0100 /* Immutable parameter */
+#define PF_NAMEVAL 0x0200 /* Parameter is in "name value" form */
#define JF_START 0x0001 /* -c */
#define JF_SET 0x0002 /* -m */
@@ -176,6 +177,7 @@
struct cfparams params;
struct cfdepends dep[2];
struct cfjails *queue;
+ struct cfjail *cfparent;
struct cfparam *intparams[IP_NPARAM];
struct cfstring *comstring;
struct jailparam *jp;
@@ -196,6 +198,12 @@
unsigned flags;
};
+struct cflex {
+ const char *cfname;
+ struct cfjail *injail;
+ int error;
+};
+
extern void *emalloc(size_t);
extern void *erealloc(void *, size_t);
extern char *estrdup(const char *);
@@ -208,7 +216,9 @@
extern int finish_command(struct cfjail *j);
extern struct cfjail *next_proc(int nonblock);
-extern void load_config(void);
+extern void load_config(const char *cfname);
+extern void include_config(const char *cfname, struct cflex *cflex,
+ int from_stdin);
extern struct cfjail *add_jail(void);
extern void add_param(struct cfjail *j, const struct cfparam *p,
enum intparam ipnum, const char *value);
@@ -220,6 +230,7 @@
extern int equalopts(const char *opt1, const char *opt2);
extern int wild_jail_name(const char *wname);
extern int wild_jail_match(const char *jname, const char *wname);
+extern void free_param_strings(struct cfparam *p);
extern void dep_setup(int docf);
extern int dep_check(struct cfjail *j);
@@ -231,13 +242,9 @@
extern void requeue(struct cfjail *j, struct cfjails *queue);
extern void requeue_head(struct cfjail *j, struct cfjails *queue);
-extern void yyerror(const char *);
-extern int yylex(void);
-
extern struct cfjails cfjails;
extern struct cfjails ready;
extern struct cfjails depend;
-extern const char *cfname;
extern int iflag;
extern int note_remove;
extern int paralimit;
diff --git a/usr.sbin/jail/jailparse.y b/usr.sbin/jail/jailparse.y
--- a/usr.sbin/jail/jailparse.y
+++ b/usr.sbin/jail/jailparse.y
@@ -30,6 +30,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <err.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -52,12 +54,17 @@
%token PLEQ
%token <cs> STR STR1 VAR VAR1
-%type <j> jail
+%type <j> jail jail_name
%type <pp> param_l
%type <p> param name
%type <ss> value
%type <s> string
+%pure-parser
+
+%lex-param { void *scanner }
+%parse-param { void *scanner }
+
%%
/*
@@ -70,35 +77,63 @@
;
| conf param ';'
{
- struct cfjail *j;
-
- j = TAILQ_LAST(&cfjails, cfjails);
- if (!j || strcmp(j->name, "*")) {
- j = add_jail();
- j->name = estrdup("*");
+ if (!special_param($2, scanner)) {
+ struct cfjail *j = yyget_extra(scanner)->injail;
+ if (!j)
+ {
+ j = TAILQ_LAST(&cfjails, cfjails);
+ if (!j || strcmp(j->name, "*")) {
+ j = add_jail();
+ j->name = estrdup("*");
+ }
+ }
+ TAILQ_INSERT_TAIL(&j->params, $2, tq);
}
- TAILQ_INSERT_TAIL(&j->params, $2, tq);
}
| conf ';'
-jail : STR '{' param_l '}'
+/*
+ * Allow nested jail definitions by prepending the outer jail name to
+ * the inner one.
+ */
+jail : jail_name '{' param_l '}'
{
- $$ = add_jail();
- $$->name = $1;
+ $$ = $1;
TAILQ_CONCAT(&$$->params, $3, tq);
free($3);
+ yyget_extra(scanner)->injail = $1->cfparent;
}
;
+jail_name : STR
+ {
+ $$ = add_jail();
+ $$->cfparent = yyget_extra(scanner)->injail;
+ yyget_extra(scanner)->injail = $$;
+ if ($$->cfparent != NULL) {
+ size_t parentlen = strlen($$->cfparent->name);
+ $$->name = emalloc(parentlen + strlen($1) + 2);
+ strcpy($$->name, $$->cfparent->name);
+ $$->name[parentlen++] = '.';
+ strcpy($$->name + parentlen, $1);
+ free($1);
+ } else
+ $$->name = $1;
+ }
+
param_l :
{
$$ = emalloc(sizeof(struct cfparams));
TAILQ_INIT($$);
}
+ | param_l jail
+ ;
| param_l param ';'
{
- $$ = $1;
- TAILQ_INSERT_TAIL($$, $2, tq);
+ if (!special_param($2, scanner)) {
+ $$ = $1;
+ TAILQ_INSERT_TAIL($$, $2, tq);
+ }
}
| param_l ';'
;
@@ -128,10 +163,12 @@
{
$$ = $1;
TAILQ_CONCAT(&$$->val, $2, tq);
+ $$->flags |= PF_NAMEVAL;
free($2);
}
| error
{
+ yyget_extra(scanner)->error = 1;
}
;
@@ -216,3 +253,52 @@
;
%%
+
+extern int YYLEX_DECL();
+
+extern struct cflex *yyget_extra(void *scanner);
+extern FILE *yyget_in(void *scanner);
+extern int yyget_lineno(void *scanner);
+extern char *yyget_text(void *scanner);
+
+static void
+YYERROR_DECL()
+{
+ if (!yyget_text(scanner))
+ warnx("%s line %d: %s",
+ yyget_extra(scanner)->cfname, yyget_lineno(scanner), s);
+ else if (!yyget_text(scanner)[0])
+ warnx("%s: unexpected EOF",
+ yyget_extra(scanner)->cfname);
+ else
+ warnx("%s line %d: %s: %s",
+ yyget_extra(scanner)->cfname, yyget_lineno(scanner),
+ yyget_text(scanner), s);
+}
+
+/* Handle special parameters (i.e. the include directive).
+ * Return true if the parameter was specially handled.
+ */
+static int
+special_param(struct cfparam *p, void *scanner)
+{
+ if ((p->flags & (PF_VAR | PF_NAMEVAL)) != PF_NAMEVAL
+ || strcmp(p->name, ".include"))
+ return 0;
+ struct cfstring *s;
+ TAILQ_FOREACH(s, &p->val, tq) {
+ if (STAILQ_EMPTY(&s->vars))
+ include_config(s->s, yyget_extra(scanner),
+ yyget_in(scanner) == stdin);
+ else {
+ warnx("%s line %d: "
+ "variables not permitted in '.include' filename",
+ yyget_extra(scanner)->cfname,
+ yyget_lineno(scanner));
+ yyget_extra(scanner)->error = 1;
+ }
+ }
+ free_param_strings(p);
+ free(p);
+ return 1;
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Apr 29, 4:59 PM (18 h, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17843277
Default Alt Text
D40188.id122676.diff (16 KB)
Attached To
Mode
D40188: Add ".include" directive to jail.conf
Attached
Detach File
Event Timeline
Log In to Comment