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