xref: /openbsd-src/usr.sbin/smtpd/smtp.c (revision f1dd7b858388b4a23f4f67a4957ec5ff656ebbe8)
1 /*	$OpenBSD: smtp.c,v 1.169 2021/04/09 16:43:43 eric Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
5  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
6  * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <sys/types.h>
22 #include <sys/queue.h>
23 #include <sys/tree.h>
24 #include <sys/socket.h>
25 
26 #include <err.h>
27 #include <errno.h>
28 #include <event.h>
29 #include <imsg.h>
30 #include <netdb.h>
31 #include <pwd.h>
32 #include <signal.h>
33 #include <limits.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <tls.h>
38 #include <unistd.h>
39 
40 #include <openssl/ssl.h>
41 
42 #include "smtpd.h"
43 #include "log.h"
44 #include "ssl.h"
45 
46 static void smtp_setup_events(void);
47 static void smtp_pause(void);
48 static void smtp_resume(void);
49 static void smtp_accept(int, short, void *);
50 static void smtp_dropped(struct listener *, int, const struct sockaddr_storage *);
51 static int smtp_enqueue(void);
52 static int smtp_can_accept(void);
53 static void smtp_setup_listeners(void);
54 static void smtp_setup_listener_tls(struct listener *);
55 
56 int
57 proxy_session(struct listener *listener, int sock,
58     const struct sockaddr_storage *ss,
59     void (*accepted)(struct listener *, int,
60 	const struct sockaddr_storage *, struct io *),
61     void (*dropped)(struct listener *, int,
62 	const struct sockaddr_storage *));
63 
64 static void smtp_accepted(struct listener *, int, const struct sockaddr_storage *, struct io *);
65 
66 /*
67  * This function are not publicy exported because it is a hack until libtls
68  * has a proper privsep setup
69  */
70 void tls_config_use_fake_private_key(struct tls_config *config);
71 
72 #define	SMTP_FD_RESERVE	5
73 static size_t	sessions;
74 static size_t	maxsessions;
75 
76 void
77 smtp_imsg(struct mproc *p, struct imsg *imsg)
78 {
79 	switch (imsg->hdr.type) {
80 	case IMSG_SMTP_CHECK_SENDER:
81 	case IMSG_SMTP_EXPAND_RCPT:
82 	case IMSG_SMTP_LOOKUP_HELO:
83 	case IMSG_SMTP_AUTHENTICATE:
84 	case IMSG_FILTER_SMTP_PROTOCOL:
85 	case IMSG_FILTER_SMTP_DATA_BEGIN:
86 		smtp_session_imsg(p, imsg);
87 		return;
88 
89 	case IMSG_SMTP_MESSAGE_COMMIT:
90 	case IMSG_SMTP_MESSAGE_CREATE:
91 	case IMSG_SMTP_MESSAGE_OPEN:
92 	case IMSG_QUEUE_ENVELOPE_SUBMIT:
93 	case IMSG_QUEUE_ENVELOPE_COMMIT:
94 		smtp_session_imsg(p, imsg);
95 		return;
96 
97 	case IMSG_QUEUE_SMTP_SESSION:
98 		m_compose(p, IMSG_QUEUE_SMTP_SESSION, 0, 0, smtp_enqueue(),
99 		    imsg->data, imsg->hdr.len - sizeof imsg->hdr);
100 		return;
101 
102 	case IMSG_CTL_SMTP_SESSION:
103 		m_compose(p, IMSG_CTL_SMTP_SESSION, imsg->hdr.peerid, 0,
104 		    smtp_enqueue(), NULL, 0);
105 		return;
106 
107 	case IMSG_CTL_PAUSE_SMTP:
108 		log_debug("debug: smtp: pausing listening sockets");
109 		smtp_pause();
110 		env->sc_flags |= SMTPD_SMTP_PAUSED;
111 		return;
112 
113 	case IMSG_CTL_RESUME_SMTP:
114 		log_debug("debug: smtp: resuming listening sockets");
115 		env->sc_flags &= ~SMTPD_SMTP_PAUSED;
116 		smtp_resume();
117 		return;
118 	}
119 
120 	errx(1, "smtp_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
121 }
122 
123 void
124 smtp_postfork(void)
125 {
126 	smtp_setup_listeners();
127 }
128 
129 void
130 smtp_postprivdrop(void)
131 {
132 }
133 
134 void
135 smtp_configure(void)
136 {
137 	smtp_setup_events();
138 }
139 
140 static void
141 smtp_setup_listeners(void)
142 {
143 	struct listener	       *l;
144 	int			opt;
145 
146 	TAILQ_FOREACH(l, env->sc_listeners, entry) {
147 		if ((l->fd = socket(l->ss.ss_family, SOCK_STREAM, 0)) == -1) {
148 			if (errno == EAFNOSUPPORT) {
149 				log_warn("smtpd: socket");
150 				continue;
151 			}
152 			fatal("smtpd: socket");
153 		}
154 
155 		if (l->flags & F_SSL)
156 			smtp_setup_listener_tls(l);
157 
158 		opt = 1;
159 		if (setsockopt(l->fd, SOL_SOCKET, SO_REUSEADDR, &opt,
160 		    sizeof(opt)) == -1)
161 			fatal("smtpd: setsockopt");
162 		if (bind(l->fd, (struct sockaddr *)&l->ss, l->ss.ss_len) == -1)
163 			fatal("smtpd: bind");
164 	}
165 }
166 
167 static void
168 smtp_setup_listener_tls(struct listener *l)
169 {
170 	static const char *dheparams[] = { "none", "auto", "legacy" };
171 	struct tls_config *config;
172 	const char *ciphers;
173 	uint32_t protos;
174 	struct pki *pki;
175 	struct ca *ca;
176 	int i;
177 
178 	if ((config = tls_config_new()) == NULL)
179 		fatal("smtpd: tls_config_new");
180 
181 	ciphers = env->sc_tls_ciphers;
182 	if (l->tls_ciphers)
183 		ciphers = l->tls_ciphers;
184 	if (ciphers && tls_config_set_ciphers(config, ciphers) == -1)
185 		err(1, "%s", tls_config_error(config));
186 
187 	if (l->tls_protocols) {
188 		if (tls_config_parse_protocols(&protos, l->tls_protocols) == -1)
189 			err(1, "failed to parse protocols \"%s\"",
190 			    l->tls_protocols);
191 		if (tls_config_set_protocols(config, protos) == -1)
192 			err(1, "%s", tls_config_error(config));
193 	}
194 
195 	pki = l->pki[0];
196 	if (pki == NULL)
197 		fatal("no pki defined");
198 
199 	if (tls_config_set_dheparams(config, dheparams[pki->pki_dhe]) == -1)
200 		fatal("tls_config_set_dheparams");
201 
202 	tls_config_use_fake_private_key(config);
203 	for (i = 0; i < l->pkicount; i++) {
204 		pki = l->pki[i];
205 		if (i == 0) {
206 			if (tls_config_set_keypair_mem(config, pki->pki_cert,
207 			    pki->pki_cert_len, NULL, 0) == -1)
208 				fatal("tls_config_set_keypair_mem");
209 		} else {
210 			if (tls_config_add_keypair_mem(config, pki->pki_cert,
211 			    pki->pki_cert_len, NULL, 0) == -1)
212 				fatal("tls_config_add_keypair_mem");
213 		}
214 	}
215 	free(l->pki);
216 	l->pkicount = 0;
217 
218 	if (l->ca_name[0]) {
219 		ca = dict_get(env->sc_ca_dict, l->ca_name);
220 		if (tls_config_set_ca_mem(config, ca->ca_cert, ca->ca_cert_len)
221 		    == -1)
222 			fatal("tls_config_set_ca_mem");
223 	}
224 	else if (tls_config_set_ca_file(config, tls_default_ca_cert_file())
225 	    == -1)
226 		fatal("tls_config_set_ca_file");
227 
228 	if (l->flags & F_TLS_VERIFY)
229 		tls_config_verify_client(config);
230 
231 	l->tls = tls_server();
232 	if (l->tls == NULL)
233 		fatal("tls_server");
234 	if (tls_configure(l->tls, config) == -1) {
235 		fatal("tls_configure: %s", tls_error(l->tls));
236 	}
237 	tls_config_free(config);
238 }
239 
240 
241 static void
242 smtp_setup_events(void)
243 {
244 	struct listener *l;
245 
246 	TAILQ_FOREACH(l, env->sc_listeners, entry) {
247 		log_debug("debug: smtp: listen on %s port %d flags 0x%01x",
248 		    ss_to_text(&l->ss), ntohs(l->port), l->flags);
249 
250 		io_set_nonblocking(l->fd);
251 		if (listen(l->fd, SMTPD_BACKLOG) == -1)
252 			fatal("listen");
253 		event_set(&l->ev, l->fd, EV_READ|EV_PERSIST, smtp_accept, l);
254 
255 		if (!(env->sc_flags & SMTPD_SMTP_PAUSED))
256 			event_add(&l->ev, NULL);
257 	}
258 
259 	purge_config(PURGE_PKI_KEYS);
260 
261 	maxsessions = (getdtablesize() - getdtablecount()) / 2 - SMTP_FD_RESERVE;
262 	log_debug("debug: smtp: will accept at most %zu clients", maxsessions);
263 }
264 
265 static void
266 smtp_pause(void)
267 {
268 	struct listener *l;
269 
270 	if (env->sc_flags & (SMTPD_SMTP_DISABLED|SMTPD_SMTP_PAUSED))
271 		return;
272 
273 	TAILQ_FOREACH(l, env->sc_listeners, entry)
274 		event_del(&l->ev);
275 }
276 
277 static void
278 smtp_resume(void)
279 {
280 	struct listener *l;
281 
282 	if (env->sc_flags & (SMTPD_SMTP_DISABLED|SMTPD_SMTP_PAUSED))
283 		return;
284 
285 	TAILQ_FOREACH(l, env->sc_listeners, entry)
286 		event_add(&l->ev, NULL);
287 }
288 
289 static int
290 smtp_enqueue(void)
291 {
292 	struct listener	*listener = env->sc_sock_listener;
293 	int		 fd[2];
294 
295 	/*
296 	 * Some enqueue requests buffered in IMSG may still arrive even after
297 	 * call to smtp_pause() because enqueue listener is not a real socket
298 	 * and thus cannot be paused properly.
299 	 */
300 	if (env->sc_flags & SMTPD_SMTP_PAUSED)
301 		return (-1);
302 
303 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fd))
304 		return (-1);
305 
306 	if ((smtp_session(listener, fd[0], &listener->ss, env->sc_hostname, NULL)) == -1) {
307 		close(fd[0]);
308 		close(fd[1]);
309 		return (-1);
310 	}
311 
312 	sessions++;
313 	stat_increment("smtp.session", 1);
314 	stat_increment("smtp.session.local", 1);
315 
316 	return (fd[1]);
317 }
318 
319 static void
320 smtp_accept(int fd, short event, void *p)
321 {
322 	struct listener		*listener = p;
323 	struct sockaddr_storage	 ss;
324 	socklen_t		 len;
325 	int			 sock;
326 
327 	if (env->sc_flags & SMTPD_SMTP_PAUSED)
328 		fatalx("smtp_session: unexpected client");
329 
330 	if (!smtp_can_accept()) {
331 		log_warnx("warn: Disabling incoming SMTP connections: "
332 		    "Client limit reached");
333 		goto pause;
334 	}
335 
336 	len = sizeof(ss);
337 	if ((sock = accept(fd, (struct sockaddr *)&ss, &len)) == -1) {
338 		if (errno == ENFILE || errno == EMFILE) {
339 			log_warn("warn: Disabling incoming SMTP connections");
340 			goto pause;
341 		}
342 		if (errno == EINTR || errno == EWOULDBLOCK ||
343 		    errno == ECONNABORTED)
344 			return;
345 		fatal("smtp_accept");
346 	}
347 
348 	if (listener->flags & F_PROXY) {
349 		io_set_nonblocking(sock);
350 		if (proxy_session(listener, sock, &ss,
351 			smtp_accepted, smtp_dropped) == -1) {
352 			close(sock);
353 			return;
354 		}
355 		return;
356 	}
357 
358 	smtp_accepted(listener, sock, &ss, NULL);
359 	return;
360 
361 pause:
362 	smtp_pause();
363 	env->sc_flags |= SMTPD_SMTP_DISABLED;
364 	return;
365 }
366 
367 static int
368 smtp_can_accept(void)
369 {
370 	if (sessions + 1 == maxsessions)
371 		return 0;
372 	return (getdtablesize() - getdtablecount() - SMTP_FD_RESERVE >= 2);
373 }
374 
375 void
376 smtp_collect(void)
377 {
378 	sessions--;
379 	stat_decrement("smtp.session", 1);
380 
381 	if (!smtp_can_accept())
382 		return;
383 
384 	if (env->sc_flags & SMTPD_SMTP_DISABLED) {
385 		log_warnx("warn: smtp: "
386 		    "fd exhaustion over, re-enabling incoming connections");
387 		env->sc_flags &= ~SMTPD_SMTP_DISABLED;
388 		smtp_resume();
389 	}
390 }
391 
392 static void
393 smtp_accepted(struct listener *listener, int sock, const struct sockaddr_storage *ss, struct io *io)
394 {
395 	int     ret;
396 
397 	ret = smtp_session(listener, sock, ss, NULL, io);
398 	if (ret == -1) {
399 		log_warn("warn: Failed to create SMTP session");
400 		close(sock);
401 		return;
402 	}
403 	io_set_nonblocking(sock);
404 
405 	sessions++;
406 	stat_increment("smtp.session", 1);
407 	if (listener->ss.ss_family == AF_LOCAL)
408 		stat_increment("smtp.session.local", 1);
409 	if (listener->ss.ss_family == AF_INET)
410 		stat_increment("smtp.session.inet4", 1);
411 	if (listener->ss.ss_family == AF_INET6)
412 		stat_increment("smtp.session.inet6", 1);
413 }
414 
415 static void
416 smtp_dropped(struct listener *listener, int sock, const struct sockaddr_storage *ss)
417 {
418 	close(sock);
419 	sessions--;
420 }
421