1 /* $NetBSD: mail_conf.c,v 1.3 2020/03/18 19:05:16 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* mail_conf 3 6 /* SUMMARY 7 /* global configuration parameter management 8 /* SYNOPSIS 9 /* #include <mail_conf.h> 10 /* 11 /* void mail_conf_read() 12 /* 13 /* void mail_conf_suck() 14 /* 15 /* void mail_conf_flush() 16 /* 17 /* void mail_conf_checkdir(config_dir) 18 /* const char *config_dir; 19 /* 20 /* void mail_conf_update(name, value) 21 /* const char *name; 22 /* const char *value; 23 /* 24 /* const char *mail_conf_lookup(name) 25 /* const char *name; 26 /* 27 /* const char *mail_conf_eval(string) 28 /* const char *string; 29 /* 30 /* const char *mail_conf_eval_once(string) 31 /* const char *string; 32 /* 33 /* const char *mail_conf_lookup_eval(name) 34 /* const char *name; 35 /* DESCRIPTION 36 /* mail_conf_suck() reads the global Postfix configuration 37 /* file, and stores its values into a global configuration 38 /* dictionary. When the configuration directory name is not 39 /* trusted, this function requires that the directory name is 40 /* authorized with the alternate_config_directories setting 41 /* in the default main.cf file. 42 /* 43 /* This function requires that all configuration directory 44 /* override mechanisms set the MAIL_CONFIG environment variable, 45 /* even if the override was specified via the command line. 46 /* This reduces the number of pathways that need to be checked 47 /* for possible security attacks. 48 /* 49 /* mail_conf_read() invokes mail_conf_suck() and assigns the values 50 /* to global variables by calling mail_params_init(). 51 /* 52 /* mail_conf_flush() discards the global configuration dictionary. 53 /* This is needed in programs that read main.cf multiple times, to 54 /* ensure that deleted parameter settings are handled properly. 55 /* 56 /* mail_conf_checkdir() verifies that configuration directory 57 /* is authorized through settings in the default main.cf file, 58 /* and terminates the program if it is not. 59 /* 60 /* The following routines are wrappers around the generic dictionary 61 /* access routines. 62 /* 63 /* mail_conf_update() updates the named global parameter. This has 64 /* no effect on parameters whose value has already been looked up. 65 /* The update succeeds or the program terminates with fatal error. 66 /* 67 /* mail_conf_lookup() looks up the value of the named parameter. 68 /* A null pointer result means the parameter was not found. 69 /* The result is volatile and should be copied if it is to be 70 /* used for any appreciable amount of time. 71 /* 72 /* mail_conf_eval() recursively expands any $parameters in the 73 /* string argument. The result is volatile and should be copied 74 /* if it is to be used for any appreciable amount of time. 75 /* 76 /* mail_conf_eval_once() non-recursively expands any $parameters 77 /* in the string argument. The result is volatile and should 78 /* be copied if it is to be used for any appreciable amount 79 /* of time. 80 /* 81 /* mail_conf_lookup_eval() looks up the named parameter, and expands any 82 /* $parameters in the result. The result is volatile and should be 83 /* copied if it is to be used for any appreciable amount of time. 84 /* DIAGNOSTICS 85 /* Fatal errors: malformed numerical value. 86 /* ENVIRONMENT 87 /* MAIL_CONFIG, non-default configuration database 88 /* MAIL_VERBOSE, enable verbose mode 89 /* FILES 90 /* /etc/postfix: default Postfix configuration directory. 91 /* SEE ALSO 92 /* dict(3) generic dictionary manager 93 /* mail_conf_int(3) integer-valued parameters 94 /* mail_conf_str(3) string-valued parameters 95 /* LICENSE 96 /* .ad 97 /* .fi 98 /* The Secure Mailer license must be distributed with this software. 99 /* AUTHOR(S) 100 /* Wietse Venema 101 /* IBM T.J. Watson Research 102 /* P.O. Box 704 103 /* Yorktown Heights, NY 10598, USA 104 /* 105 /* Wietse Venema 106 /* Google, Inc. 107 /* 111 8th Avenue 108 /* New York, NY 10011, USA 109 /*--*/ 110 111 /* System library. */ 112 113 #include <sys_defs.h> 114 #include <unistd.h> 115 #include <stdlib.h> 116 #include <string.h> 117 118 /* Utility library. */ 119 120 #include <msg.h> 121 #include <mymalloc.h> 122 #include <vstream.h> 123 #include <vstring.h> 124 #include <dict.h> 125 #include <safe.h> 126 #include <stringops.h> 127 #include <readlline.h> 128 129 /* Global library. */ 130 131 #include "mail_params.h" 132 #include "mail_conf.h" 133 134 /* mail_conf_checkdir - authorize non-default directory */ 135 136 void mail_conf_checkdir(const char *config_dir) 137 { 138 VSTRING *buf; 139 VSTREAM *fp; 140 char *path; 141 char *name; 142 char *value; 143 char *cp; 144 int found = 0; 145 146 /* 147 * If running set-[ug]id, require that a non-default configuration 148 * directory name is blessed as a bona fide configuration directory in 149 * the default main.cf file. 150 */ 151 path = concatenate(DEF_CONFIG_DIR, "/", "main.cf", (char *) 0); 152 if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0) 153 msg_fatal("open file %s: %m", path); 154 155 buf = vstring_alloc(1); 156 while (found == 0 && readlline(buf, fp, (int *) 0)) { 157 if (split_nameval(vstring_str(buf), &name, &value) == 0 158 && (strcmp(name, VAR_CONFIG_DIRS) == 0 159 || strcmp(name, VAR_MULTI_CONF_DIRS) == 0)) { 160 while (found == 0 && (cp = mystrtok(&value, CHARS_COMMA_SP)) != 0) 161 if (strcmp(cp, config_dir) == 0) 162 found = 1; 163 } 164 } 165 if (vstream_fclose(fp)) 166 msg_fatal("read file %s: %m", path); 167 vstring_free(buf); 168 169 if (found == 0) { 170 msg_error("unauthorized configuration directory name: %s", config_dir); 171 msg_fatal("specify \"%s = %s\" or \"%s = %s\" in %s", 172 VAR_CONFIG_DIRS, config_dir, 173 VAR_MULTI_CONF_DIRS, config_dir, path); 174 } 175 myfree(path); 176 } 177 178 /* mail_conf_read - read global configuration file */ 179 180 void mail_conf_read(void) 181 { 182 mail_conf_suck(); 183 mail_params_init(); 184 } 185 186 /* mail_conf_suck - suck in the global configuration file */ 187 188 void mail_conf_suck(void) 189 { 190 char *config_dir; 191 char *path; 192 193 /* 194 * The code below requires that all configuration directory override 195 * mechanisms set the CONF_ENV_PATH environment variable, even if the 196 * override was specified via the command line. This reduces the number 197 * of pathways that need to be checked for possible security attacks. 198 * 199 * Note: this code necessarily runs before cleanenv() can enforce the 200 * import_environment scrubbing policy. 201 */ 202 203 /* 204 * Permit references to unknown configuration variable names. We rely on 205 * a separate configuration checking tool to spot misspelled names and 206 * other kinds of trouble. Enter the configuration directory into the 207 * default dictionary. 208 */ 209 if (var_config_dir) 210 myfree(var_config_dir); 211 if ((config_dir = getenv(CONF_ENV_PATH)) == 0) 212 config_dir = DEF_CONFIG_DIR; 213 var_config_dir = mystrdup(config_dir); 214 set_mail_conf_str(VAR_CONFIG_DIR, var_config_dir); 215 216 /* 217 * If the configuration directory name comes from an untrusted source, 218 * require that it is listed in the default main.cf file. 219 */ 220 if (strcmp(var_config_dir, DEF_CONFIG_DIR) != 0 /* non-default */ 221 && unsafe()) /* untrusted env and cli */ 222 mail_conf_checkdir(var_config_dir); 223 path = concatenate(var_config_dir, "/", "main.cf", (char *) 0); 224 if (dict_load_file_xt(CONFIG_DICT, path) == 0) 225 msg_fatal("open %s: %m", path); 226 myfree(path); 227 } 228 229 /* mail_conf_flush - discard configuration dictionary */ 230 231 void mail_conf_flush(void) 232 { 233 if (dict_handle(CONFIG_DICT) != 0) 234 dict_unregister(CONFIG_DICT); 235 } 236 237 /* mail_conf_eval - expand macros in string */ 238 239 const char *mail_conf_eval(const char *string) 240 { 241 #define RECURSIVE 1 242 243 return (dict_eval(CONFIG_DICT, string, RECURSIVE)); 244 } 245 246 /* mail_conf_eval_once - expand one level of macros in string */ 247 248 const char *mail_conf_eval_once(const char *string) 249 { 250 #define NONRECURSIVE 0 251 252 return (dict_eval(CONFIG_DICT, string, NONRECURSIVE)); 253 } 254 255 /* mail_conf_lookup - lookup named variable */ 256 257 const char *mail_conf_lookup(const char *name) 258 { 259 return (dict_lookup(CONFIG_DICT, name)); 260 } 261 262 /* mail_conf_lookup_eval - expand named variable */ 263 264 const char *mail_conf_lookup_eval(const char *name) 265 { 266 const char *value; 267 268 #define RECURSIVE 1 269 270 if ((value = dict_lookup(CONFIG_DICT, name)) != 0) 271 value = dict_eval(CONFIG_DICT, value, RECURSIVE); 272 return (value); 273 } 274 275 /* mail_conf_update - update parameter */ 276 277 void mail_conf_update(const char *key, const char *value) 278 { 279 dict_update(CONFIG_DICT, key, value); 280 } 281