diff --git a/doc/configuration.txt b/doc/configuration.txt index 71a91cf2e..7f369da34 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -538,9 +538,12 @@ The following keywords are supported in the "global" section : - nbproc - node - pidfile + - presetenv + - resetenv - uid - ulimit-n - user + - setenv - stats - ssl-default-bind-ciphers - ssl-default-bind-options @@ -549,6 +552,7 @@ The following keywords are supported in the "global" section : - ssl-dh-param-file - ssl-server-verify - unix-bind + - unsetenv - 51degrees-data-file - 51degrees-property-name-list - 51degrees-property-separator @@ -778,6 +782,22 @@ pidfile the "-p" command line argument. The file must be accessible to the user starting the process. See also "daemon". +presetenv + Sets environment variable to value . If the variable exists, it + is NOT overwritten. The changes immediately take effect so that the next line + in the configuration file sees the new value. See also "setenv", "resetenv", + and "unsetenv". + +resetenv [ ...] + Removes all environment variables except the ones specified in argument. It + allows to use a clean controlled environment before setting new values with + setenv or unsetenv. Please note that some internal functions may make use of + some environment variables, such as time manipulation functions, but also + OpenSSL or even external checks. This must be used with extreme care and only + after complete validation. The changes immediately take effect so that the + next line in the configuration file sees the new environment. See also + "setenv", "presetenv", and "unsetenv". + stats bind-process [ all | odd | even | [-] ] ... Limits the stats socket to a certain set of processes numbers. By default the stats socket is bound to all processes, causing a warning to be emitted when @@ -806,6 +826,12 @@ server-state-file configuration. See also "server-state-base" and "show servers state", "load-server-state-from-file" and "server-state-file-name" +setenv + Sets environment variable to value . If the variable exists, it + is overwritten. The changes immediately take effect so that the next line in + the configuration file sees the new value. See also "presetenv", "resetenv", + and "unsetenv". + ssl-default-bind-ciphers This setting is only available when support for OpenSSL was built in. It sets the default string describing the list of cipher algorithms ("cipher suite") @@ -901,6 +927,15 @@ unix-bind [ prefix ] [ mode ] [ user ] [ uid ] both are specified, the "bind" statement has priority, meaning that the "unix-bind" settings may be seen as process-wide default settings. +unsetenv [ ...] + Removes environment variables specified in arguments. This can be useful to + hide some sensitive information that are occasionally inherited from the + user's environment during some operations. Variables which did not exist are + silently ignored so that after the operation, it is certain that none of + these variables remain. The changes immediately take effect so that the next + line in the configuration file will not see these variables. See also + "setenv", "presetenv", and "resetenv". + user Similar to "uid" but uses the UID of user name from /etc/passwd. See also "uid" and "group". diff --git a/src/cfgparse.c b/src/cfgparse.c index 68cee2629..d44f57a43 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -1826,6 +1826,78 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) goto out; #endif } + else if (strcmp(args[0], "setenv") == 0 || strcmp(args[0], "presetenv") == 0) { + if (alertif_too_many_args(3, file, linenum, args, &err_code)) + goto out; + + if (*(args[2]) == 0) { + Alert("parsing [%s:%d]: '%s' expects a name and a value.\n", file, linenum, args[0]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + /* "setenv" overwrites, "presetenv" only sets if not yet set */ + if (setenv(args[1], args[2], (args[0][0] == 's')) != 0) { + Alert("parsing [%s:%d]: '%s' failed on variable '%s' : %s.\n", file, linenum, args[0], args[1], strerror(errno)); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + } + else if (!strcmp(args[0], "unsetenv")) { + int arg; + + if (*(args[1]) == 0) { + Alert("parsing [%s:%d]: '%s' expects at least one variable name.\n", file, linenum, args[0]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + for (arg = 1; *args[arg]; arg++) { + if (unsetenv(args[arg]) != 0) { + Alert("parsing [%s:%d]: '%s' failed on variable '%s' : %s.\n", file, linenum, args[0], args[arg], strerror(errno)); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + } + } + else if (!strcmp(args[0], "resetenv")) { + extern char **environ; + char **env = environ; + + /* args contain variable names to keep, one per argument */ + while (*env) { + int arg; + + /* look for current variable in among all those we want to keep */ + for (arg = 1; *args[arg]; arg++) { + if (strncmp(*env, args[arg], strlen(args[arg])) == 0 && + (*env)[strlen(args[arg])] == '=') + break; + } + + /* delete this variable */ + if (!*args[arg]) { + char *delim = strchr(*env, '='); + + if (!delim || delim - *env >= trash.size) { + Alert("parsing [%s:%d]: '%s' failed to unset invalid variable '%s'.\n", file, linenum, args[0], *env); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + memcpy(trash.str, *env, delim - *env); + trash.str[delim - *env] = 0; + + if (unsetenv(trash.str) != 0) { + Alert("parsing [%s:%d]: '%s' failed to unset variable '%s' : %s.\n", file, linenum, args[0], *env, strerror(errno)); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + } + else + env++; + } + } else { struct cfg_kw_list *kwl; int index;