1 /* $OpenBSD: smtp.c,v 1.91 2011/09/01 20:17:47 gilles Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.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/param.h> 25 #include <sys/socket.h> 26 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 <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <unistd.h> 37 38 #include "smtpd.h" 39 #include "log.h" 40 41 static void smtp_imsg(struct imsgev *, struct imsg *); 42 static void smtp_shutdown(void); 43 static void smtp_sig_handler(int, short, void *); 44 static void smtp_setup_events(void); 45 static void smtp_disable_events(void); 46 static void smtp_pause(void); 47 static int smtp_enqueue(uid_t *); 48 static void smtp_accept(int, short, void *); 49 static struct session *smtp_new(struct listener *); 50 static struct session *session_lookup(u_int64_t); 51 52 53 static void 54 smtp_imsg(struct imsgev *iev, struct imsg *imsg) 55 { 56 struct session skey; 57 struct submit_status *ss; 58 struct listener *l; 59 struct session *s; 60 struct auth *auth; 61 struct ssl *ssl; 62 struct dns *dns; 63 64 if (iev->proc == PROC_LKA) { 65 switch (imsg->hdr.type) { 66 case IMSG_DNS_PTR: 67 dns = imsg->data; 68 s = session_lookup(dns->id); 69 if (s == NULL) 70 fatalx("smtp: impossible quit"); 71 strlcpy(s->s_hostname, 72 dns->error ? "<unknown>" : dns->host, 73 sizeof s->s_hostname); 74 strlcpy(s->s_msg.delivery.hostname, s->s_hostname, 75 sizeof s->s_msg.delivery.hostname); 76 session_init(s->s_l, s); 77 return; 78 } 79 } 80 81 if (iev->proc == PROC_MFA) { 82 switch (imsg->hdr.type) { 83 case IMSG_MFA_HELO: 84 case IMSG_MFA_MAIL: 85 case IMSG_MFA_RCPT: 86 log_debug("smtp: got imsg_mfa_helo/mail/rcpt"); 87 case IMSG_MFA_DATALINE: 88 ss = imsg->data; 89 s = session_lookup(ss->id); 90 if (s == NULL) 91 return; 92 session_pickup(s, ss); 93 return; 94 } 95 } 96 97 if (iev->proc == PROC_QUEUE) { 98 ss = imsg->data; 99 100 switch (imsg->hdr.type) { 101 case IMSG_QUEUE_CREATE_MESSAGE: 102 log_debug("smtp: imsg_queue_create_message returned"); 103 s = session_lookup(ss->id); 104 if (s == NULL) 105 return; 106 s->s_msg.delivery.id = (u_int64_t)ss->u.msgid << 32; 107 session_pickup(s, ss); 108 return; 109 110 case IMSG_QUEUE_MESSAGE_FILE: 111 log_debug("smtp: imsg_queue_message_file returned"); 112 s = session_lookup(ss->id); 113 if (s == NULL) { 114 close(imsg->fd); 115 return; 116 } 117 s->datafp = fdopen(imsg->fd, "w"); 118 if (s->datafp == NULL) { 119 /* queue may have experienced tempfail. */ 120 if (ss->code != 421) 121 fatalx("smtp: fdopen"); 122 close(imsg->fd); 123 } 124 session_pickup(s, ss); 125 return; 126 127 case IMSG_QUEUE_TEMPFAIL: 128 log_debug("smtp: got imsg_queue_tempfail"); 129 skey.s_id = ss->id; 130 s = SPLAY_FIND(sessiontree, &env->sc_sessions, &skey); 131 if (s == NULL) 132 fatalx("smtp: session is gone"); 133 if (s->s_flags & F_WRITEONLY) 134 /* session is write-only, must not destroy it. */ 135 s->s_msg.delivery.status |= DS_TEMPFAILURE; 136 else 137 fatalx("smtp: corrupt session"); 138 return; 139 140 case IMSG_QUEUE_COMMIT_ENVELOPES: 141 log_debug("smtp: got imsg_queue_commit_envelopes"); 142 s = session_lookup(ss->id); 143 if (s == NULL) 144 return; 145 session_pickup(s, ss); 146 return; 147 148 case IMSG_QUEUE_COMMIT_MESSAGE: 149 log_debug("smtp: got imsg_queue_commit_message"); 150 s = session_lookup(ss->id); 151 if (s == NULL) 152 return; 153 session_pickup(s, ss); 154 return; 155 156 case IMSG_SMTP_ENQUEUE: 157 imsg_compose_event(iev, IMSG_SMTP_ENQUEUE, 0, 0, 158 smtp_enqueue(NULL), imsg->data, 159 sizeof(struct envelope)); 160 return; 161 } 162 } 163 164 if (iev->proc == PROC_PARENT) { 165 switch (imsg->hdr.type) { 166 case IMSG_CONF_RELOAD: 167 /* 168 * Reloading may invalidate various pointers our 169 * sessions rely upon, we better tell clients we 170 * want them to retry. 171 */ 172 SPLAY_FOREACH(s, sessiontree, &env->sc_sessions) { 173 s->s_l = NULL; 174 s->s_msg.delivery.status |= DS_TEMPFAILURE; 175 } 176 if (env->sc_listeners) 177 smtp_disable_events(); 178 imsg_compose_event(iev, IMSG_PARENT_SEND_CONFIG, 0, 0, -1, 179 NULL, 0); 180 return; 181 182 case IMSG_CONF_START: 183 if (env->sc_flags & SMTPD_CONFIGURING) 184 return; 185 env->sc_flags |= SMTPD_CONFIGURING; 186 env->sc_listeners = calloc(1, sizeof *env->sc_listeners); 187 env->sc_ssl = calloc(1, sizeof *env->sc_ssl); 188 if (env->sc_listeners == NULL || env->sc_ssl == NULL) 189 fatal(NULL); 190 TAILQ_INIT(env->sc_listeners); 191 return; 192 193 case IMSG_CONF_SSL: 194 if (!(env->sc_flags & SMTPD_CONFIGURING)) 195 return; 196 ssl = calloc(1, sizeof *ssl); 197 if (ssl == NULL) 198 fatal(NULL); 199 *ssl = *(struct ssl *)imsg->data; 200 ssl->ssl_cert = strdup((char *)imsg->data + 201 sizeof *ssl); 202 if (ssl->ssl_cert == NULL) 203 fatal(NULL); 204 ssl->ssl_key = strdup((char *)imsg->data + sizeof *ssl + 205 ssl->ssl_cert_len); 206 if (ssl->ssl_key == NULL) 207 fatal(NULL); 208 if (ssl->ssl_dhparams_len) { 209 ssl->ssl_dhparams = strdup((char *)imsg->data 210 + sizeof *ssl + ssl->ssl_cert_len + 211 ssl->ssl_key_len); 212 if (ssl->ssl_dhparams == NULL) 213 fatal(NULL); 214 } 215 SPLAY_INSERT(ssltree, env->sc_ssl, ssl); 216 return; 217 218 case IMSG_CONF_LISTENER: 219 if (!(env->sc_flags & SMTPD_CONFIGURING)) 220 return; 221 l = calloc(1, sizeof *l); 222 if (l == NULL) 223 fatal(NULL); 224 *l = *(struct listener *)imsg->data; 225 l->fd = imsg->fd; 226 if (l->fd < 0) 227 fatalx("smtp: listener pass failed"); 228 if (l->flags & F_SSL) { 229 struct ssl key; 230 231 strlcpy(key.ssl_name, l->ssl_cert_name, 232 sizeof key.ssl_name); 233 l->ssl = SPLAY_FIND(ssltree, env->sc_ssl, &key); 234 if (l->ssl == NULL) 235 fatalx("smtp: ssltree out of sync"); 236 } 237 TAILQ_INSERT_TAIL(env->sc_listeners, l, entry); 238 return; 239 240 case IMSG_CONF_END: 241 if (!(env->sc_flags & SMTPD_CONFIGURING)) 242 return; 243 smtp_setup_events(); 244 env->sc_flags &= ~SMTPD_CONFIGURING; 245 return; 246 247 case IMSG_PARENT_AUTHENTICATE: 248 auth = imsg->data; 249 s = session_lookup(auth->id); 250 if (s == NULL) 251 return; 252 if (auth->success) { 253 s->s_flags |= F_AUTHENTICATED; 254 s->s_msg.delivery.flags |= DF_AUTHENTICATED; 255 } else { 256 s->s_flags &= ~F_AUTHENTICATED; 257 s->s_msg.delivery.flags &= ~DF_AUTHENTICATED; 258 } 259 session_pickup(s, NULL); 260 return; 261 262 case IMSG_CTL_VERBOSE: 263 log_verbose(*(int *)imsg->data); 264 return; 265 } 266 } 267 268 if (iev->proc == PROC_CONTROL) { 269 switch (imsg->hdr.type) { 270 case IMSG_SMTP_ENQUEUE: 271 imsg_compose_event(iev, IMSG_SMTP_ENQUEUE, 272 imsg->hdr.peerid, 0, smtp_enqueue(imsg->data), 273 NULL, 0); 274 return; 275 276 case IMSG_SMTP_PAUSE: 277 smtp_pause(); 278 return; 279 280 case IMSG_SMTP_RESUME: 281 smtp_resume(); 282 return; 283 } 284 } 285 286 fatalx("smtp_imsg: unexpected imsg"); 287 } 288 289 static void 290 smtp_sig_handler(int sig, short event, void *p) 291 { 292 switch (sig) { 293 case SIGINT: 294 case SIGTERM: 295 smtp_shutdown(); 296 break; 297 default: 298 fatalx("smtp_sig_handler: unexpected signal"); 299 } 300 } 301 302 static void 303 smtp_shutdown(void) 304 { 305 log_info("smtp server exiting"); 306 _exit(0); 307 } 308 309 pid_t 310 smtp(void) 311 { 312 pid_t pid; 313 struct passwd *pw; 314 315 struct event ev_sigint; 316 struct event ev_sigterm; 317 318 struct peer peers[] = { 319 { PROC_PARENT, imsg_dispatch }, 320 { PROC_MFA, imsg_dispatch }, 321 { PROC_QUEUE, imsg_dispatch }, 322 { PROC_LKA, imsg_dispatch }, 323 { PROC_CONTROL, imsg_dispatch } 324 }; 325 326 switch (pid = fork()) { 327 case -1: 328 fatal("smtp: cannot fork"); 329 case 0: 330 break; 331 default: 332 return (pid); 333 } 334 335 ssl_init(); 336 purge_config(PURGE_EVERYTHING); 337 338 pw = env->sc_pw; 339 340 if (chroot(pw->pw_dir) == -1) 341 fatal("smtp: chroot"); 342 if (chdir("/") == -1) 343 fatal("smtp: chdir(\"/\")"); 344 345 smtpd_process = PROC_SMTP; 346 setproctitle("%s", env->sc_title[smtpd_process]); 347 348 if (setgroups(1, &pw->pw_gid) || 349 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 350 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 351 fatal("smtp: cannot drop privileges"); 352 353 imsg_callback = smtp_imsg; 354 event_init(); 355 356 signal_set(&ev_sigint, SIGINT, smtp_sig_handler, NULL); 357 signal_set(&ev_sigterm, SIGTERM, smtp_sig_handler, NULL); 358 signal_add(&ev_sigint, NULL); 359 signal_add(&ev_sigterm, NULL); 360 signal(SIGPIPE, SIG_IGN); 361 signal(SIGHUP, SIG_IGN); 362 363 /* Initial limit for use by IMSG_SMTP_ENQUEUE, will be tuned later once 364 * the listening sockets arrive. */ 365 env->sc_maxconn = availdesc() / 2; 366 367 config_pipes(peers, nitems(peers)); 368 config_peers(peers, nitems(peers)); 369 370 if (event_dispatch() < 0) 371 fatal("event_dispatch"); 372 smtp_shutdown(); 373 374 return (0); 375 } 376 377 static void 378 smtp_setup_events(void) 379 { 380 struct listener *l; 381 int avail = availdesc(); 382 383 TAILQ_FOREACH(l, env->sc_listeners, entry) { 384 log_debug("smtp_setup_events: listen on %s port %d flags 0x%01x" 385 " cert \"%s\"", ss_to_text(&l->ss), ntohs(l->port), 386 l->flags, l->ssl_cert_name); 387 388 session_socket_blockmode(l->fd, BM_NONBLOCK); 389 if (listen(l->fd, SMTPD_BACKLOG) == -1) 390 fatal("listen"); 391 event_set(&l->ev, l->fd, EV_READ|EV_PERSIST, smtp_accept, l); 392 event_add(&l->ev, NULL); 393 ssl_setup(l); 394 avail--; 395 } 396 397 /* guarantee 2 fds to each accepted client */ 398 if ((env->sc_maxconn = avail / 2) < 1) 399 fatalx("smtp_setup_events: fd starvation"); 400 401 log_debug("smtp: will accept at most %d clients", env->sc_maxconn); 402 } 403 404 static void 405 smtp_disable_events(void) 406 { 407 struct listener *l; 408 409 log_debug("smtp_disable_events: closing listening sockets"); 410 while ((l = TAILQ_FIRST(env->sc_listeners)) != NULL) { 411 TAILQ_REMOVE(env->sc_listeners, l, entry); 412 event_del(&l->ev); 413 close(l->fd); 414 free(l); 415 } 416 free(env->sc_listeners); 417 env->sc_listeners = NULL; 418 env->sc_maxconn = 0; 419 } 420 421 static void 422 smtp_pause(void) 423 { 424 struct listener *l; 425 426 log_debug("smtp_pause: pausing listening sockets"); 427 env->sc_opts |= SMTPD_SMTP_PAUSED; 428 429 TAILQ_FOREACH(l, env->sc_listeners, entry) 430 event_del(&l->ev); 431 } 432 433 void 434 smtp_resume(void) 435 { 436 struct listener *l; 437 438 log_debug("smtp_resume: resuming listening sockets"); 439 env->sc_opts &= ~SMTPD_SMTP_PAUSED; 440 441 TAILQ_FOREACH(l, env->sc_listeners, entry) 442 event_add(&l->ev, NULL); 443 } 444 445 static int 446 smtp_enqueue(uid_t *euid) 447 { 448 static struct listener local, *l; 449 static struct sockaddr_storage sa; 450 struct session *s; 451 int fd[2]; 452 453 if (l == NULL) { 454 struct addrinfo hints, *res; 455 456 l = &local; 457 strlcpy(l->tag, "local", sizeof(l->tag)); 458 459 bzero(&hints, sizeof(hints)); 460 hints.ai_family = PF_UNSPEC; 461 hints.ai_flags = AI_NUMERICHOST; 462 463 if (getaddrinfo("::1", NULL, &hints, &res)) 464 fatal("getaddrinfo"); 465 memcpy(&sa, res->ai_addr, res->ai_addrlen); 466 freeaddrinfo(res); 467 } 468 469 /* 470 * Some enqueue requests buffered in IMSG may still arrive even after 471 * call to smtp_pause() because enqueue listener is not a real socket 472 * and thus cannot be paused properly. 473 */ 474 if (env->sc_opts & SMTPD_SMTP_PAUSED) 475 return (-1); 476 477 if ((s = smtp_new(l)) == NULL) 478 return (-1); 479 480 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fd)) 481 fatal("socketpair"); 482 483 s->s_fd = fd[0]; 484 s->s_ss = sa; 485 s->s_msg.delivery.flags |= DF_ENQUEUED; 486 487 if (euid) 488 bsnprintf(s->s_hostname, sizeof(s->s_hostname), "%d@localhost", 489 *euid); 490 else { 491 strlcpy(s->s_hostname, "localhost", sizeof(s->s_hostname)); 492 s->s_msg.delivery.flags |= DF_BOUNCE; 493 } 494 495 strlcpy(s->s_msg.delivery.hostname, s->s_hostname, 496 sizeof(s->s_msg.delivery.hostname)); 497 498 session_init(l, s); 499 500 return (fd[1]); 501 } 502 503 static void 504 smtp_accept(int fd, short event, void *p) 505 { 506 struct listener *l = p; 507 struct session *s; 508 socklen_t len; 509 510 if ((s = smtp_new(l)) == NULL) 511 return; 512 513 len = sizeof(s->s_ss); 514 if ((s->s_fd = accept(fd, (struct sockaddr *)&s->s_ss, &len)) == -1) { 515 if (errno == EINTR || errno == ECONNABORTED) 516 return; 517 fatal("smtp_accept"); 518 } 519 520 521 s->s_flags |= F_WRITEONLY; 522 dns_query_ptr(&s->s_ss, s->s_id); 523 } 524 525 526 static struct session * 527 smtp_new(struct listener *l) 528 { 529 struct session *s; 530 531 log_debug("smtp_new: incoming client on listener: %p", l); 532 533 if (env->sc_opts & SMTPD_SMTP_PAUSED) 534 fatalx("smtp_new: unexpected client"); 535 536 if ((s = calloc(1, sizeof(*s))) == NULL) 537 fatal(NULL); 538 s->s_id = generate_uid(); 539 s->s_l = l; 540 strlcpy(s->s_msg.tag, l->tag, sizeof(s->s_msg.tag)); 541 SPLAY_INSERT(sessiontree, &env->sc_sessions, s); 542 543 if (stat_increment(STATS_SMTP_SESSION) >= env->sc_maxconn) { 544 log_warnx("client limit hit, disabling incoming connections"); 545 smtp_pause(); 546 } 547 548 if (s->s_l->ss.ss_family == AF_INET) 549 stat_increment(STATS_SMTP_SESSION_INET4); 550 if (s->s_l->ss.ss_family == AF_INET6) 551 stat_increment(STATS_SMTP_SESSION_INET6); 552 553 return (s); 554 } 555 556 /* 557 * Helper function for handling IMSG replies. 558 */ 559 static struct session * 560 session_lookup(u_int64_t id) 561 { 562 struct session key; 563 struct session *s; 564 565 key.s_id = id; 566 s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key); 567 if (s == NULL) 568 fatalx("session_lookup: session is gone"); 569 570 if (!(s->s_flags & F_WRITEONLY)) 571 fatalx("session_lookup: corrupt session"); 572 s->s_flags &= ~F_WRITEONLY; 573 574 if (s->s_flags & F_QUIT) { 575 session_destroy(s); 576 s = NULL; 577 } 578 579 return (s); 580 } 581