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