diff --git a/libexec/rc/rc.d/jail b/libexec/rc/rc.d/jail --- a/libexec/rc/rc.d/jail +++ b/libexec/rc/rc.d/jail @@ -25,6 +25,7 @@ : ${jail_consolecmd:=/usr/bin/login -f root} : ${jail_jexec:=/usr/sbin/jexec} : ${jail_jls:=/usr/sbin/jls} +: ${jail_config_file:="single"} need_dad_wait= @@ -455,7 +456,14 @@ _ALL) command=$jail_program rc_flags=$jail_flags - command_args="-f $jail_conf -c" + if [ "${jail_config_file}" = "single" ]; then + command_args="-f $jail_conf -c" + elif [ "${jail_config_file}" = "multiple" ]; then + command_args="-F -c" + else + echo "jail_config_file must be 'single' or 'multiple'" >&2 + exit 1 + fi if ! checkyesno jail_parallel_start; then command_args="$command_args -p1" fi @@ -485,7 +493,14 @@ eval rc_flags=\${jail_${_jv}_flags:-$jail_flags} eval command=\${jail_${_jv}_program:-$jail_program} - command_args="-i -f $_conf -c $_j" + if [ "${jail_config_file}" = "single" ]; then + command_args="-i -f $_conf -c $_j" + elif [ "${jail_config_file}" = "multiple" ]; then + command_args="-i -F -c $_j" + else + echo "jail_config_file must be 'single' or 'multiple'" >&2 + exit 1 + fi ( _tmp=`mktemp -t jail_${_j}` || exit 3 if $command $rc_flags $command_args \ @@ -513,7 +528,14 @@ eval rc_flags=\${jail_${_jv}_flags:-$jail_flags} eval command=\${jail_${_jv}_program:-$jail_program} - command_args="-i -f $_conf -c $_j" + if [ "${jail_config_file}" = "single" ]; then + command_args="-i -f $_conf -c $_j" + elif [ "${jail_config_file}" = "multiple" ]; then + command_args="-i -F -c $_j" + else + echo "jail_config_file must be 'single' or 'multiple'" >&2 + exit 1 + fi _tmp=`mktemp -t jail` || exit 3 if $command $rc_flags $command_args \ >> $_tmp 2>&1 &2 + exit 1 + fi if checkyesno jail_reverse_stop; then $jail_jls name | tail -r else @@ -574,7 +603,14 @@ eval command=\${jail_${_jv}_program:-$jail_program} echo -n " ${_hostname:-${_j}}" _tmp=`mktemp -t jail` || exit 3 - $command -q -f $_conf -r $_j >> $_tmp 2>&1 + if [ "${jail_config_file}" = "single" ]; then + $command -q -f $_conf -r $_j >> $_tmp 2>&1 + elif [ "${jail_config_file}" = "multiple" ]; then + $command -q -F -r $_j >> $_tmp 2>&1 + else + echo "jail_config_file must be 'single' or 'multiple'" >&2 + exit 1 + fi if $jail_jls -j $_j > /dev/null 2>&1; then cat $_tmp else 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 @@ -32,12 +32,14 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -123,11 +125,25 @@ [KP_VNET] = {"vnet", 0}, }; +static const char *conf_files[] = { + "/etc/jail.conf", + "/etc/jail.conf.d/*.conf", + "/etc/jail.*.conf" +}; + +static void +check_glob_err(int rc) { + if (rc == GLOB_NOSPACE) + err(1, "Failed to allocate memory for glob!"); + else if (rc == GLOB_ABORTED) + err(1, "Error encountered parsing glob!"); +} + /* * Parse the jail configuration file. */ void -load_config(void) +load_config(int op) { struct cfjails wild; struct cfparams opp; @@ -135,19 +151,52 @@ struct cfparam *p, *vp, *tp; struct cfstring *s, *vs, *ns; struct cfvar *v, *vv; + struct stat st = {0}; + const char *mycfname = cfname; + glob_t g = {0}; 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); + size_t si; + int did_self, jseq, pgen, rc; + + if (op & JF_CONF_ALL) { + si = sizeof(conf_files) / sizeof(conf_files[0]); + for (size_t i = 0; i < si; i++) { + rc = glob(conf_files[i], GLOB_APPEND, NULL, &g); + check_glob_err(rc); + } + for (size_t i = 0; i < g.gl_pathc; i++) { + cfname = g.gl_pathv[i]; + yyin = fopen(cfname, "r"); + if (!yyin) + err(1, "%s", cfname); + if (yyparse() || yynerrs) { + fclose(yyin); + exit(1); + } + fclose(yyin); + } + } + cfname = mycfname; + if (cfname != NULL) { + if (strcmp(cfname, "-")) { + if (stat(cfname, &st) != 0) + err(1, "No such file %s!", cfname); + yyin = fopen(cfname, "r"); + if (!yyin) + err(1, "%s", cfname); + if (yyparse() || yynerrs) { + fclose(yyin); + exit(1); + } + fclose(yyin); + } else { + cfname = "STDIN"; + yyin = stdin; + if (yyparse() || yynerrs) { + exit(1); + } + } } - if (yyparse() || yynerrs) - exit(1); /* Separate the wildcard jails out from the actual jails. */ jseq = 0; diff --git a/usr.sbin/jail/jail.8 b/usr.sbin/jail/jail.8 --- a/usr.sbin/jail/jail.8 +++ b/usr.sbin/jail/jail.8 @@ -41,13 +41,13 @@ .Ar param Ns = Ns Ar value ... .Op Cm command Ns = Ns Ar command ... .Nm -.Op Fl dqv +.Op Fl dqvF .Op Fl f Ar conf_file .Op Fl p Ar limit .Op Fl cmr .Op Ar jail .Nm -.Op Fl qv +.Op Fl qvF .Op Fl f Ar conf_file .Op Fl rR .Op Cm * | Ar jail ... @@ -62,6 +62,7 @@ .Ar command ... .Nm .Op Fl f Ar conf_file +.Op Fl F .Fl e .Ar separator .Sh DESCRIPTION @@ -146,6 +147,11 @@ .Ar conf_file instead of the default .Pa /etc/jail.conf . +.It Fl F +Parse all configuration files, namely /etc/jail.conf, +/etc/jail.conf.d/.conf and /etc/jail..conf, in that order. If +.Fl f Ar conf_file +is used, it will be appended to the list of files to be parsed. .It Fl h Resolve the .Va host.hostname @@ -1377,6 +1383,15 @@ .Va path . This is by virtue of the child jail being created in the chrooted environment of the first jail. +.El +.Sh FILES +.Bl -tag -width indent -compact +.It Pa /etc/jail.conf +Main configuration file. +.It Pa /etc/jail.conf.d +Directory with jail configuration files. It is usually used as jail per file. +.It Pa /etc/jail..conf +Jail per file configuration. .Sh SEE ALSO .Xr killall 1 , .Xr lsvfs 1 , 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 @@ -134,7 +134,6 @@ int main(int argc, char **argv) { - struct stat st; FILE *jfp; struct cfjail *j; char *JidFile; @@ -152,10 +151,10 @@ op = 0; dflag = Rflag = 0; docf = 1; - cfname = CONF_FILE; + cfname = NULL; JidFile = NULL; - while ((ch = getopt(argc, argv, "cde:f:hiJ:lmn:p:qrRs:u:U:v")) != -1) { + while ((ch = getopt(argc, argv, "cde:f:FhiJ:lmn:p:qrRs:u:U:v")) != -1) { switch (ch) { case 'c': op |= JF_START; @@ -170,6 +169,9 @@ case 'f': cfname = optarg; break; + case 'F': + op |= JF_CONF_ALL; + break; case 'h': #if defined(INET) || defined(INET6) add_param(NULL, NULL, IP_IP_HOSTNAME, NULL); @@ -287,20 +289,20 @@ } 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(op); show_jails(); exit(0); } /* Jail remove, perhaps using the config file */ if (!docf || argc == 0) usage(); - if (!Rflag) + docf = Rflag == 0 ? 1 : 0; + if (docf) { for (i = 0; i < argc; i++) if (strchr(argv[i], '=')) usage(); - if ((docf = !Rflag && - (!strcmp(cfname, "-") || stat(cfname, &st) == 0))) - load_config(); + load_config(op); + } 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 +350,7 @@ /* From the config file, perhaps with a specified jail */ if (Rflag || !docf) usage(); - load_config(); + load_config(op); } /* Find out which jails will be run. */ @@ -1054,11 +1056,11 @@ (void)fprintf(stderr, "usage: jail [-dhilqv] [-J jid_file] [-u username] [-U username]\n" " -[cmr] param=value ... [command=command ...]\n" - " jail [-dqv] [-f file] -[cmr] [jail]\n" - " jail [-qv] [-f file] -[rR] ['*' | jail ...]\n" + " jail [-dqvF] [-f file] -[cmr] [jail]\n" + " jail [-qvF] [-f file] -[rR] ['*' | jail ...]\n" " jail [-dhilqv] [-J jid_file] [-u username] [-U username]\n" " [-n jailname] [-s securelevel]\n" " path hostname ip[,...] command ...\n" - " jail [-f file] -e separator\n"); + " jail [-f file] [-F] -e separator\n"); exit(1); } 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 @@ -36,8 +36,6 @@ #include -#define CONF_FILE "/etc/jail.conf" - #define DEP_FROM 0 #define DEP_TO 1 @@ -68,6 +66,7 @@ #define JF_SLEEPQ 0x0400 /* Waiting on a command and/or timeout */ #define JF_FROM_RUNQ 0x0800 /* Has already been on the run queue */ #define JF_SHOW 0x1000 /* -e Exhibit list of configured jails */ +#define JF_CONF_ALL 0x2000 /* jail.conf, jail.conf.d and jail..conf */ #define JF_OP_MASK (JF_START | JF_SET | JF_STOP) #define JF_RESTART (JF_START | JF_STOP) @@ -208,7 +207,7 @@ extern int finish_command(struct cfjail *j); extern struct cfjail *next_proc(int nonblock); -extern void load_config(void); +extern void load_config(int op); extern struct cfjail *add_jail(void); extern void add_param(struct cfjail *j, const struct cfparam *p, enum intparam ipnum, const char *value);