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
29void		 set_local(struct smtpd *, const char *);
30void		 set_localaddrs(struct smtpd *, struct table *);
31
32struct smtpd *
33config_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
136error:
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
154void
155set_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
166void
167set_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
222void
223purge_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
287void
288config_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
302void
303config_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
332void config_process(enum smtp_proc_type proc) {}
333void config_peer(enum smtp_proc_type proc) {}
334
335#endif
336