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