aboutsummaryrefslogtreecommitdiffstats
path: root/smtpd/smtp.c
diff options
context:
space:
mode:
Diffstat (limited to 'smtpd/smtp.c')
-rw-r--r--smtpd/smtp.c387
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--;
-}