1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "apr.h" 18#include "apr_strings.h" 19 20#if APR_HAVE_STDLIB_H 21#include <stdlib.h> 22#endif 23 24#include "ap_config.h" 25#include "httpd.h" 26#include "http_config.h" 27#include "http_request.h" 28#include "http_log.h" 29 30typedef struct { 31 apr_table_t *vars; 32 apr_table_t *unsetenv; 33} env_dir_config_rec; 34 35module AP_MODULE_DECLARE_DATA env_module; 36 37static void *create_env_dir_config(apr_pool_t *p, char *dummy) 38{ 39 env_dir_config_rec *conf = apr_palloc(p, sizeof(*conf)); 40 41 conf->vars = apr_table_make(p, 10); 42 conf->unsetenv = apr_table_make(p, 10); 43 44 return conf; 45} 46 47static void *merge_env_dir_configs(apr_pool_t *p, void *basev, void *addv) 48{ 49 env_dir_config_rec *base = basev; 50 env_dir_config_rec *add = addv; 51 env_dir_config_rec *res = apr_palloc(p, sizeof(*res)); 52 53 const apr_table_entry_t *elts; 54 const apr_array_header_t *arr; 55 56 int i; 57 58 /* 59 * res->vars = copy_table( p, base->vars ); 60 * foreach $unsetenv ( @add->unsetenv ) 61 * table_unset( res->vars, $unsetenv ); 62 * foreach $element ( @add->vars ) 63 * table_set( res->vars, $element.key, $element.val ); 64 * 65 * add->unsetenv already removed the vars from add->vars, 66 * if they preceeded the UnsetEnv directive. 67 */ 68 res->vars = apr_table_copy(p, base->vars); 69 res->unsetenv = NULL; 70 71 arr = apr_table_elts(add->unsetenv); 72 if (arr) { 73 elts = (const apr_table_entry_t *)arr->elts; 74 75 for (i = 0; i < arr->nelts; ++i) { 76 apr_table_unset(res->vars, elts[i].key); 77 } 78 } 79 80 arr = apr_table_elts(add->vars); 81 if (arr) { 82 elts = (const apr_table_entry_t *)arr->elts; 83 84 for (i = 0; i < arr->nelts; ++i) { 85 apr_table_setn(res->vars, elts[i].key, elts[i].val); 86 } 87 } 88 89 return res; 90} 91 92static const char *add_env_module_vars_passed(cmd_parms *cmd, void *sconf_, 93 const char *arg) 94{ 95 env_dir_config_rec *sconf = sconf_; 96 apr_table_t *vars = sconf->vars; 97 const char *env_var; 98 99 env_var = getenv(arg); 100 if (env_var != NULL) { 101 apr_table_setn(vars, arg, apr_pstrdup(cmd->pool, env_var)); 102 } 103 else { 104 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(01506) 105 "PassEnv variable %s was undefined", arg); 106 } 107 108 return NULL; 109} 110 111static const char *add_env_module_vars_set(cmd_parms *cmd, void *sconf_, 112 const char *name, const char *value) 113{ 114 env_dir_config_rec *sconf = sconf_; 115 116 /* name is mandatory, value is optional. no value means 117 * set the variable to an empty string 118 */ 119 apr_table_setn(sconf->vars, name, value ? value : ""); 120 121 return NULL; 122} 123 124static const char *add_env_module_vars_unset(cmd_parms *cmd, void *sconf_, 125 const char *arg) 126{ 127 env_dir_config_rec *sconf = sconf_; 128 129 /* Always UnsetEnv FOO in the same context as {Set,Pass}Env FOO 130 * only if this UnsetEnv follows the {Set,Pass}Env. The merge 131 * will only apply unsetenv to the parent env (main server). 132 */ 133 apr_table_set(sconf->unsetenv, arg, NULL); 134 apr_table_unset(sconf->vars, arg); 135 136 return NULL; 137} 138 139static const command_rec env_module_cmds[] = 140{ 141AP_INIT_ITERATE("PassEnv", add_env_module_vars_passed, NULL, 142 OR_FILEINFO, "a list of environment variables to pass to CGI."), 143AP_INIT_TAKE12("SetEnv", add_env_module_vars_set, NULL, 144 OR_FILEINFO, "an environment variable name and optional value to pass to CGI."), 145AP_INIT_ITERATE("UnsetEnv", add_env_module_vars_unset, NULL, 146 OR_FILEINFO, "a list of variables to remove from the CGI environment."), 147 {NULL}, 148}; 149 150static int fixup_env_module(request_rec *r) 151{ 152 env_dir_config_rec *sconf = ap_get_module_config(r->per_dir_config, 153 &env_module); 154 155 if (apr_is_empty_table(sconf->vars)) { 156 return DECLINED; 157 } 158 159 r->subprocess_env = apr_table_overlay(r->pool, r->subprocess_env, 160 sconf->vars); 161 162 return OK; 163} 164 165static void register_hooks(apr_pool_t *p) 166{ 167 ap_hook_fixups(fixup_env_module, NULL, NULL, APR_HOOK_MIDDLE); 168} 169 170AP_DECLARE_MODULE(env) = 171{ 172 STANDARD20_MODULE_STUFF, 173 create_env_dir_config, /* dir config creater */ 174 merge_env_dir_configs, /* dir merger --- default is to override */ 175 NULL, /* server config */ 176 NULL, /* merge server configs */ 177 env_module_cmds, /* command apr_table_t */ 178 register_hooks /* register hooks */ 179}; 180