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
mail_conf_checkdir(const char * config_dir)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
mail_conf_read(void)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
mail_conf_suck(void)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
mail_conf_flush(void)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
mail_conf_eval(const char * string)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
mail_conf_eval_once(const char * string)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
mail_conf_lookup(const char * name)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
mail_conf_lookup_eval(const char * name)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
mail_conf_update(const char * key,const char * value)277 void mail_conf_update(const char *key, const char *value)
278 {
279 dict_update(CONFIG_DICT, key, value);
280 }
281