xref: /openbsd-src/usr.sbin/smtpd/config.c (revision ed9a50d3bb49a44ad441943db2e0746b2d138d31)
1 /*	$OpenBSD: config.c,v 1.58 2024/01/04 09:30:09 op Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/resource.h>
20 
21 #include <ifaddrs.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include "smtpd.h"
26 #include "log.h"
27 #include "ssl.h"
28 
29 void		 set_local(struct smtpd *, const char *);
30 void		 set_localaddrs(struct smtpd *, struct table *);
31 
32 struct smtpd *
config_default(void)33 config_default(void)
34 {
35 	struct smtpd	       *conf = NULL;
36 	struct mta_limits      *limits = NULL;
37 	struct table	       *t = NULL;
38 	char			hostname[HOST_NAME_MAX+1];
39 
40 	if (getmailname(hostname, sizeof hostname) == -1)
41 		return NULL;
42 
43 	if ((conf = calloc(1, sizeof(*conf))) == NULL)
44 		return conf;
45 
46 	(void)strlcpy(conf->sc_hostname, hostname, sizeof(conf->sc_hostname));
47 
48 	conf->sc_maxsize = DEFAULT_MAX_BODY_SIZE;
49 	conf->sc_subaddressing_delim = SUBADDRESSING_DELIMITER;
50 	conf->sc_ttl = SMTPD_QUEUE_EXPIRY;
51 	conf->sc_srs_ttl = SMTPD_QUEUE_EXPIRY / 86400;
52 
53 	conf->sc_mta_max_deferred = 100;
54 	conf->sc_scheduler_max_inflight = 5000;
55 	conf->sc_scheduler_max_schedule = 10;
56 	conf->sc_scheduler_max_evp_batch_size = 256;
57 	conf->sc_scheduler_max_msg_batch_size = 1024;
58 
59 	conf->sc_session_max_rcpt = 1000;
60 	conf->sc_session_max_mails = 100;
61 
62 	conf->sc_mda_max_session = 50;
63 	conf->sc_mda_max_user_session = 7;
64 	conf->sc_mda_task_hiwat = 50;
65 	conf->sc_mda_task_lowat = 30;
66 	conf->sc_mda_task_release = 10;
67 
68 	/* Report mails delayed for more than 4 hours */
69 	conf->sc_bounce_warn[0] = 3600 * 4;
70 
71 	conf->sc_tables_dict = calloc(1, sizeof(*conf->sc_tables_dict));
72 	conf->sc_rules = calloc(1, sizeof(*conf->sc_rules));
73 	conf->sc_dispatchers = calloc(1, sizeof(*conf->sc_dispatchers));
74 	conf->sc_listeners = calloc(1, sizeof(*conf->sc_listeners));
75 	conf->sc_ca_dict = calloc(1, sizeof(*conf->sc_ca_dict));
76 	conf->sc_pki_dict = calloc(1, sizeof(*conf->sc_pki_dict));
77 	conf->sc_ssl_dict = calloc(1, sizeof(*conf->sc_ssl_dict));
78 	conf->sc_limits_dict = calloc(1, sizeof(*conf->sc_limits_dict));
79 	conf->sc_mda_wrappers = calloc(1, sizeof(*conf->sc_mda_wrappers));
80 	conf->sc_filter_processes_dict = calloc(1, sizeof(*conf->sc_filter_processes_dict));
81 	conf->sc_dispatcher_bounce = calloc(1, sizeof(*conf->sc_dispatcher_bounce));
82 	conf->sc_filters_dict = calloc(1, sizeof(*conf->sc_filters_dict));
83 	limits = calloc(1, sizeof(*limits));
84 
85 	if (conf->sc_tables_dict == NULL	||
86 	    conf->sc_rules == NULL		||
87 	    conf->sc_dispatchers == NULL	||
88 	    conf->sc_listeners == NULL		||
89 	    conf->sc_ca_dict == NULL		||
90 	    conf->sc_pki_dict == NULL		||
91 	    conf->sc_ssl_dict == NULL		||
92 	    conf->sc_limits_dict == NULL        ||
93 	    conf->sc_mda_wrappers == NULL	||
94 	    conf->sc_filter_processes_dict == NULL	||
95 	    conf->sc_dispatcher_bounce == NULL	||
96 	    conf->sc_filters_dict == NULL	||
97 	    limits == NULL)
98 		goto error;
99 
100 	dict_init(conf->sc_dispatchers);
101 	dict_init(conf->sc_mda_wrappers);
102 	dict_init(conf->sc_ca_dict);
103 	dict_init(conf->sc_pki_dict);
104 	dict_init(conf->sc_ssl_dict);
105 	dict_init(conf->sc_tables_dict);
106 	dict_init(conf->sc_limits_dict);
107 	dict_init(conf->sc_filter_processes_dict);
108 
109 	limit_mta_set_defaults(limits);
110 
111 	dict_xset(conf->sc_limits_dict, "default", limits);
112 
113 	TAILQ_INIT(conf->sc_listeners);
114 	TAILQ_INIT(conf->sc_rules);
115 
116 
117 	/* bounce dispatcher */
118 	conf->sc_dispatcher_bounce->type = DISPATCHER_BOUNCE;
119 
120 	/*
121 	 * declare special "localhost", "anyhost" and "localnames" tables
122 	 */
123 	set_local(conf, conf->sc_hostname);
124 
125 	t = table_create(conf, "static", "<anydestination>", NULL);
126 	table_add(t, "*", NULL);
127 
128 	hostname[strcspn(hostname, ".")] = '\0';
129 	if (strcmp(conf->sc_hostname, hostname) != 0)
130 		table_add(t, hostname, NULL);
131 
132 	table_create(conf, "getpwnam", "<getpwnam>", NULL);
133 
134 	return conf;
135 
136 error:
137 	free(conf->sc_tables_dict);
138 	free(conf->sc_rules);
139 	free(conf->sc_dispatchers);
140 	free(conf->sc_listeners);
141 	free(conf->sc_ca_dict);
142 	free(conf->sc_pki_dict);
143 	free(conf->sc_ssl_dict);
144 	free(conf->sc_limits_dict);
145 	free(conf->sc_mda_wrappers);
146 	free(conf->sc_filter_processes_dict);
147 	free(conf->sc_dispatcher_bounce);
148 	free(conf->sc_filters_dict);
149 	free(limits);
150 	free(conf);
151 	return NULL;
152 }
153 
154 void
set_local(struct smtpd * conf,const char * hostname)155 set_local(struct smtpd *conf, const char *hostname)
156 {
157 	struct table	*t;
158 
159 	t = table_create(conf, "static", "<localnames>", NULL);
160 	table_add(t, "localhost", NULL);
161 	table_add(t, hostname, NULL);
162 
163 	set_localaddrs(conf, t);
164 }
165 
166 void
set_localaddrs(struct smtpd * conf,struct table * localnames)167 set_localaddrs(struct smtpd *conf, struct table *localnames)
168 {
169 	struct ifaddrs *ifap, *p;
170 	struct sockaddr_storage ss;
171 	struct sockaddr_in	*sain;
172 	struct sockaddr_in6	*sin6;
173 	struct table		*t;
174 
175 	t = table_create(conf, "static", "<anyhost>", NULL);
176 	table_add(t, "local", NULL);
177 	table_add(t, "0.0.0.0/0", NULL);
178 	table_add(t, "::/0", NULL);
179 
180 	if (getifaddrs(&ifap) == -1)
181 		fatal("getifaddrs");
182 
183 	t = table_create(conf, "static", "<localhost>", NULL);
184 	table_add(t, "local", NULL);
185 
186 	for (p = ifap; p != NULL; p = p->ifa_next) {
187 		if (p->ifa_addr == NULL)
188 			continue;
189 		switch (p->ifa_addr->sa_family) {
190 		case AF_INET:
191 			sain = (struct sockaddr_in *)&ss;
192 			*sain = *(struct sockaddr_in *)p->ifa_addr;
193 			sain->sin_len = sizeof(struct sockaddr_in);
194 			table_add(t, ss_to_text(&ss), NULL);
195 			table_add(localnames, ss_to_text(&ss), NULL);
196 			break;
197 
198 		case AF_INET6:
199 			sin6 = (struct sockaddr_in6 *)&ss;
200 			*sin6 = *(struct sockaddr_in6 *)p->ifa_addr;
201 			sin6->sin6_len = sizeof(struct sockaddr_in6);
202 #ifdef __KAME__
203 			if ((IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
204 			    IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr) ||
205 			    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) &&
206 			    sin6->sin6_scope_id == 0) {
207 				sin6->sin6_scope_id = ntohs(
208 				    *(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
209 				sin6->sin6_addr.s6_addr[2] = 0;
210 				sin6->sin6_addr.s6_addr[3] = 0;
211 			}
212 #endif
213 			table_add(t, ss_to_text(&ss), NULL);
214 			table_add(localnames, ss_to_text(&ss), NULL);
215 			break;
216 		}
217 	}
218 
219 	freeifaddrs(ifap);
220 }
221 
222 void
purge_config(uint8_t what)223 purge_config(uint8_t what)
224 {
225 	struct dispatcher	*d;
226 	struct listener	*l;
227 	struct table	*t;
228 	struct rule	*r;
229 	struct pki	*p;
230 	const char	*k;
231 	void		*iter_dict;
232 
233 	if (what & PURGE_LISTENERS) {
234 		while ((l = TAILQ_FIRST(env->sc_listeners)) != NULL) {
235 			TAILQ_REMOVE(env->sc_listeners, l, entry);
236 			free(l->tls_ciphers);
237 			free(l->tls_protocols);
238 			free(l->pki);
239 			free(l);
240 		}
241 		free(env->sc_listeners);
242 		env->sc_listeners = NULL;
243 	}
244 	if (what & PURGE_TABLES) {
245 		while (dict_root(env->sc_tables_dict, NULL, (void **)&t))
246 			table_destroy(env, t);
247 		free(env->sc_tables_dict);
248 		env->sc_tables_dict = NULL;
249 	}
250 	if (what & PURGE_RULES) {
251 		while ((r = TAILQ_FIRST(env->sc_rules)) != NULL) {
252 			TAILQ_REMOVE(env->sc_rules, r, r_entry);
253 			free(r);
254 		}
255 		free(env->sc_rules);
256 		env->sc_rules = NULL;
257 	}
258 	if (what & PURGE_DISPATCHERS) {
259 		while (dict_poproot(env->sc_dispatchers, (void **)&d)) {
260 			free(d);
261 		}
262 		free(env->sc_dispatchers);
263 		env->sc_dispatchers = NULL;
264 	}
265 	if (what & PURGE_PKI) {
266 		while (dict_poproot(env->sc_pki_dict, (void **)&p)) {
267 			freezero(p->pki_cert, p->pki_cert_len);
268 			freezero(p->pki_key, p->pki_key_len);
269 			free(p);
270 		}
271 		free(env->sc_pki_dict);
272 		env->sc_pki_dict = NULL;
273 	} else if (what & PURGE_PKI_KEYS) {
274 		iter_dict = NULL;
275 		while (dict_iter(env->sc_pki_dict, &iter_dict, &k,
276 		    (void **)&p)) {
277 			freezero(p->pki_cert, p->pki_cert_len);
278 			p->pki_cert = NULL;
279 			freezero(p->pki_key, p->pki_key_len);
280 			p->pki_key = NULL;
281 		}
282 	}
283 }
284 
285 #ifndef CONFIG_MINIMUM
286 
287 void
config_process(enum smtp_proc_type proc)288 config_process(enum smtp_proc_type proc)
289 {
290 	struct rlimit rl;
291 
292 	smtpd_process = proc;
293 	setproctitle("%s", proc_title(proc));
294 
295 	if (getrlimit(RLIMIT_NOFILE, &rl) == -1)
296 		fatal("fdlimit: getrlimit");
297 	rl.rlim_cur = rl.rlim_max;
298 	if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
299 		fatal("fdlimit: setrlimit");
300 }
301 
302 void
config_peer(enum smtp_proc_type proc)303 config_peer(enum smtp_proc_type proc)
304 {
305 	struct mproc	*p;
306 
307 	if (proc == smtpd_process)
308 		fatal("config_peers: cannot peer with oneself");
309 
310 	if (proc == PROC_CONTROL)
311 		p = p_control;
312 	else if (proc == PROC_LKA)
313 		p = p_lka;
314 	else if (proc == PROC_PARENT)
315 		p = p_parent;
316 	else if (proc == PROC_QUEUE)
317 		p = p_queue;
318 	else if (proc == PROC_SCHEDULER)
319 		p = p_scheduler;
320 	else if (proc == PROC_DISPATCHER)
321 		p = p_dispatcher;
322 	else if (proc == PROC_CA)
323 		p = p_ca;
324 	else
325 		fatalx("bad peer");
326 
327 	mproc_enable(p);
328 }
329 
330 #else
331 
config_process(enum smtp_proc_type proc)332 void config_process(enum smtp_proc_type proc) {}
config_peer(enum smtp_proc_type proc)333 void config_peer(enum smtp_proc_type proc) {}
334 
335 #endif
336