xref: /netbsd-src/external/ibm-public/postfix/dist/src/global/mail_conf.c (revision 33881f779a77dce6440bdc44610d94de75bebefe)
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