xref: /openbsd-src/usr.sbin/smtpd/config.c (revision ed9a50d3bb49a44ad441943db2e0746b2d138d31)
1*ed9a50d3Sop /*	$OpenBSD: config.c,v 1.58 2024/01/04 09:30:09 op Exp $	*/
21f3c2bcfSsobrado 
33ef9cbf7Sgilles /*
43ef9cbf7Sgilles  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
53ef9cbf7Sgilles  *
63ef9cbf7Sgilles  * Permission to use, copy, modify, and distribute this software for any
73ef9cbf7Sgilles  * purpose with or without fee is hereby granted, provided that the above
83ef9cbf7Sgilles  * copyright notice and this permission notice appear in all copies.
93ef9cbf7Sgilles  *
103ef9cbf7Sgilles  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
113ef9cbf7Sgilles  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
123ef9cbf7Sgilles  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
133ef9cbf7Sgilles  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
143ef9cbf7Sgilles  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
153ef9cbf7Sgilles  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
163ef9cbf7Sgilles  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
173ef9cbf7Sgilles  */
183ef9cbf7Sgilles 
1942b7f83eSeric #include <sys/resource.h>
203ef9cbf7Sgilles 
21942f9647Sgilles #include <ifaddrs.h>
223ef9cbf7Sgilles #include <stdlib.h>
2365c4fdfbSgilles #include <string.h>
2465c4fdfbSgilles 
253ef9cbf7Sgilles #include "smtpd.h"
265eb8dddaSgilles #include "log.h"
2765c4fdfbSgilles #include "ssl.h"
283ef9cbf7Sgilles 
29942f9647Sgilles void		 set_local(struct smtpd *, const char *);
30942f9647Sgilles void		 set_localaddrs(struct smtpd *, struct table *);
31942f9647Sgilles 
32942f9647Sgilles struct smtpd *
config_default(void)33942f9647Sgilles config_default(void)
34942f9647Sgilles {
35942f9647Sgilles 	struct smtpd	       *conf = NULL;
36942f9647Sgilles 	struct mta_limits      *limits = NULL;
37942f9647Sgilles 	struct table	       *t = NULL;
38942f9647Sgilles 	char			hostname[HOST_NAME_MAX+1];
39942f9647Sgilles 
40942f9647Sgilles 	if (getmailname(hostname, sizeof hostname) == -1)
41942f9647Sgilles 		return NULL;
42942f9647Sgilles 
43942f9647Sgilles 	if ((conf = calloc(1, sizeof(*conf))) == NULL)
44942f9647Sgilles 		return conf;
45942f9647Sgilles 
46942f9647Sgilles 	(void)strlcpy(conf->sc_hostname, hostname, sizeof(conf->sc_hostname));
47942f9647Sgilles 
48942f9647Sgilles 	conf->sc_maxsize = DEFAULT_MAX_BODY_SIZE;
49942f9647Sgilles 	conf->sc_subaddressing_delim = SUBADDRESSING_DELIMITER;
50942f9647Sgilles 	conf->sc_ttl = SMTPD_QUEUE_EXPIRY;
51c78098c5Sgilles 	conf->sc_srs_ttl = SMTPD_QUEUE_EXPIRY / 86400;
52942f9647Sgilles 
53942f9647Sgilles 	conf->sc_mta_max_deferred = 100;
54942f9647Sgilles 	conf->sc_scheduler_max_inflight = 5000;
55942f9647Sgilles 	conf->sc_scheduler_max_schedule = 10;
56942f9647Sgilles 	conf->sc_scheduler_max_evp_batch_size = 256;
57942f9647Sgilles 	conf->sc_scheduler_max_msg_batch_size = 1024;
58942f9647Sgilles 
59942f9647Sgilles 	conf->sc_session_max_rcpt = 1000;
60942f9647Sgilles 	conf->sc_session_max_mails = 100;
61942f9647Sgilles 
62942f9647Sgilles 	conf->sc_mda_max_session = 50;
63942f9647Sgilles 	conf->sc_mda_max_user_session = 7;
64942f9647Sgilles 	conf->sc_mda_task_hiwat = 50;
65942f9647Sgilles 	conf->sc_mda_task_lowat = 30;
66942f9647Sgilles 	conf->sc_mda_task_release = 10;
67942f9647Sgilles 
68942f9647Sgilles 	/* Report mails delayed for more than 4 hours */
69942f9647Sgilles 	conf->sc_bounce_warn[0] = 3600 * 4;
70942f9647Sgilles 
71942f9647Sgilles 	conf->sc_tables_dict = calloc(1, sizeof(*conf->sc_tables_dict));
72942f9647Sgilles 	conf->sc_rules = calloc(1, sizeof(*conf->sc_rules));
73942f9647Sgilles 	conf->sc_dispatchers = calloc(1, sizeof(*conf->sc_dispatchers));
74942f9647Sgilles 	conf->sc_listeners = calloc(1, sizeof(*conf->sc_listeners));
75942f9647Sgilles 	conf->sc_ca_dict = calloc(1, sizeof(*conf->sc_ca_dict));
76942f9647Sgilles 	conf->sc_pki_dict = calloc(1, sizeof(*conf->sc_pki_dict));
77942f9647Sgilles 	conf->sc_ssl_dict = calloc(1, sizeof(*conf->sc_ssl_dict));
78942f9647Sgilles 	conf->sc_limits_dict = calloc(1, sizeof(*conf->sc_limits_dict));
79942f9647Sgilles 	conf->sc_mda_wrappers = calloc(1, sizeof(*conf->sc_mda_wrappers));
805d1bf438Sgilles 	conf->sc_filter_processes_dict = calloc(1, sizeof(*conf->sc_filter_processes_dict));
81942f9647Sgilles 	conf->sc_dispatcher_bounce = calloc(1, sizeof(*conf->sc_dispatcher_bounce));
82ec69ed85Sgilles 	conf->sc_filters_dict = calloc(1, sizeof(*conf->sc_filters_dict));
83942f9647Sgilles 	limits = calloc(1, sizeof(*limits));
84942f9647Sgilles 
85942f9647Sgilles 	if (conf->sc_tables_dict == NULL	||
86942f9647Sgilles 	    conf->sc_rules == NULL		||
87942f9647Sgilles 	    conf->sc_dispatchers == NULL	||
88942f9647Sgilles 	    conf->sc_listeners == NULL		||
89942f9647Sgilles 	    conf->sc_ca_dict == NULL		||
90942f9647Sgilles 	    conf->sc_pki_dict == NULL		||
91942f9647Sgilles 	    conf->sc_ssl_dict == NULL		||
92942f9647Sgilles 	    conf->sc_limits_dict == NULL        ||
93942f9647Sgilles 	    conf->sc_mda_wrappers == NULL	||
945d1bf438Sgilles 	    conf->sc_filter_processes_dict == NULL	||
95942f9647Sgilles 	    conf->sc_dispatcher_bounce == NULL	||
96ec69ed85Sgilles 	    conf->sc_filters_dict == NULL	||
97942f9647Sgilles 	    limits == NULL)
98942f9647Sgilles 		goto error;
99942f9647Sgilles 
100942f9647Sgilles 	dict_init(conf->sc_dispatchers);
101942f9647Sgilles 	dict_init(conf->sc_mda_wrappers);
102942f9647Sgilles 	dict_init(conf->sc_ca_dict);
103942f9647Sgilles 	dict_init(conf->sc_pki_dict);
104942f9647Sgilles 	dict_init(conf->sc_ssl_dict);
105942f9647Sgilles 	dict_init(conf->sc_tables_dict);
106942f9647Sgilles 	dict_init(conf->sc_limits_dict);
1075d1bf438Sgilles 	dict_init(conf->sc_filter_processes_dict);
108942f9647Sgilles 
109942f9647Sgilles 	limit_mta_set_defaults(limits);
110942f9647Sgilles 
111942f9647Sgilles 	dict_xset(conf->sc_limits_dict, "default", limits);
112942f9647Sgilles 
113942f9647Sgilles 	TAILQ_INIT(conf->sc_listeners);
114942f9647Sgilles 	TAILQ_INIT(conf->sc_rules);
115942f9647Sgilles 
116d7b0dc3bSgilles 
117942f9647Sgilles 	/* bounce dispatcher */
118942f9647Sgilles 	conf->sc_dispatcher_bounce->type = DISPATCHER_BOUNCE;
119942f9647Sgilles 
120942f9647Sgilles 	/*
121942f9647Sgilles 	 * declare special "localhost", "anyhost" and "localnames" tables
122942f9647Sgilles 	 */
123942f9647Sgilles 	set_local(conf, conf->sc_hostname);
124942f9647Sgilles 
125ff18143eSeric 	t = table_create(conf, "static", "<anydestination>", NULL);
126942f9647Sgilles 	table_add(t, "*", NULL);
127942f9647Sgilles 
128942f9647Sgilles 	hostname[strcspn(hostname, ".")] = '\0';
129942f9647Sgilles 	if (strcmp(conf->sc_hostname, hostname) != 0)
130942f9647Sgilles 		table_add(t, hostname, NULL);
131942f9647Sgilles 
132ff18143eSeric 	table_create(conf, "getpwnam", "<getpwnam>", NULL);
133942f9647Sgilles 
134942f9647Sgilles 	return conf;
135942f9647Sgilles 
136942f9647Sgilles error:
137942f9647Sgilles 	free(conf->sc_tables_dict);
138942f9647Sgilles 	free(conf->sc_rules);
139942f9647Sgilles 	free(conf->sc_dispatchers);
140942f9647Sgilles 	free(conf->sc_listeners);
141942f9647Sgilles 	free(conf->sc_ca_dict);
142942f9647Sgilles 	free(conf->sc_pki_dict);
143942f9647Sgilles 	free(conf->sc_ssl_dict);
144942f9647Sgilles 	free(conf->sc_limits_dict);
145942f9647Sgilles 	free(conf->sc_mda_wrappers);
1465d1bf438Sgilles 	free(conf->sc_filter_processes_dict);
147942f9647Sgilles 	free(conf->sc_dispatcher_bounce);
148ec69ed85Sgilles 	free(conf->sc_filters_dict);
149942f9647Sgilles 	free(limits);
150942f9647Sgilles 	free(conf);
151942f9647Sgilles 	return NULL;
152942f9647Sgilles }
153942f9647Sgilles 
154942f9647Sgilles void
set_local(struct smtpd * conf,const char * hostname)155942f9647Sgilles set_local(struct smtpd *conf, const char *hostname)
156942f9647Sgilles {
157942f9647Sgilles 	struct table	*t;
158942f9647Sgilles 
159ff18143eSeric 	t = table_create(conf, "static", "<localnames>", NULL);
160942f9647Sgilles 	table_add(t, "localhost", NULL);
161942f9647Sgilles 	table_add(t, hostname, NULL);
162942f9647Sgilles 
163942f9647Sgilles 	set_localaddrs(conf, t);
164942f9647Sgilles }
165942f9647Sgilles 
166942f9647Sgilles void
set_localaddrs(struct smtpd * conf,struct table * localnames)167942f9647Sgilles set_localaddrs(struct smtpd *conf, struct table *localnames)
168942f9647Sgilles {
169942f9647Sgilles 	struct ifaddrs *ifap, *p;
170942f9647Sgilles 	struct sockaddr_storage ss;
171942f9647Sgilles 	struct sockaddr_in	*sain;
172942f9647Sgilles 	struct sockaddr_in6	*sin6;
173942f9647Sgilles 	struct table		*t;
174942f9647Sgilles 
175ff18143eSeric 	t = table_create(conf, "static", "<anyhost>", NULL);
176942f9647Sgilles 	table_add(t, "local", NULL);
177942f9647Sgilles 	table_add(t, "0.0.0.0/0", NULL);
178942f9647Sgilles 	table_add(t, "::/0", NULL);
179942f9647Sgilles 
180942f9647Sgilles 	if (getifaddrs(&ifap) == -1)
181942f9647Sgilles 		fatal("getifaddrs");
182942f9647Sgilles 
183ff18143eSeric 	t = table_create(conf, "static", "<localhost>", NULL);
184942f9647Sgilles 	table_add(t, "local", NULL);
185942f9647Sgilles 
186942f9647Sgilles 	for (p = ifap; p != NULL; p = p->ifa_next) {
187942f9647Sgilles 		if (p->ifa_addr == NULL)
188942f9647Sgilles 			continue;
189942f9647Sgilles 		switch (p->ifa_addr->sa_family) {
190942f9647Sgilles 		case AF_INET:
191942f9647Sgilles 			sain = (struct sockaddr_in *)&ss;
192942f9647Sgilles 			*sain = *(struct sockaddr_in *)p->ifa_addr;
193942f9647Sgilles 			sain->sin_len = sizeof(struct sockaddr_in);
194942f9647Sgilles 			table_add(t, ss_to_text(&ss), NULL);
195942f9647Sgilles 			table_add(localnames, ss_to_text(&ss), NULL);
196942f9647Sgilles 			break;
197942f9647Sgilles 
198942f9647Sgilles 		case AF_INET6:
199942f9647Sgilles 			sin6 = (struct sockaddr_in6 *)&ss;
200942f9647Sgilles 			*sin6 = *(struct sockaddr_in6 *)p->ifa_addr;
201942f9647Sgilles 			sin6->sin6_len = sizeof(struct sockaddr_in6);
202ad380068Sclaudio #ifdef __KAME__
203ad380068Sclaudio 			if ((IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
204ad380068Sclaudio 			    IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr) ||
205ad380068Sclaudio 			    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) &&
206ad380068Sclaudio 			    sin6->sin6_scope_id == 0) {
207ad380068Sclaudio 				sin6->sin6_scope_id = ntohs(
208ad380068Sclaudio 				    *(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
209ad380068Sclaudio 				sin6->sin6_addr.s6_addr[2] = 0;
210ad380068Sclaudio 				sin6->sin6_addr.s6_addr[3] = 0;
211ad380068Sclaudio 			}
212ad380068Sclaudio #endif
213942f9647Sgilles 			table_add(t, ss_to_text(&ss), NULL);
214942f9647Sgilles 			table_add(localnames, ss_to_text(&ss), NULL);
215942f9647Sgilles 			break;
216942f9647Sgilles 		}
217942f9647Sgilles 	}
218942f9647Sgilles 
219942f9647Sgilles 	freeifaddrs(ifap);
220942f9647Sgilles }
221942f9647Sgilles 
2223ef9cbf7Sgilles void
purge_config(uint8_t what)223d2241734Schl purge_config(uint8_t what)
2243ef9cbf7Sgilles {
225a8e22235Sgilles 	struct dispatcher	*d;
2263ef9cbf7Sgilles 	struct listener	*l;
22765c4fdfbSgilles 	struct table	*t;
2283ef9cbf7Sgilles 	struct rule	*r;
2291c3ac238Seric 	struct pki	*p;
230c4df3bf2Sreyk 	const char	*k;
231c4df3bf2Sreyk 	void		*iter_dict;
2323ef9cbf7Sgilles 
2333ef9cbf7Sgilles 	if (what & PURGE_LISTENERS) {
234fcba321cSgilles 		while ((l = TAILQ_FIRST(env->sc_listeners)) != NULL) {
235fcba321cSgilles 			TAILQ_REMOVE(env->sc_listeners, l, entry);
236a040621aSeric 			free(l->tls_ciphers);
237a040621aSeric 			free(l->tls_protocols);
238eed85469Seric 			free(l->pki);
2393ef9cbf7Sgilles 			free(l);
2403ef9cbf7Sgilles 		}
241fcba321cSgilles 		free(env->sc_listeners);
242fcba321cSgilles 		env->sc_listeners = NULL;
2433ef9cbf7Sgilles 	}
24465c4fdfbSgilles 	if (what & PURGE_TABLES) {
245299c4efeSeric 		while (dict_root(env->sc_tables_dict, NULL, (void **)&t))
246b80b41afSgilles 			table_destroy(env, t);
24765c4fdfbSgilles 		free(env->sc_tables_dict);
24865c4fdfbSgilles 		env->sc_tables_dict = NULL;
2493ef9cbf7Sgilles 	}
2503ef9cbf7Sgilles 	if (what & PURGE_RULES) {
2513ef9cbf7Sgilles 		while ((r = TAILQ_FIRST(env->sc_rules)) != NULL) {
2523ef9cbf7Sgilles 			TAILQ_REMOVE(env->sc_rules, r, r_entry);
2533ef9cbf7Sgilles 			free(r);
2543ef9cbf7Sgilles 		}
255c6f2f3e6Sjacekm 		free(env->sc_rules);
2563ef9cbf7Sgilles 		env->sc_rules = NULL;
2573ef9cbf7Sgilles 	}
258a8e22235Sgilles 	if (what & PURGE_DISPATCHERS) {
259a8e22235Sgilles 		while (dict_poproot(env->sc_dispatchers, (void **)&d)) {
260a8e22235Sgilles 			free(d);
261a8e22235Sgilles 		}
262a8e22235Sgilles 		free(env->sc_dispatchers);
263a8e22235Sgilles 		env->sc_dispatchers = NULL;
264a8e22235Sgilles 	}
2651c3ac238Seric 	if (what & PURGE_PKI) {
2661c3ac238Seric 		while (dict_poproot(env->sc_pki_dict, (void **)&p)) {
267d914c05cSderaadt 			freezero(p->pki_cert, p->pki_cert_len);
268d914c05cSderaadt 			freezero(p->pki_key, p->pki_key_len);
2691c3ac238Seric 			free(p);
2703ef9cbf7Sgilles 		}
2711c3ac238Seric 		free(env->sc_pki_dict);
2721c3ac238Seric 		env->sc_pki_dict = NULL;
273c4df3bf2Sreyk 	} else if (what & PURGE_PKI_KEYS) {
274c4df3bf2Sreyk 		iter_dict = NULL;
275c4df3bf2Sreyk 		while (dict_iter(env->sc_pki_dict, &iter_dict, &k,
276c4df3bf2Sreyk 		    (void **)&p)) {
277d914c05cSderaadt 			freezero(p->pki_cert, p->pki_cert_len);
278c4df3bf2Sreyk 			p->pki_cert = NULL;
279d914c05cSderaadt 			freezero(p->pki_key, p->pki_key_len);
280c4df3bf2Sreyk 			p->pki_key = NULL;
281c4df3bf2Sreyk 		}
2823ef9cbf7Sgilles 	}
2833ef9cbf7Sgilles }
2843ef9cbf7Sgilles 
285b9318d1dSmortimer #ifndef CONFIG_MINIMUM
286b9318d1dSmortimer 
2873ef9cbf7Sgilles void
config_process(enum smtp_proc_type proc)28865c4fdfbSgilles config_process(enum smtp_proc_type proc)
2895b8a38b4Sjacekm {
29042b7f83eSeric 	struct rlimit rl;
29142b7f83eSeric 
29265c4fdfbSgilles 	smtpd_process = proc;
29365c4fdfbSgilles 	setproctitle("%s", proc_title(proc));
29442b7f83eSeric 
29542b7f83eSeric 	if (getrlimit(RLIMIT_NOFILE, &rl) == -1)
29642b7f83eSeric 		fatal("fdlimit: getrlimit");
29742b7f83eSeric 	rl.rlim_cur = rl.rlim_max;
29842b7f83eSeric 	if (setrlimit(RLIMIT_NOFILE, &rl) == -1)
29942b7f83eSeric 		fatal("fdlimit: setrlimit");
30065c4fdfbSgilles }
3013ef9cbf7Sgilles 
30265c4fdfbSgilles void
config_peer(enum smtp_proc_type proc)30365c4fdfbSgilles config_peer(enum smtp_proc_type proc)
30465c4fdfbSgilles {
30565c4fdfbSgilles 	struct mproc	*p;
3065b8a38b4Sjacekm 
30765c4fdfbSgilles 	if (proc == smtpd_process)
3083ef9cbf7Sgilles 		fatal("config_peers: cannot peer with oneself");
3093ef9cbf7Sgilles 
31065c4fdfbSgilles 	if (proc == PROC_CONTROL)
311b88ab68dSeric 		p = p_control;
31265c4fdfbSgilles 	else if (proc == PROC_LKA)
313b88ab68dSeric 		p = p_lka;
31465c4fdfbSgilles 	else if (proc == PROC_PARENT)
315b88ab68dSeric 		p = p_parent;
31665c4fdfbSgilles 	else if (proc == PROC_QUEUE)
317b88ab68dSeric 		p = p_queue;
31865c4fdfbSgilles 	else if (proc == PROC_SCHEDULER)
319b88ab68dSeric 		p = p_scheduler;
3201a5b831aSmartijn 	else if (proc == PROC_DISPATCHER)
3211a5b831aSmartijn 		p = p_dispatcher;
32276eb97c5Sreyk 	else if (proc == PROC_CA)
323b88ab68dSeric 		p = p_ca;
32465c4fdfbSgilles 	else
32565c4fdfbSgilles 		fatalx("bad peer");
326b88ab68dSeric 
327b88ab68dSeric 	mproc_enable(p);
32865c4fdfbSgilles }
329b9318d1dSmortimer 
330b9318d1dSmortimer #else
331b9318d1dSmortimer 
config_process(enum smtp_proc_type proc)332b9318d1dSmortimer void config_process(enum smtp_proc_type proc) {}
config_peer(enum smtp_proc_type proc)333b9318d1dSmortimer void config_peer(enum smtp_proc_type proc) {}
334b9318d1dSmortimer 
335b9318d1dSmortimer #endif
336