diff options
Diffstat (limited to 'smtpd/smtp.c')
-rw-r--r-- | smtpd/smtp.c | 387 |
1 files changed, 0 insertions, 387 deletions
diff --git a/smtpd/smtp.c b/smtpd/smtp.c deleted file mode 100644 index 602fd0d6..00000000 --- a/smtpd/smtp.c +++ /dev/null @@ -1,387 +0,0 @@ -/* $OpenBSD: smtp.c,v 1.166 2019/08/10 16:07:01 gilles Exp $ */ - -/* - * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> - * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> - * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "includes.h" - -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/tree.h> -#include <sys/socket.h> - -#include <err.h> -#include <errno.h> -#include <event.h> -#include <grp.h> /* needed for setgroups */ -#include <imsg.h> -#include <netdb.h> -#include <pwd.h> -#include <signal.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <openssl/ssl.h> - -#include "smtpd.h" -#include "log.h" -#include "ssl.h" - -static void smtp_setup_events(void); -static void smtp_pause(void); -static void smtp_resume(void); -static void smtp_accept(int, short, void *); -static void smtp_dropped(struct listener *, int, const struct sockaddr_storage *); -static int smtp_enqueue(void); -static int smtp_can_accept(void); -static void smtp_setup_listeners(void); -static int smtp_sni_callback(SSL *, int *, void *); - -int -proxy_session(struct listener *listener, int sock, - const struct sockaddr_storage *ss, - void (*accepted)(struct listener *, int, - const struct sockaddr_storage *, struct io *), - void (*dropped)(struct listener *, int, - const struct sockaddr_storage *)); - -static void smtp_accepted(struct listener *, int, const struct sockaddr_storage *, struct io *); - - -#define SMTP_FD_RESERVE 5 -#define getdtablecount() 0 - -static size_t sessions; -static size_t maxsessions; - -void -smtp_imsg(struct mproc *p, struct imsg *imsg) -{ - switch (imsg->hdr.type) { - case IMSG_SMTP_CHECK_SENDER: - case IMSG_SMTP_EXPAND_RCPT: - case IMSG_SMTP_LOOKUP_HELO: - case IMSG_SMTP_AUTHENTICATE: - case IMSG_FILTER_SMTP_PROTOCOL: - case IMSG_FILTER_SMTP_DATA_BEGIN: - smtp_session_imsg(p, imsg); - return; - - case IMSG_SMTP_MESSAGE_COMMIT: - case IMSG_SMTP_MESSAGE_CREATE: - case IMSG_SMTP_MESSAGE_OPEN: - case IMSG_QUEUE_ENVELOPE_SUBMIT: - case IMSG_QUEUE_ENVELOPE_COMMIT: - smtp_session_imsg(p, imsg); - return; - - case IMSG_QUEUE_SMTP_SESSION: - m_compose(p, IMSG_QUEUE_SMTP_SESSION, 0, 0, smtp_enqueue(), - imsg->data, imsg->hdr.len - sizeof imsg->hdr); - return; - - case IMSG_CTL_SMTP_SESSION: - m_compose(p, IMSG_CTL_SMTP_SESSION, imsg->hdr.peerid, 0, - smtp_enqueue(), NULL, 0); - return; - - case IMSG_CTL_PAUSE_SMTP: - log_debug("debug: smtp: pausing listening sockets"); - smtp_pause(); - env->sc_flags |= SMTPD_SMTP_PAUSED; - return; - - case IMSG_CTL_RESUME_SMTP: - log_debug("debug: smtp: resuming listening sockets"); - env->sc_flags &= ~SMTPD_SMTP_PAUSED; - smtp_resume(); - return; - } - - errx(1, "smtp_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type)); -} - -void -smtp_postfork(void) -{ - smtp_setup_listeners(); -} - -void -smtp_postprivdrop(void) -{ -} - -void -smtp_configure(void) -{ - smtp_setup_events(); -} - -static void -smtp_setup_listeners(void) -{ - struct listener *l; - int opt; - - TAILQ_FOREACH(l, env->sc_listeners, entry) { - if ((l->fd = socket(l->ss.ss_family, SOCK_STREAM, 0)) == -1) { - if (errno == EAFNOSUPPORT) { - log_warn("smtpd: socket"); - continue; - } - fatal("smtpd: socket"); - } - opt = 1; -#ifdef SO_REUSEADDR - if (setsockopt(l->fd, SOL_SOCKET, SO_REUSEADDR, &opt, - sizeof(opt)) == -1) - fatal("smtpd: setsockopt"); -#else - if (setsockopt(l->fd, SOL_SOCKET, SO_REUSEPORT, &opt, - sizeof(opt)) < 0) - fatal("smtpd: setsockopt"); -#endif -#ifdef IPV6_V6ONLY - /* - * If using IPv6, bind only to IPv6 if possible. - * This avoids ambiguities with IPv4-mapped IPv6 addresses. - */ - if (l->ss.ss_family == AF_INET6) - if (setsockopt(l->fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, - sizeof(opt)) < 0) - fatal("smtpd: setsockopt"); -#endif - if (bind(l->fd, (struct sockaddr *)&l->ss, SS_LEN(&l->ss)) == -1) - fatal("smtpd: bind"); - } -} - -static void -smtp_setup_events(void) -{ - struct listener *l; - struct pki *pki; - SSL_CTX *ssl_ctx; - void *iter; - const char *k; - - TAILQ_FOREACH(l, env->sc_listeners, entry) { - log_debug("debug: smtp: listen on %s port %d flags 0x%01x" - " pki \"%s\"" - " ca \"%s\"", ss_to_text(&l->ss), ntohs(l->port), - l->flags, l->pki_name, l->ca_name); - - io_set_nonblocking(l->fd); - if (listen(l->fd, SMTPD_BACKLOG) == -1) - fatal("listen"); - event_set(&l->ev, l->fd, EV_READ|EV_PERSIST, smtp_accept, l); - - if (!(env->sc_flags & SMTPD_SMTP_PAUSED)) - event_add(&l->ev, NULL); - } - - iter = NULL; - while (dict_iter(env->sc_pki_dict, &iter, &k, (void **)&pki)) { - if (!ssl_setup((SSL_CTX **)&ssl_ctx, pki, smtp_sni_callback, - env->sc_tls_ciphers)) - fatal("smtp_setup_events: ssl_setup failure"); - dict_xset(env->sc_ssl_dict, k, ssl_ctx); - } - - purge_config(PURGE_PKI_KEYS); - - maxsessions = (getdtablesize() - getdtablecount()) / 2 - SMTP_FD_RESERVE; - log_debug("debug: smtp: will accept at most %zu clients", maxsessions); -} - -static void -smtp_pause(void) -{ - struct listener *l; - - if (env->sc_flags & (SMTPD_SMTP_DISABLED|SMTPD_SMTP_PAUSED)) - return; - - TAILQ_FOREACH(l, env->sc_listeners, entry) - event_del(&l->ev); -} - -static void -smtp_resume(void) -{ - struct listener *l; - - if (env->sc_flags & (SMTPD_SMTP_DISABLED|SMTPD_SMTP_PAUSED)) - return; - - TAILQ_FOREACH(l, env->sc_listeners, entry) - event_add(&l->ev, NULL); -} - -static int -smtp_enqueue(void) -{ - struct listener *listener = env->sc_sock_listener; - int fd[2]; - - /* - * Some enqueue requests buffered in IMSG may still arrive even after - * call to smtp_pause() because enqueue listener is not a real socket - * and thus cannot be paused properly. - */ - if (env->sc_flags & SMTPD_SMTP_PAUSED) - return (-1); - - if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fd)) - return (-1); - - if ((smtp_session(listener, fd[0], &listener->ss, env->sc_hostname, NULL)) == -1) { - close(fd[0]); - close(fd[1]); - return (-1); - } - - sessions++; - stat_increment("smtp.session", 1); - stat_increment("smtp.session.local", 1); - - return (fd[1]); -} - -static void -smtp_accept(int fd, short event, void *p) -{ - struct listener *listener = p; - struct sockaddr_storage ss; - socklen_t len; - int sock; - - if (env->sc_flags & SMTPD_SMTP_PAUSED) - fatalx("smtp_session: unexpected client"); - - if (!smtp_can_accept()) { - log_warnx("warn: Disabling incoming SMTP connections: " - "Client limit reached"); - goto pause; - } - - len = sizeof(ss); - if ((sock = accept(fd, (struct sockaddr *)&ss, &len)) == -1) { - if (errno == ENFILE || errno == EMFILE) { - log_warn("warn: Disabling incoming SMTP connections"); - goto pause; - } - if (errno == EINTR || errno == EWOULDBLOCK || - errno == ECONNABORTED) - return; - fatal("smtp_accept"); - } - - if (listener->flags & F_PROXY) { - io_set_nonblocking(sock); - if (proxy_session(listener, sock, &ss, - smtp_accepted, smtp_dropped) == -1) { - close(sock); - return; - } - return; - } - - smtp_accepted(listener, sock, &ss, NULL); - return; - -pause: - smtp_pause(); - env->sc_flags |= SMTPD_SMTP_DISABLED; - return; -} - -static int -smtp_can_accept(void) -{ - if (sessions + 1 == maxsessions) - return 0; - return (getdtablesize() - getdtablecount() - SMTP_FD_RESERVE >= 2); -} - -void -smtp_collect(void) -{ - sessions--; - stat_decrement("smtp.session", 1); - - if (!smtp_can_accept()) - return; - - if (env->sc_flags & SMTPD_SMTP_DISABLED) { - log_warnx("warn: smtp: " - "fd exhaustion over, re-enabling incoming connections"); - env->sc_flags &= ~SMTPD_SMTP_DISABLED; - smtp_resume(); - } -} - -static int -smtp_sni_callback(SSL *ssl, int *ad, void *arg) -{ - const char *sn; - void *ssl_ctx; - - sn = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); - if (sn == NULL) - return SSL_TLSEXT_ERR_NOACK; - ssl_ctx = dict_get(env->sc_ssl_dict, sn); - if (ssl_ctx == NULL) - return SSL_TLSEXT_ERR_NOACK; - SSL_set_SSL_CTX(ssl, ssl_ctx); - return SSL_TLSEXT_ERR_OK; -} - -static void -smtp_accepted(struct listener *listener, int sock, const struct sockaddr_storage *ss, struct io *io) -{ - int ret; - - ret = smtp_session(listener, sock, ss, NULL, io); - if (ret == -1) { - log_warn("warn: Failed to create SMTP session"); - close(sock); - return; - } - io_set_nonblocking(sock); - - sessions++; - stat_increment("smtp.session", 1); - if (listener->ss.ss_family == AF_LOCAL) - stat_increment("smtp.session.local", 1); - if (listener->ss.ss_family == AF_INET) - stat_increment("smtp.session.inet4", 1); - if (listener->ss.ss_family == AF_INET6) - stat_increment("smtp.session.inet6", 1); -} - -static void -smtp_dropped(struct listener *listener, int sock, const struct sockaddr_storage *ss) -{ - close(sock); - sessions--; -} |