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