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 136void 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 180void 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 188void 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 231void 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 239const 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 248const 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 257const 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 264const 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 277void mail_conf_update(const char *key, const char *value) 278{ 279 dict_update(CONFIG_DICT, key, value); 280} 281