1 /* $OpenBSD: smtp.c,v 1.64 2009/11/08 21:40:05 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 <ctype.h> 28 #include <event.h> 29 #include <netdb.h> 30 #include <pwd.h> 31 #include <signal.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <time.h> 36 #include <unistd.h> 37 38 #include "smtpd.h" 39 40 __dead void smtp_shutdown(void); 41 void smtp_sig_handler(int, short, void *); 42 void smtp_dispatch_parent(int, short, void *); 43 void smtp_dispatch_mfa(int, short, void *); 44 void smtp_dispatch_lka(int, short, void *); 45 void smtp_dispatch_queue(int, short, void *); 46 void smtp_dispatch_control(int, short, void *); 47 void smtp_dispatch_runner(int, short, void *); 48 void smtp_setup_events(struct smtpd *); 49 void smtp_disable_events(struct smtpd *); 50 void smtp_pause(struct smtpd *); 51 void smtp_resume(struct smtpd *); 52 void smtp_accept(int, short, void *); 53 void session_auth_pickup(struct session *, char *, size_t); 54 struct session *session_lookup(struct smtpd *, u_int64_t); 55 56 void 57 smtp_sig_handler(int sig, short event, void *p) 58 { 59 switch (sig) { 60 case SIGINT: 61 case SIGTERM: 62 smtp_shutdown(); 63 break; 64 default: 65 fatalx("smtp_sig_handler: unexpected signal"); 66 } 67 } 68 69 void 70 smtp_dispatch_parent(int sig, short event, void *p) 71 { 72 struct smtpd *env = p; 73 struct imsgev *iev; 74 struct imsgbuf *ibuf; 75 struct imsg imsg; 76 ssize_t n; 77 78 iev = env->sc_ievs[PROC_PARENT]; 79 ibuf = &iev->ibuf; 80 81 82 if (event & EV_READ) { 83 if ((n = imsg_read(ibuf)) == -1) 84 fatal("imsg_read_error"); 85 if (n == 0) { 86 /* this pipe is dead, so remove the event handler */ 87 event_del(&iev->ev); 88 event_loopexit(NULL); 89 return; 90 } 91 } 92 93 if (event & EV_WRITE) { 94 if (msgbuf_write(&ibuf->w) == -1) 95 fatal("msgbuf_write"); 96 } 97 98 for (;;) { 99 if ((n = imsg_get(ibuf, &imsg)) == -1) 100 fatal("smtp_dispatch_parent: imsg_get error"); 101 if (n == 0) 102 break; 103 104 switch (imsg.hdr.type) { 105 case IMSG_CONF_RELOAD: { 106 struct session *s; 107 108 /* reloading may invalidate various pointers our 109 * sessions rely upon, we better tell clients we 110 * want them to retry. 111 */ 112 SPLAY_FOREACH(s, sessiontree, &env->sc_sessions) { 113 s->s_l = NULL; 114 s->s_msg.status |= S_MESSAGE_TEMPFAILURE; 115 } 116 if (env->sc_listeners) 117 smtp_disable_events(env); 118 imsg_compose_event(iev, IMSG_PARENT_SEND_CONFIG, 0, 0, -1, 119 NULL, 0); 120 break; 121 } 122 case IMSG_CONF_START: 123 if (env->sc_flags & SMTPD_CONFIGURING) 124 break; 125 env->sc_flags |= SMTPD_CONFIGURING; 126 127 if ((env->sc_listeners = calloc(1, sizeof(*env->sc_listeners))) == NULL) 128 fatal("smtp_dispatch_parent: calloc"); 129 if ((env->sc_ssl = calloc(1, sizeof(*env->sc_ssl))) == NULL) 130 fatal("smtp_dispatch_parent: calloc"); 131 TAILQ_INIT(env->sc_listeners); 132 break; 133 case IMSG_CONF_SSL: { 134 struct ssl *s; 135 struct ssl *x_ssl; 136 137 if (!(env->sc_flags & SMTPD_CONFIGURING)) 138 break; 139 140 if ((s = calloc(1, sizeof(*s))) == NULL) 141 fatal(NULL); 142 x_ssl = imsg.data; 143 (void)strlcpy(s->ssl_name, x_ssl->ssl_name, 144 sizeof(s->ssl_name)); 145 s->ssl_cert_len = x_ssl->ssl_cert_len; 146 if ((s->ssl_cert = 147 strdup((char *)imsg.data + sizeof(*s))) == NULL) 148 fatal(NULL); 149 s->ssl_key_len = x_ssl->ssl_key_len; 150 if ((s->ssl_key = strdup((char *)imsg.data + 151 (sizeof(*s) + s->ssl_cert_len))) == NULL) 152 fatal(NULL); 153 154 SPLAY_INSERT(ssltree, env->sc_ssl, s); 155 break; 156 } 157 case IMSG_CONF_LISTENER: { 158 struct listener *l; 159 struct ssl key; 160 161 if (!(env->sc_flags & SMTPD_CONFIGURING)) 162 break; 163 164 if ((l = calloc(1, sizeof(*l))) == NULL) 165 fatal(NULL); 166 memcpy(l, imsg.data, sizeof(*l)); 167 168 if ((l->fd = imsg.fd) == -1) 169 fatal("cannot get fd"); 170 171 (void)strlcpy(key.ssl_name, l->ssl_cert_name, 172 sizeof(key.ssl_name)); 173 174 if (l->flags & F_SSL) 175 if ((l->ssl = SPLAY_FIND(ssltree, 176 env->sc_ssl, &key)) == NULL) 177 fatal("parent and smtp desynchronized"); 178 179 TAILQ_INSERT_TAIL(env->sc_listeners, l, entry); 180 break; 181 } 182 case IMSG_CONF_END: 183 if (!(env->sc_flags & SMTPD_CONFIGURING)) 184 break; 185 smtp_setup_events(env); 186 env->sc_flags &= ~SMTPD_CONFIGURING; 187 break; 188 case IMSG_PARENT_AUTHENTICATE: { 189 struct auth *reply = imsg.data; 190 struct session *s; 191 192 log_debug("smtp_dispatch_parent: got auth reply"); 193 194 IMSG_SIZE_CHECK(reply); 195 196 if ((s = session_lookup(env, reply->id)) == NULL) 197 break; 198 199 if (reply->success) { 200 s->s_flags |= F_AUTHENTICATED; 201 s->s_msg.flags |= F_MESSAGE_AUTHENTICATED; 202 } else { 203 s->s_flags &= ~F_AUTHENTICATED; 204 s->s_msg.flags &= ~F_MESSAGE_AUTHENTICATED; 205 } 206 207 session_pickup(s, NULL); 208 break; 209 } 210 default: 211 log_warnx("smtp_dispatch_parent: got imsg %d", 212 imsg.hdr.type); 213 fatalx("smtp_dispatch_parent: unexpected imsg"); 214 } 215 imsg_free(&imsg); 216 } 217 imsg_event_add(iev); 218 } 219 220 void 221 smtp_dispatch_mfa(int sig, short event, void *p) 222 { 223 struct smtpd *env = p; 224 struct imsgev *iev; 225 struct imsgbuf *ibuf; 226 struct imsg imsg; 227 ssize_t n; 228 229 iev = env->sc_ievs[PROC_MFA]; 230 ibuf = &iev->ibuf; 231 232 if (event & EV_READ) { 233 if ((n = imsg_read(ibuf)) == -1) 234 fatal("imsg_read_error"); 235 if (n == 0) { 236 /* this pipe is dead, so remove the event handler */ 237 event_del(&iev->ev); 238 event_loopexit(NULL); 239 return; 240 } 241 } 242 243 if (event & EV_WRITE) { 244 if (msgbuf_write(&ibuf->w) == -1) 245 fatal("msgbuf_write"); 246 } 247 248 for (;;) { 249 if ((n = imsg_get(ibuf, &imsg)) == -1) 250 fatal("smtp_dispatch_mfa: imsg_get error"); 251 if (n == 0) 252 break; 253 254 switch (imsg.hdr.type) { 255 case IMSG_MFA_MAIL: 256 case IMSG_MFA_RCPT: { 257 struct submit_status *ss = imsg.data; 258 struct session *s; 259 260 log_debug("smtp_dispatch_mfa: mfa handled return path"); 261 262 IMSG_SIZE_CHECK(ss); 263 264 if ((s = session_lookup(env, ss->id)) == NULL) 265 break; 266 267 session_pickup(s, ss); 268 break; 269 } 270 default: 271 log_warnx("smtp_dispatch_mfa: got imsg %d", 272 imsg.hdr.type); 273 fatalx("smtp_dispatch_mfa: unexpected imsg"); 274 } 275 imsg_free(&imsg); 276 } 277 imsg_event_add(iev); 278 } 279 280 void 281 smtp_dispatch_lka(int sig, short event, void *p) 282 { 283 struct smtpd *env = p; 284 struct imsgev *iev; 285 struct imsgbuf *ibuf; 286 struct imsg imsg; 287 ssize_t n; 288 289 iev = env->sc_ievs[PROC_LKA]; 290 ibuf = &iev->ibuf; 291 292 if (event & EV_READ) { 293 if ((n = imsg_read(ibuf)) == -1) 294 fatal("imsg_read_error"); 295 if (n == 0) { 296 /* this pipe is dead, so remove the event handler */ 297 event_del(&iev->ev); 298 event_loopexit(NULL); 299 return; 300 } 301 } 302 303 if (event & EV_WRITE) { 304 if (msgbuf_write(&ibuf->w) == -1) 305 fatal("msgbuf_write"); 306 } 307 308 for (;;) { 309 if ((n = imsg_get(ibuf, &imsg)) == -1) 310 fatal("smtp_dispatch_lka: imsg_get error"); 311 if (n == 0) 312 break; 313 314 switch (imsg.hdr.type) { 315 case IMSG_DNS_PTR: { 316 struct dns *reply = imsg.data; 317 struct session *s; 318 struct session key; 319 320 IMSG_SIZE_CHECK(reply); 321 322 key.s_id = reply->id; 323 324 s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key); 325 if (s == NULL) 326 fatal("smtp_dispatch_lka: session is gone"); 327 328 strlcpy(s->s_hostname, 329 reply->error ? "<unknown>" : reply->host, 330 sizeof(s->s_hostname)); 331 332 strlcpy(s->s_msg.session_hostname, s->s_hostname, 333 sizeof(s->s_msg.session_hostname)); 334 335 session_init(s->s_l, s); 336 337 break; 338 } 339 default: 340 log_warnx("smtp_dispatch_lka: got imsg %d", 341 imsg.hdr.type); 342 fatalx("smtp_dispatch_lka: unexpected imsg"); 343 } 344 imsg_free(&imsg); 345 } 346 imsg_event_add(iev); 347 } 348 349 void 350 smtp_dispatch_queue(int sig, short event, void *p) 351 { 352 struct smtpd *env = p; 353 struct imsgev *iev; 354 struct imsgbuf *ibuf; 355 struct imsg imsg; 356 ssize_t n; 357 358 iev = env->sc_ievs[PROC_QUEUE]; 359 ibuf = &iev->ibuf; 360 361 if (event & EV_READ) { 362 if ((n = imsg_read(ibuf)) == -1) 363 fatal("imsg_read_error"); 364 if (n == 0) { 365 /* this pipe is dead, so remove the event handler */ 366 event_del(&iev->ev); 367 event_loopexit(NULL); 368 return; 369 } 370 } 371 372 if (event & EV_WRITE) { 373 if (msgbuf_write(&ibuf->w) == -1) 374 fatal("msgbuf_write"); 375 } 376 377 for (;;) { 378 if ((n = imsg_get(ibuf, &imsg)) == -1) 379 fatal("smtp_dispatch_queue: imsg_get error"); 380 if (n == 0) 381 break; 382 383 switch (imsg.hdr.type) { 384 case IMSG_QUEUE_CREATE_MESSAGE: { 385 struct submit_status *ss = imsg.data; 386 struct session *s; 387 388 log_debug("smtp_dispatch_queue: queue handled message creation"); 389 390 IMSG_SIZE_CHECK(ss); 391 392 if ((s = session_lookup(env, ss->id)) == NULL) 393 break; 394 395 (void)strlcpy(s->s_msg.message_id, ss->u.msgid, 396 sizeof(s->s_msg.message_id)); 397 session_pickup(s, ss); 398 break; 399 } 400 case IMSG_QUEUE_MESSAGE_FILE: { 401 struct submit_status *ss = imsg.data; 402 struct session *s; 403 int fd; 404 405 log_debug("smtp_dispatch_queue: queue handled message creation"); 406 407 IMSG_SIZE_CHECK(ss); 408 409 fd = imsg.fd; 410 411 if ((s = session_lookup(env, ss->id)) == NULL) { 412 close(fd); 413 break; 414 } 415 416 if ((s->datafp = fdopen(fd, "w")) == NULL) { 417 /* queue may have experienced tempfail. */ 418 if (ss->code != 421) 419 fatal("smtp_dispatch_queue: fdopen"); 420 close(fd); 421 } 422 423 session_pickup(s, ss); 424 break; 425 } 426 case IMSG_QUEUE_TEMPFAIL: { 427 struct submit_status *ss = imsg.data; 428 struct session *s; 429 struct session key; 430 431 log_debug("smtp_dispatch_queue: tempfail in queue"); 432 433 IMSG_SIZE_CHECK(ss); 434 435 key.s_id = ss->id; 436 s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key); 437 if (s == NULL) 438 fatalx("smtp_dispatch_queue: session is gone"); 439 440 if (s->s_flags & F_WRITEONLY) { 441 /* 442 * Session is write-only, can't destroy it. 443 */ 444 s->s_msg.status |= S_MESSAGE_TEMPFAILURE; 445 } else 446 fatalx("smtp_dispatch_queue: corrupt session"); 447 break; 448 } 449 450 case IMSG_QUEUE_COMMIT_ENVELOPES: 451 case IMSG_QUEUE_COMMIT_MESSAGE: { 452 struct submit_status *ss = imsg.data; 453 struct session *s; 454 455 log_debug("smtp_dispatch_queue: queue acknowledged message submission"); 456 457 IMSG_SIZE_CHECK(ss); 458 459 if ((s = session_lookup(env, ss->id)) == NULL) 460 break; 461 462 session_pickup(s, ss); 463 break; 464 } 465 default: 466 log_warnx("smtp_dispatch_queue: got imsg %d", 467 imsg.hdr.type); 468 fatalx("smtp_dispatch_queue: unexpected imsg"); 469 } 470 imsg_free(&imsg); 471 } 472 imsg_event_add(iev); 473 } 474 475 void 476 smtp_dispatch_control(int sig, short event, void *p) 477 { 478 struct smtpd *env = p; 479 struct imsgev *iev; 480 struct imsgbuf *ibuf; 481 struct imsg imsg; 482 ssize_t n; 483 484 iev = env->sc_ievs[PROC_CONTROL]; 485 ibuf = &iev->ibuf; 486 487 if (event & EV_READ) { 488 if ((n = imsg_read(ibuf)) == -1) 489 fatal("imsg_read_error"); 490 if (n == 0) { 491 /* this pipe is dead, so remove the event handler */ 492 event_del(&iev->ev); 493 event_loopexit(NULL); 494 return; 495 } 496 } 497 498 if (event & EV_WRITE) { 499 if (msgbuf_write(&ibuf->w) == -1) 500 fatal("msgbuf_write"); 501 } 502 503 for (;;) { 504 if ((n = imsg_get(ibuf, &imsg)) == -1) 505 fatal("smtp_dispatch_control: imsg_get error"); 506 if (n == 0) 507 break; 508 509 switch (imsg.hdr.type) { 510 case IMSG_SMTP_ENQUEUE: { 511 static struct listener l; 512 struct addrinfo hints, *res; 513 struct session *s; 514 uid_t euid; 515 int fd[2]; 516 517 bzero(&l, sizeof(l)); 518 l.env = env; 519 520 memcpy(&euid, imsg.data, sizeof(euid)); 521 522 if (env->stats->smtp.sessions_active >= 523 env->sc_maxconn) { 524 log_warnx("denying local connection, too many" 525 " sessions active"); 526 imsg_compose_event(iev, IMSG_SMTP_ENQUEUE, 527 imsg.hdr.peerid, 0, -1, NULL, 0); 528 break; 529 } 530 531 if (socketpair( 532 AF_UNIX, SOCK_STREAM, PF_UNSPEC, fd) == -1) 533 fatal("socketpair"); 534 535 if ((s = calloc(1, sizeof(*s))) == NULL) 536 fatal(NULL); 537 538 s->s_id = generate_uid(); 539 s->s_fd = fd[0]; 540 s->s_env = env; 541 s->s_l = &l; 542 s->s_msg.flags |= F_MESSAGE_ENQUEUED; 543 (void)strlcpy(s->s_msg.tag, s->s_l->tag, sizeof(s->s_msg.tag)); 544 545 bzero(&hints, sizeof(hints)); 546 hints.ai_family = PF_UNSPEC; 547 hints.ai_flags = AI_NUMERICHOST; 548 549 if (getaddrinfo("::1", NULL, &hints, &res) != 0) 550 fatal("getaddrinfo"); 551 552 memcpy(&s->s_ss, res->ai_addr, res->ai_addrlen); 553 554 env->stats->smtp.sessions++; 555 env->stats->smtp.sessions_active++; 556 557 bsnprintf(s->s_hostname, sizeof(s->s_hostname), 558 "%d@localhost", euid); 559 strlcpy(s->s_msg.session_hostname, s->s_hostname, 560 sizeof(s->s_msg.session_hostname)); 561 562 SPLAY_INSERT(sessiontree, &s->s_env->sc_sessions, s); 563 564 session_init(s->s_l, s); 565 566 imsg_compose_event(iev, IMSG_SMTP_ENQUEUE, 567 imsg.hdr.peerid, 0, fd[1], NULL, 0); 568 break; 569 } 570 case IMSG_SMTP_PAUSE: 571 smtp_pause(env); 572 break; 573 case IMSG_SMTP_RESUME: 574 smtp_resume(env); 575 break; 576 default: 577 log_warnx("smtp_dispatch_control: got imsg %d", 578 imsg.hdr.type); 579 fatalx("smtp_dispatch_control: unexpected imsg"); 580 } 581 imsg_free(&imsg); 582 } 583 imsg_event_add(iev); 584 } 585 586 void 587 smtp_dispatch_runner(int sig, short event, void *p) 588 { 589 struct smtpd *env = p; 590 struct imsgev *iev; 591 struct imsgbuf *ibuf; 592 struct imsg imsg; 593 ssize_t n; 594 595 iev = env->sc_ievs[PROC_RUNNER]; 596 ibuf = &iev->ibuf; 597 598 if (event & EV_READ) { 599 if ((n = imsg_read(ibuf)) == -1) 600 fatal("imsg_read_error"); 601 if (n == 0) { 602 /* this pipe is dead, so remove the event handler */ 603 event_del(&iev->ev); 604 event_loopexit(NULL); 605 return; 606 } 607 } 608 609 if (event & EV_WRITE) { 610 if (msgbuf_write(&ibuf->w) == -1) 611 fatal("msgbuf_write"); 612 } 613 614 for (;;) { 615 if ((n = imsg_get(ibuf, &imsg)) == -1) 616 fatal("smtp_dispatch_runner: imsg_get error"); 617 if (n == 0) 618 break; 619 620 switch (imsg.hdr.type) { 621 case IMSG_SMTP_ENQUEUE: { 622 static struct listener l; 623 struct addrinfo hints, *res; 624 struct session *s; 625 int fd[2]; 626 627 bzero(&l, sizeof(l)); 628 l.env = env; 629 630 if (env->stats->smtp.sessions_active >= 631 env->sc_maxconn) { 632 log_warnx("denying internal connection, too many" 633 " sessions active"); 634 imsg_compose_event(iev, IMSG_SMTP_ENQUEUE, 0, 0, -1, 635 imsg.data, sizeof(struct message)); 636 break; 637 } 638 639 if (socketpair( 640 AF_UNIX, SOCK_STREAM, PF_UNSPEC, fd) == -1) 641 fatal("socketpair"); 642 643 if ((s = calloc(1, sizeof(*s))) == NULL) 644 fatal(NULL); 645 646 s->s_id = generate_uid(); 647 s->s_fd = fd[0]; 648 s->s_env = env; 649 s->s_l = &l; 650 s->s_msg.flags |= F_MESSAGE_ENQUEUED|F_MESSAGE_BOUNCE; 651 652 bzero(&hints, sizeof(hints)); 653 hints.ai_family = PF_UNSPEC; 654 hints.ai_flags = AI_NUMERICHOST; 655 656 if (getaddrinfo("::1", NULL, &hints, &res) != 0) 657 fatal("getaddrinfo"); 658 659 memcpy(&s->s_ss, res->ai_addr, res->ai_addrlen); 660 661 env->stats->smtp.sessions++; 662 env->stats->smtp.sessions_active++; 663 664 strlcpy(s->s_hostname, "localhost", 665 sizeof(s->s_hostname)); 666 strlcpy(s->s_msg.session_hostname, s->s_hostname, 667 sizeof(s->s_msg.session_hostname)); 668 669 SPLAY_INSERT(sessiontree, &s->s_env->sc_sessions, s); 670 671 session_init(s->s_l, s); 672 673 imsg_compose_event(iev, IMSG_SMTP_ENQUEUE, 0, 0, fd[1], 674 imsg.data, sizeof(struct message)); 675 break; 676 } 677 default: 678 log_warnx("smtp_dispatch_runner: got imsg %d", 679 imsg.hdr.type); 680 fatalx("smtp_dispatch_runner: unexpected imsg"); 681 } 682 imsg_free(&imsg); 683 } 684 imsg_event_add(iev); 685 } 686 687 void 688 smtp_shutdown(void) 689 { 690 log_info("smtp server exiting"); 691 _exit(0); 692 } 693 694 pid_t 695 smtp(struct smtpd *env) 696 { 697 pid_t pid; 698 struct passwd *pw; 699 700 struct event ev_sigint; 701 struct event ev_sigterm; 702 703 struct peer peers[] = { 704 { PROC_PARENT, smtp_dispatch_parent }, 705 { PROC_MFA, smtp_dispatch_mfa }, 706 { PROC_QUEUE, smtp_dispatch_queue }, 707 { PROC_LKA, smtp_dispatch_lka }, 708 { PROC_CONTROL, smtp_dispatch_control }, 709 { PROC_RUNNER, smtp_dispatch_runner } 710 }; 711 712 switch (pid = fork()) { 713 case -1: 714 fatal("smtp: cannot fork"); 715 case 0: 716 break; 717 default: 718 return (pid); 719 } 720 721 ssl_init(); 722 purge_config(env, PURGE_EVERYTHING); 723 724 pw = env->sc_pw; 725 726 #ifndef DEBUG 727 if (chroot(pw->pw_dir) == -1) 728 fatal("smtp: chroot"); 729 if (chdir("/") == -1) 730 fatal("smtp: chdir(\"/\")"); 731 #else 732 #warning disabling privilege revocation and chroot in DEBUG MODE 733 #endif 734 735 smtpd_process = PROC_SMTP; 736 setproctitle("%s", env->sc_title[smtpd_process]); 737 738 #ifndef DEBUG 739 if (setgroups(1, &pw->pw_gid) || 740 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 741 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 742 fatal("smtp: cannot drop privileges"); 743 #endif 744 745 event_init(); 746 747 signal_set(&ev_sigint, SIGINT, smtp_sig_handler, env); 748 signal_set(&ev_sigterm, SIGTERM, smtp_sig_handler, env); 749 signal_add(&ev_sigint, NULL); 750 signal_add(&ev_sigterm, NULL); 751 signal(SIGPIPE, SIG_IGN); 752 signal(SIGHUP, SIG_IGN); 753 754 config_pipes(env, peers, nitems(peers)); 755 config_peers(env, peers, nitems(peers)); 756 757 event_dispatch(); 758 smtp_shutdown(); 759 760 return (0); 761 } 762 763 void 764 smtp_setup_events(struct smtpd *env) 765 { 766 struct listener *l; 767 768 TAILQ_FOREACH(l, env->sc_listeners, entry) { 769 log_debug("smtp_setup_events: listen on %s port %d flags 0x%01x" 770 " cert \"%s\"", ss_to_text(&l->ss), ntohs(l->port), 771 l->flags, l->ssl_cert_name); 772 773 session_socket_blockmode(l->fd, BM_NONBLOCK); 774 if (listen(l->fd, SMTPD_BACKLOG) == -1) 775 fatal("listen"); 776 l->env = env; 777 event_set(&l->ev, l->fd, EV_READ, smtp_accept, l); 778 event_add(&l->ev, NULL); 779 ssl_setup(env, l); 780 } 781 } 782 783 void 784 smtp_disable_events(struct smtpd *env) 785 { 786 struct listener *l; 787 788 log_debug("smtp_disable_events: closing listening sockets"); 789 while ((l = TAILQ_FIRST(env->sc_listeners)) != NULL) { 790 TAILQ_REMOVE(env->sc_listeners, l, entry); 791 event_del(&l->ev); 792 close(l->fd); 793 free(l); 794 } 795 free(env->sc_listeners); 796 env->sc_listeners = NULL; 797 } 798 799 void 800 smtp_pause(struct smtpd *env) 801 { 802 struct listener *l; 803 804 log_debug("smtp_pause: pausing listening sockets"); 805 env->sc_opts |= SMTPD_SMTP_PAUSED; 806 807 TAILQ_FOREACH(l, env->sc_listeners, entry) 808 event_del(&l->ev); 809 } 810 811 void 812 smtp_resume(struct smtpd *env) 813 { 814 struct listener *l; 815 816 log_debug("smtp_resume: resuming listening sockets"); 817 env->sc_opts &= ~SMTPD_SMTP_PAUSED; 818 819 TAILQ_FOREACH(l, env->sc_listeners, entry) 820 event_add(&l->ev, NULL); 821 } 822 823 void 824 smtp_accept(int fd, short event, void *p) 825 { 826 int s_fd; 827 struct sockaddr_storage ss; 828 struct listener *l = p; 829 struct session *s; 830 socklen_t len; 831 832 log_debug("smtp_accept: incoming client on listener: %p", l); 833 len = sizeof(struct sockaddr_storage); 834 if ((s_fd = accept(l->fd, (struct sockaddr *)&ss, &len)) == -1) { 835 event_del(&l->ev); 836 return; 837 } 838 839 log_debug("smtp_accept: accepted client on listener: %p", l); 840 if ((s = calloc(1, sizeof(*s))) == NULL) 841 fatal(NULL); 842 len = sizeof(s->s_ss); 843 844 s->s_id = generate_uid(); 845 s->s_fd = s_fd; 846 s->s_env = l->env; 847 s->s_l = l; 848 849 (void)memcpy(&s->s_ss, &ss, sizeof(s->s_ss)); 850 851 event_add(&l->ev, NULL); 852 853 s->s_env->stats->smtp.sessions++; 854 s->s_env->stats->smtp.sessions_active++; 855 856 if (s->s_env->stats->smtp.sessions_active == s->s_env->sc_maxconn) 857 event_del(&l->ev); 858 859 dns_query_ptr(l->env, &s->s_ss, s->s_id); 860 861 SPLAY_INSERT(sessiontree, &s->s_env->sc_sessions, s); 862 } 863 864 /* 865 * Helper function for handling IMSG replies. 866 */ 867 struct session * 868 session_lookup(struct smtpd *env, u_int64_t id) 869 { 870 struct session key; 871 struct session *s; 872 873 key.s_id = id; 874 s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key); 875 if (s == NULL) 876 fatalx("session_lookup: session is gone"); 877 878 if (!(s->s_flags & F_WRITEONLY)) 879 fatalx("session_lookup: corrupt session"); 880 s->s_flags &= ~F_WRITEONLY; 881 882 if (s->s_flags & F_QUIT) { 883 session_destroy(s); 884 s = NULL; 885 } 886 887 return (s); 888 } 889