1 /* $OpenBSD: smtp.c,v 1.167 2021/03/05 12:37:32 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 struct pki *pki; 173 struct ca *ca; 174 int i; 175 176 if ((config = tls_config_new()) == NULL) 177 fatal("smtpd: tls_config_new"); 178 179 if (env->sc_tls_ciphers && 180 tls_config_set_ciphers(config, env->sc_tls_ciphers) == -1) 181 err(1, "%s", tls_config_error(config)); 182 183 pki = l->pki[0]; 184 if (pki == NULL) 185 fatal("no pki defined"); 186 187 if (tls_config_set_dheparams(config, dheparams[pki->pki_dhe]) == -1) 188 fatal("tls_config_set_dheparams"); 189 190 tls_config_use_fake_private_key(config); 191 for (i = 0; i < l->pkicount; i++) { 192 pki = l->pki[i]; 193 if (i == 0) { 194 if (tls_config_set_keypair_mem(config, pki->pki_cert, 195 pki->pki_cert_len, NULL, 0) == -1) 196 fatal("tls_config_set_keypair_mem"); 197 } else { 198 if (tls_config_add_keypair_mem(config, pki->pki_cert, 199 pki->pki_cert_len, NULL, 0) == -1) 200 fatal("tls_config_add_keypair_mem"); 201 } 202 } 203 free(l->pki); 204 l->pkicount = 0; 205 206 if (l->ca_name[0]) { 207 ca = dict_get(env->sc_ca_dict, l->ca_name); 208 if (tls_config_set_ca_mem(config, ca->ca_cert, ca->ca_cert_len) 209 == -1) 210 fatal("tls_config_set_ca_mem"); 211 } 212 else if (tls_config_set_ca_file(config, tls_default_ca_cert_file()) 213 == -1) 214 fatal("tls_config_set_ca_file"); 215 216 if (l->flags & F_TLS_VERIFY) 217 tls_config_verify_client(config); 218 else 219 tls_config_verify_client_optional(config); 220 221 l->tls = tls_server(); 222 if (l->tls == NULL) 223 fatal("tls_server"); 224 if (tls_configure(l->tls, config) == -1) { 225 fatal("tls_configure: %s", tls_error(l->tls)); 226 } 227 tls_config_free(config); 228 } 229 230 231 static void 232 smtp_setup_events(void) 233 { 234 struct listener *l; 235 236 TAILQ_FOREACH(l, env->sc_listeners, entry) { 237 log_debug("debug: smtp: listen on %s port %d flags 0x%01x", 238 ss_to_text(&l->ss), ntohs(l->port), l->flags); 239 240 io_set_nonblocking(l->fd); 241 if (listen(l->fd, SMTPD_BACKLOG) == -1) 242 fatal("listen"); 243 event_set(&l->ev, l->fd, EV_READ|EV_PERSIST, smtp_accept, l); 244 245 if (!(env->sc_flags & SMTPD_SMTP_PAUSED)) 246 event_add(&l->ev, NULL); 247 } 248 249 purge_config(PURGE_PKI_KEYS); 250 251 maxsessions = (getdtablesize() - getdtablecount()) / 2 - SMTP_FD_RESERVE; 252 log_debug("debug: smtp: will accept at most %zu clients", maxsessions); 253 } 254 255 static void 256 smtp_pause(void) 257 { 258 struct listener *l; 259 260 if (env->sc_flags & (SMTPD_SMTP_DISABLED|SMTPD_SMTP_PAUSED)) 261 return; 262 263 TAILQ_FOREACH(l, env->sc_listeners, entry) 264 event_del(&l->ev); 265 } 266 267 static void 268 smtp_resume(void) 269 { 270 struct listener *l; 271 272 if (env->sc_flags & (SMTPD_SMTP_DISABLED|SMTPD_SMTP_PAUSED)) 273 return; 274 275 TAILQ_FOREACH(l, env->sc_listeners, entry) 276 event_add(&l->ev, NULL); 277 } 278 279 static int 280 smtp_enqueue(void) 281 { 282 struct listener *listener = env->sc_sock_listener; 283 int fd[2]; 284 285 /* 286 * Some enqueue requests buffered in IMSG may still arrive even after 287 * call to smtp_pause() because enqueue listener is not a real socket 288 * and thus cannot be paused properly. 289 */ 290 if (env->sc_flags & SMTPD_SMTP_PAUSED) 291 return (-1); 292 293 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fd)) 294 return (-1); 295 296 if ((smtp_session(listener, fd[0], &listener->ss, env->sc_hostname, NULL)) == -1) { 297 close(fd[0]); 298 close(fd[1]); 299 return (-1); 300 } 301 302 sessions++; 303 stat_increment("smtp.session", 1); 304 stat_increment("smtp.session.local", 1); 305 306 return (fd[1]); 307 } 308 309 static void 310 smtp_accept(int fd, short event, void *p) 311 { 312 struct listener *listener = p; 313 struct sockaddr_storage ss; 314 socklen_t len; 315 int sock; 316 317 if (env->sc_flags & SMTPD_SMTP_PAUSED) 318 fatalx("smtp_session: unexpected client"); 319 320 if (!smtp_can_accept()) { 321 log_warnx("warn: Disabling incoming SMTP connections: " 322 "Client limit reached"); 323 goto pause; 324 } 325 326 len = sizeof(ss); 327 if ((sock = accept(fd, (struct sockaddr *)&ss, &len)) == -1) { 328 if (errno == ENFILE || errno == EMFILE) { 329 log_warn("warn: Disabling incoming SMTP connections"); 330 goto pause; 331 } 332 if (errno == EINTR || errno == EWOULDBLOCK || 333 errno == ECONNABORTED) 334 return; 335 fatal("smtp_accept"); 336 } 337 338 if (listener->flags & F_PROXY) { 339 io_set_nonblocking(sock); 340 if (proxy_session(listener, sock, &ss, 341 smtp_accepted, smtp_dropped) == -1) { 342 close(sock); 343 return; 344 } 345 return; 346 } 347 348 smtp_accepted(listener, sock, &ss, NULL); 349 return; 350 351 pause: 352 smtp_pause(); 353 env->sc_flags |= SMTPD_SMTP_DISABLED; 354 return; 355 } 356 357 static int 358 smtp_can_accept(void) 359 { 360 if (sessions + 1 == maxsessions) 361 return 0; 362 return (getdtablesize() - getdtablecount() - SMTP_FD_RESERVE >= 2); 363 } 364 365 void 366 smtp_collect(void) 367 { 368 sessions--; 369 stat_decrement("smtp.session", 1); 370 371 if (!smtp_can_accept()) 372 return; 373 374 if (env->sc_flags & SMTPD_SMTP_DISABLED) { 375 log_warnx("warn: smtp: " 376 "fd exhaustion over, re-enabling incoming connections"); 377 env->sc_flags &= ~SMTPD_SMTP_DISABLED; 378 smtp_resume(); 379 } 380 } 381 382 static void 383 smtp_accepted(struct listener *listener, int sock, const struct sockaddr_storage *ss, struct io *io) 384 { 385 int ret; 386 387 ret = smtp_session(listener, sock, ss, NULL, io); 388 if (ret == -1) { 389 log_warn("warn: Failed to create SMTP session"); 390 close(sock); 391 return; 392 } 393 io_set_nonblocking(sock); 394 395 sessions++; 396 stat_increment("smtp.session", 1); 397 if (listener->ss.ss_family == AF_LOCAL) 398 stat_increment("smtp.session.local", 1); 399 if (listener->ss.ss_family == AF_INET) 400 stat_increment("smtp.session.inet4", 1); 401 if (listener->ss.ss_family == AF_INET6) 402 stat_increment("smtp.session.inet6", 1); 403 } 404 405 static void 406 smtp_dropped(struct listener *listener, int sock, const struct sockaddr_storage *ss) 407 { 408 close(sock); 409 sessions--; 410 } 411