diff --git a/changes-entries/mod_env_setenvfromfile.txt b/changes-entries/mod_env_setenvfromfile.txt new file mode 100644 index 00000000000..2ed101b7b25 --- /dev/null +++ b/changes-entries/mod_env_setenvfromfile.txt @@ -0,0 +1,3 @@ + *) mod_env: Add the SetEnvFromFile directive to set internal environment + variables from a file of name=value lines, read at configuration time. + [Cornel Isbiceanu ] diff --git a/docs/manual/mod/mod_env.xml b/docs/manual/mod/mod_env.xml index 73062037bb7..08263ecaaf5 100644 --- a/docs/manual/mod/mod_env.xml +++ b/docs/manual/mod/mod_env.xml @@ -118,5 +118,69 @@ SSI pages - + +SetEnvFromFile +Sets environment variables from a file +SetEnvFromFile file-path +server configvirtual host +directory +Available in version 2.4.70 and later. + + +

Sets internal environment variables read from a file, which are then + available to Apache HTTP Server modules, and passed on to CGI scripts and + SSI pages. This is equivalent to a series of SetEnv directives, one per variable, but keeps + the values in a separate file.

+ +

The file-path is either an absolute path or a path relative + to the ServerRoot. The file is read + once when the configuration is parsed; changes to it take effect only after + the server is restarted.

+ +

Each line of the file has the form name=value. Blank lines + and lines beginning with # are ignored, and leading and + trailing whitespace is stripped. If a line contains no =, the + variable is set to an empty string. A line ending in a backslash + (\) is continued on the following line, just as in the main + configuration files.

+ + Example + +SetEnvFromFile "conf/app.env" + + + + Example file (<code>conf/app.env</code>) + +# Application settings +APP_MODE=production +SPECIAL_PATH=/foo/bin + + + +

As with SetEnv, the + variables are set after most early request processing directives + are run, such as access control and URI-to-filename mapping.

+
+ + Security +

Unlike SetEnv, this directive + reads the contents of a file into the internal environment, where + they may be exposed through CGI, SSI, logging and other consumers. To + prevent an untrusted author from disclosing the contents of any file + readable by the server (for example configuration or credential files + elsewhere on the host), SetEnvFromFile is + not permitted in .htaccess files; it may only + be used in the main server configuration.

+
+
+ +Environment Variables + +SetEnv + +
+ + diff --git a/modules/metadata/mod_env.c b/modules/metadata/mod_env.c index 52594e9cf20..a7e13f37605 100644 --- a/modules/metadata/mod_env.c +++ b/modules/metadata/mod_env.c @@ -146,6 +146,59 @@ static const char *add_env_module_vars_unset(cmd_parms *cmd, void *sconf_, return NULL; } +static const char *add_env_module_vars_from_file(cmd_parms *cmd, void *sconf_, + const char *arg) +{ + env_dir_config_rec *sconf = sconf_; + const char *fname; + ap_configfile_t *file; + apr_status_t rv; + char line[MAX_STRING_LEN]; + + fname = ap_server_root_relative(cmd->temp_pool, arg); + if (!fname) { + return apr_pstrcat(cmd->pool, cmd->cmd->name, + ": Invalid file path ", arg, NULL); + } + + rv = ap_pcfg_openfile(&file, cmd->temp_pool, fname); + if (rv != APR_SUCCESS) { + return apr_psprintf(cmd->pool, "%s: Could not open file %s: %pm", + cmd->cmd->name, fname, &rv); + } + + /* Each line is "name=value"; blank lines and '#' comments are ignored. + * ap_cfg_getline() strips surrounding whitespace and handles line + * continuations. Names are read at config time and stored in the same + * table used by SetEnv, so they merge and reach r->subprocess_env the + * same way. + */ + while (!ap_cfg_getline(line, sizeof(line), file)) { + const char *rest = line; + const char *name, *value; + + if (line[0] == '#' || line[0] == '\0') { + continue; + } + + name = ap_getword(cmd->pool, &rest, '='); + if (!name[0]) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, + APLOGNO(10632) "%s: Skipping malformed line " + "(no variable name) in %s", cmd->cmd->name, fname); + continue; + } + + /* rest points just past the '='; no '=' means an empty value. */ + value = apr_pstrdup(cmd->pool, rest); + apr_table_setn(sconf->vars, name, value); + } + + ap_cfg_closefile(file); + + return NULL; +} + static const command_rec env_module_cmds[] = { AP_INIT_ITERATE("PassEnv", add_env_module_vars_passed, NULL, @@ -154,6 +207,9 @@ AP_INIT_TAKE12("SetEnv", add_env_module_vars_set, NULL, OR_FILEINFO, "an environment variable name and optional value to pass to CGI."), AP_INIT_ITERATE("UnsetEnv", add_env_module_vars_unset, NULL, OR_FILEINFO, "a list of variables to remove from the CGI environment."), +AP_INIT_TAKE1("SetEnvFromFile", add_env_module_vars_from_file, NULL, + RSRC_CONF | ACCESS_CONF, + "the path to a file of name=value lines to pass to CGI."), {NULL}, }; diff --git a/test/modules/metadata/test_002_setenvfromfile.py b/test/modules/metadata/test_002_setenvfromfile.py index 4b37be16a33..621f4dbdcac 100644 --- a/test/modules/metadata/test_002_setenvfromfile.py +++ b/test/modules/metadata/test_002_setenvfromfile.py @@ -5,7 +5,8 @@ from pyhttpd.backport import skip_not_backported from pyhttpd.conf import HttpdConf -pytestmark = skip_not_backported("r1938506", "SetEnvFromFile") +pytestmark = skip_not_backported("r1938506", "SetEnvFromFile", + backported_in="2.4.70") def _write_ssi_echo(path, names):