1 /* $OpenBSD: smtp.c,v 1.41 2009/04/28 22:38:22 jacekm Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> 5 * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/queue.h> 22 #include <sys/tree.h> 23 #include <sys/param.h> 24 #include <sys/socket.h> 25 26 #include <ctype.h> 27 #include <event.h> 28 #include <netdb.h> 29 #include <pwd.h> 30 #include <signal.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <time.h> 35 #include <unistd.h> 36 37 #include "smtpd.h" 38 39 __dead void smtp_shutdown(void); 40 void smtp_sig_handler(int, short, void *); 41 void smtp_dispatch_parent(int, short, void *); 42 void smtp_dispatch_mfa(int, short, void *); 43 void smtp_dispatch_lka(int, short, void *); 44 void smtp_dispatch_queue(int, short, void *); 45 void smtp_dispatch_control(int, short, void *); 46 void smtp_setup_events(struct smtpd *); 47 void smtp_disable_events(struct smtpd *); 48 void smtp_pause(struct smtpd *); 49 void smtp_resume(struct smtpd *); 50 void smtp_accept(int, short, void *); 51 void session_auth_pickup(struct session *, char *, size_t); 52 struct session *session_lookup(struct smtpd *, u_int64_t); 53 54 struct s_session s_smtp; 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 imsgbuf *ibuf; 74 struct imsg imsg; 75 ssize_t n; 76 77 ibuf = env->sc_ibufs[PROC_PARENT]; 78 switch (event) { 79 case EV_READ: 80 if ((n = imsg_read(ibuf)) == -1) 81 fatal("imsg_read_error"); 82 if (n == 0) { 83 /* this pipe is dead, so remove the event handler */ 84 event_del(&ibuf->ev); 85 event_loopexit(NULL); 86 return; 87 } 88 break; 89 case EV_WRITE: 90 if (msgbuf_write(&ibuf->w) == -1) 91 fatal("msgbuf_write"); 92 imsg_event_add(ibuf); 93 return; 94 default: 95 fatalx("unknown event"); 96 } 97 98 for (;;) { 99 if ((n = imsg_get(ibuf, &imsg)) == -1) 100 fatalx("smtp_dispatch_parent: imsg_get error"); 101 if (n == 0) 102 break; 103 104 switch (imsg.hdr.type) { 105 case IMSG_CONF_START: 106 if (env->sc_flags & SMTPD_CONFIGURING) 107 break; 108 env->sc_flags |= SMTPD_CONFIGURING; 109 smtp_disable_events(env); 110 break; 111 case IMSG_CONF_SSL: { 112 struct ssl *s; 113 struct ssl *x_ssl; 114 115 if (!(env->sc_flags & SMTPD_CONFIGURING)) 116 break; 117 118 if ((s = calloc(1, sizeof(*s))) == NULL) 119 fatal(NULL); 120 x_ssl = imsg.data; 121 (void)strlcpy(s->ssl_name, x_ssl->ssl_name, 122 sizeof(s->ssl_name)); 123 s->ssl_cert_len = x_ssl->ssl_cert_len; 124 if ((s->ssl_cert = 125 strdup((char *)imsg.data + sizeof(*s))) == NULL) 126 fatal(NULL); 127 s->ssl_key_len = x_ssl->ssl_key_len; 128 if ((s->ssl_key = strdup((char *)imsg.data + 129 (sizeof(*s) + s->ssl_cert_len))) == NULL) 130 fatal(NULL); 131 132 SPLAY_INSERT(ssltree, &env->sc_ssl, s); 133 break; 134 } 135 case IMSG_CONF_LISTENER: { 136 struct listener *l; 137 struct ssl key; 138 139 if (!(env->sc_flags & SMTPD_CONFIGURING)) 140 break; 141 142 if ((l = calloc(1, sizeof(*l))) == NULL) 143 fatal(NULL); 144 memcpy(l, imsg.data, sizeof(*l)); 145 if ((l->fd = imsg_get_fd(ibuf, &imsg)) == -1) 146 fatal("cannot get fd"); 147 148 (void)strlcpy(key.ssl_name, l->ssl_cert_name, 149 sizeof(key.ssl_name)); 150 151 if (l->flags & F_SSL) 152 if ((l->ssl = SPLAY_FIND(ssltree, 153 &env->sc_ssl, &key)) == NULL) 154 fatal("parent and smtp desynchronized"); 155 156 TAILQ_INSERT_TAIL(&env->sc_listeners, l, entry); 157 break; 158 } 159 case IMSG_CONF_END: 160 if (!(env->sc_flags & SMTPD_CONFIGURING)) 161 break; 162 smtp_setup_events(env); 163 env->sc_flags &= ~SMTPD_CONFIGURING; 164 break; 165 case IMSG_PARENT_AUTHENTICATE: { 166 struct session *s; 167 struct session_auth_reply *reply = imsg.data; 168 169 log_debug("smtp_dispatch_parent: parent handled authentication"); 170 171 if ((s = session_lookup(env, reply->session_id)) == NULL) 172 break; 173 174 if (reply->value) 175 s->s_flags |= F_AUTHENTICATED; 176 177 session_auth_pickup(s, NULL, 0); 178 179 break; 180 } 181 default: 182 log_warnx("smtp_dispatch_parent: got imsg %d", 183 imsg.hdr.type); 184 fatalx("smtp_dispatch_parent: unexpected imsg"); 185 } 186 imsg_free(&imsg); 187 } 188 imsg_event_add(ibuf); 189 } 190 191 void 192 smtp_dispatch_mfa(int sig, short event, void *p) 193 { 194 struct smtpd *env = p; 195 struct imsgbuf *ibuf; 196 struct imsg imsg; 197 ssize_t n; 198 199 ibuf = env->sc_ibufs[PROC_MFA]; 200 switch (event) { 201 case EV_READ: 202 if ((n = imsg_read(ibuf)) == -1) 203 fatal("imsg_read_error"); 204 if (n == 0) { 205 /* this pipe is dead, so remove the event handler */ 206 event_del(&ibuf->ev); 207 event_loopexit(NULL); 208 return; 209 } 210 break; 211 case EV_WRITE: 212 if (msgbuf_write(&ibuf->w) == -1) 213 fatal("msgbuf_write"); 214 imsg_event_add(ibuf); 215 return; 216 default: 217 fatalx("unknown event"); 218 } 219 220 for (;;) { 221 if ((n = imsg_get(ibuf, &imsg)) == -1) 222 fatalx("smtp_dispatch_mfa: imsg_get error"); 223 if (n == 0) 224 break; 225 226 switch (imsg.hdr.type) { 227 case IMSG_MFA_MAIL: 228 case IMSG_MFA_RCPT: { 229 struct submit_status *ss = imsg.data; 230 struct session *s; 231 232 log_debug("smtp_dispatch_mfa: mfa handled return path"); 233 234 if ((s = session_lookup(env, ss->id)) == NULL) 235 break; 236 237 session_pickup(s, ss); 238 break; 239 } 240 default: 241 log_warnx("smtp_dispatch_mfa: got imsg %d", 242 imsg.hdr.type); 243 fatalx("smtp_dispatch_mfa: unexpected imsg"); 244 } 245 imsg_free(&imsg); 246 } 247 imsg_event_add(ibuf); 248 } 249 250 void 251 smtp_dispatch_lka(int sig, short event, void *p) 252 { 253 struct smtpd *env = p; 254 struct imsgbuf *ibuf; 255 struct imsg imsg; 256 ssize_t n; 257 258 ibuf = env->sc_ibufs[PROC_LKA]; 259 switch (event) { 260 case EV_READ: 261 if ((n = imsg_read(ibuf)) == -1) 262 fatal("imsg_read_error"); 263 if (n == 0) { 264 /* this pipe is dead, so remove the event handler */ 265 event_del(&ibuf->ev); 266 event_loopexit(NULL); 267 return; 268 } 269 break; 270 case EV_WRITE: 271 if (msgbuf_write(&ibuf->w) == -1) 272 fatal("msgbuf_write"); 273 imsg_event_add(ibuf); 274 return; 275 default: 276 fatalx("unknown event"); 277 } 278 279 for (;;) { 280 if ((n = imsg_get(ibuf, &imsg)) == -1) 281 fatalx("smtp_dispatch_lka: imsg_get error"); 282 if (n == 0) 283 break; 284 285 switch (imsg.hdr.type) { 286 case IMSG_LKA_HOST: { 287 struct session key; 288 struct session *s; 289 struct session *ss; 290 291 ss = imsg.data; 292 key.s_id = ss->s_id; 293 294 s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key); 295 if (s == NULL) 296 fatal("smtp_dispatch_lka: session is gone"); 297 298 strlcpy(s->s_hostname, ss->s_hostname, 299 sizeof(s->s_hostname)); 300 strlcpy(s->s_msg.session_hostname, ss->s_hostname, 301 sizeof(s->s_msg.session_hostname)); 302 303 session_init(s->s_l, s); 304 305 break; 306 } 307 default: 308 log_warnx("smtp_dispatch_lka: got imsg %d", 309 imsg.hdr.type); 310 fatalx("smtp_dispatch_lka: unexpected imsg"); 311 } 312 imsg_free(&imsg); 313 } 314 imsg_event_add(ibuf); 315 } 316 317 void 318 smtp_dispatch_queue(int sig, short event, void *p) 319 { 320 struct smtpd *env = p; 321 struct imsgbuf *ibuf; 322 struct imsg imsg; 323 ssize_t n; 324 325 ibuf = env->sc_ibufs[PROC_QUEUE]; 326 switch (event) { 327 case EV_READ: 328 if ((n = imsg_read(ibuf)) == -1) 329 fatal("imsg_read_error"); 330 if (n == 0) { 331 /* this pipe is dead, so remove the event handler */ 332 event_del(&ibuf->ev); 333 event_loopexit(NULL); 334 return; 335 } 336 break; 337 case EV_WRITE: 338 if (msgbuf_write(&ibuf->w) == -1) 339 fatal("msgbuf_write"); 340 imsg_event_add(ibuf); 341 return; 342 default: 343 fatalx("unknown event"); 344 } 345 346 for (;;) { 347 if ((n = imsg_get(ibuf, &imsg)) == -1) 348 fatalx("smtp_dispatch_queue: imsg_get error"); 349 if (n == 0) 350 break; 351 352 switch (imsg.hdr.type) { 353 case IMSG_QUEUE_CREATE_MESSAGE: { 354 struct submit_status *ss = imsg.data; 355 struct session *s; 356 357 log_debug("smtp_dispatch_queue: queue handled message creation"); 358 359 if ((s = session_lookup(env, ss->id)) == NULL) 360 break; 361 362 (void)strlcpy(s->s_msg.message_id, ss->u.msgid, 363 sizeof(s->s_msg.message_id)); 364 session_pickup(s, ss); 365 break; 366 } 367 case IMSG_QUEUE_MESSAGE_FILE: { 368 struct submit_status *ss = imsg.data; 369 struct session *s; 370 int fd; 371 372 log_debug("smtp_dispatch_queue: queue handled message creation"); 373 374 fd = imsg_get_fd(ibuf, &imsg); 375 376 if ((s = session_lookup(env, ss->id)) == NULL) { 377 close(fd); 378 break; 379 } 380 381 if ((s->datafp = fdopen(fd, "w")) == NULL) { 382 /* queue may have experienced tempfail. */ 383 if (ss->code != 421) 384 fatal("smtp_dispatch_queue: fdopen"); 385 close(fd); 386 } 387 388 session_pickup(s, ss); 389 break; 390 } 391 case IMSG_QUEUE_TEMPFAIL: { 392 struct submit_status *ss = imsg.data; 393 struct session *s; 394 struct session key; 395 396 log_debug("smtp_dispatch_queue: tempfail in queue"); 397 398 /* 399 * IMSG_QUEUE_TEMPFAIL is not the final reply to 400 * IMSG_MFA_RCPT - IMSG_QUEUE_COMMIT_ENVELOPES is. 401 * Therefore, nothing more but updating the flags 402 * is allowed here. If session_lookup were to be 403 * called, then subsequent session_lookup in the 404 * IMSG_QUEUE_COMMIT_ENVELOPES handler would fatal for 405 * either of two reasons: missing session, or missing 406 * EVLOCKED flag. 407 */ 408 key.s_id = ss->id; 409 s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key); 410 if (s == NULL) 411 fatalx("smtp_dispatch_queue: session is gone"); 412 413 s->s_msg.status |= S_MESSAGE_TEMPFAILURE; 414 break; 415 } 416 417 case IMSG_QUEUE_COMMIT_ENVELOPES: 418 case IMSG_QUEUE_COMMIT_MESSAGE: { 419 struct submit_status *ss = imsg.data; 420 struct session *s; 421 422 log_debug("smtp_dispatch_queue: queue acknowledged message submission"); 423 424 if ((s = session_lookup(env, ss->id)) == NULL) 425 break; 426 427 session_pickup(s, ss); 428 break; 429 } 430 default: 431 log_warnx("smtp_dispatch_queue: got imsg %d", 432 imsg.hdr.type); 433 fatalx("smtp_dispatch_queue: unexpected imsg"); 434 } 435 imsg_free(&imsg); 436 } 437 imsg_event_add(ibuf); 438 } 439 440 void 441 smtp_dispatch_control(int sig, short event, void *p) 442 { 443 struct smtpd *env = p; 444 struct imsgbuf *ibuf; 445 struct imsg imsg; 446 ssize_t n; 447 448 ibuf = env->sc_ibufs[PROC_CONTROL]; 449 switch (event) { 450 case EV_READ: 451 if ((n = imsg_read(ibuf)) == -1) 452 fatal("imsg_read_error"); 453 if (n == 0) { 454 /* this pipe is dead, so remove the event handler */ 455 event_del(&ibuf->ev); 456 event_loopexit(NULL); 457 return; 458 } 459 break; 460 case EV_WRITE: 461 if (msgbuf_write(&ibuf->w) == -1) 462 fatal("msgbuf_write"); 463 imsg_event_add(ibuf); 464 return; 465 default: 466 fatalx("unknown event"); 467 } 468 469 for (;;) { 470 if ((n = imsg_get(ibuf, &imsg)) == -1) 471 fatalx("smtp_dispatch_control: imsg_get error"); 472 if (n == 0) 473 break; 474 475 switch (imsg.hdr.type) { 476 case IMSG_SMTP_ENQUEUE: { 477 static struct listener l; 478 struct addrinfo hints, *res; 479 struct session *s; 480 int fd[2]; 481 482 bzero(&l, sizeof(l)); 483 l.env = env; 484 485 if (s_smtp.sessions_active >= env->sc_maxconn) { 486 log_warnx("denying local connection, too many" 487 " sessions active"); 488 imsg_compose(ibuf, IMSG_SMTP_ENQUEUE, 0, 0, -1, 489 imsg.data, sizeof(int)); 490 break; 491 } 492 493 if (socketpair( 494 AF_UNIX, SOCK_STREAM, PF_UNSPEC, fd) == -1) 495 fatal("socketpair"); 496 497 if ((s = calloc(1, sizeof(*s))) == NULL) 498 fatal(NULL); 499 500 s->s_id = queue_generate_id(); 501 s->s_fd = fd[0]; 502 s->s_env = env; 503 s->s_l = &l; 504 s->s_msg.flags |= F_MESSAGE_ENQUEUED; 505 506 bzero(&hints, sizeof(hints)); 507 hints.ai_family = PF_UNSPEC; 508 hints.ai_flags = AI_NUMERICHOST; 509 510 if (getaddrinfo("::1", NULL, &hints, &res) != 0) 511 fatal("getaddrinfo"); 512 513 memcpy(&s->s_ss, res->ai_addr, res->ai_addrlen); 514 515 s_smtp.sessions++; 516 s_smtp.sessions_active++; 517 518 strlcpy(s->s_hostname, "localhost", 519 sizeof(s->s_hostname)); 520 strlcpy(s->s_msg.session_hostname, s->s_hostname, 521 sizeof(s->s_msg.session_hostname)); 522 523 SPLAY_INSERT(sessiontree, &s->s_env->sc_sessions, s); 524 525 session_init(s->s_l, s); 526 527 imsg_compose(ibuf, IMSG_SMTP_ENQUEUE, 0, 0, fd[1], 528 imsg.data, sizeof(int)); 529 break; 530 } 531 case IMSG_SMTP_PAUSE: 532 smtp_pause(env); 533 break; 534 case IMSG_SMTP_RESUME: 535 smtp_resume(env); 536 break; 537 case IMSG_STATS: { 538 struct stats *s; 539 540 s = imsg.data; 541 s->u.smtp = s_smtp; 542 imsg_compose(ibuf, IMSG_STATS, 0, 0, -1, s, sizeof(*s)); 543 break; 544 } 545 default: 546 log_warnx("smtp_dispatch_control: got imsg %d", 547 imsg.hdr.type); 548 fatalx("smtp_dispatch_control: unexpected imsg"); 549 } 550 imsg_free(&imsg); 551 } 552 imsg_event_add(ibuf); 553 } 554 555 void 556 smtp_shutdown(void) 557 { 558 log_info("smtp server exiting"); 559 _exit(0); 560 } 561 562 pid_t 563 smtp(struct smtpd *env) 564 { 565 pid_t pid; 566 struct passwd *pw; 567 568 struct event ev_sigint; 569 struct event ev_sigterm; 570 571 struct peer peers[] = { 572 { PROC_PARENT, smtp_dispatch_parent }, 573 { PROC_MFA, smtp_dispatch_mfa }, 574 { PROC_QUEUE, smtp_dispatch_queue }, 575 { PROC_LKA, smtp_dispatch_lka }, 576 { PROC_CONTROL, smtp_dispatch_control } 577 }; 578 579 switch (pid = fork()) { 580 case -1: 581 fatal("smtp: cannot fork"); 582 case 0: 583 break; 584 default: 585 return (pid); 586 } 587 588 ssl_init(); 589 purge_config(env, PURGE_EVERYTHING); 590 591 pw = env->sc_pw; 592 593 #ifndef DEBUG 594 if (chroot(pw->pw_dir) == -1) 595 fatal("smtp: chroot"); 596 if (chdir("/") == -1) 597 fatal("smtp: chdir(\"/\")"); 598 #else 599 #warning disabling privilege revocation and chroot in DEBUG MODE 600 #endif 601 602 setproctitle("smtp server"); 603 smtpd_process = PROC_SMTP; 604 605 #ifndef DEBUG 606 if (setgroups(1, &pw->pw_gid) || 607 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 608 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 609 fatal("smtp: cannot drop privileges"); 610 #endif 611 612 event_init(); 613 614 signal_set(&ev_sigint, SIGINT, smtp_sig_handler, env); 615 signal_set(&ev_sigterm, SIGTERM, smtp_sig_handler, env); 616 signal_add(&ev_sigint, NULL); 617 signal_add(&ev_sigterm, NULL); 618 signal(SIGPIPE, SIG_IGN); 619 signal(SIGHUP, SIG_IGN); 620 621 config_pipes(env, peers, 5); 622 config_peers(env, peers, 5); 623 624 smtp_setup_events(env); 625 event_dispatch(); 626 smtp_shutdown(); 627 628 return (0); 629 } 630 631 void 632 smtp_setup_events(struct smtpd *env) 633 { 634 struct listener *l; 635 636 TAILQ_FOREACH(l, &env->sc_listeners, entry) { 637 log_debug("smtp_setup_events: listen on %s port %d flags 0x%01x" 638 " cert \"%s\"", ss_to_text(&l->ss), ntohs(l->port), 639 l->flags, l->ssl_cert_name); 640 641 session_socket_blockmode(l->fd, BM_NONBLOCK); 642 if (listen(l->fd, SMTPD_BACKLOG) == -1) 643 fatal("listen"); 644 l->env = env; 645 event_set(&l->ev, l->fd, EV_READ, smtp_accept, l); 646 event_add(&l->ev, NULL); 647 ssl_setup(env, l); 648 } 649 } 650 651 void 652 smtp_disable_events(struct smtpd *env) 653 { 654 struct listener *l; 655 656 log_debug("smtp_disable_events: closing listening sockets"); 657 while ((l = TAILQ_FIRST(&env->sc_listeners)) != NULL) { 658 TAILQ_REMOVE(&env->sc_listeners, l, entry); 659 event_del(&l->ev); 660 close(l->fd); 661 free(l); 662 } 663 TAILQ_INIT(&env->sc_listeners); 664 } 665 666 void 667 smtp_pause(struct smtpd *env) 668 { 669 log_debug("smtp_pause_listeners: pausing listening sockets"); 670 smtp_disable_events(env); 671 env->sc_opts |= SMTPD_SMTP_PAUSED; 672 } 673 674 void 675 smtp_resume(struct smtpd *env) 676 { 677 log_debug("smtp_pause_listeners: resuming listening sockets"); 678 imsg_compose(env->sc_ibufs[PROC_PARENT], IMSG_PARENT_SEND_CONFIG, 679 0, 0, -1, NULL, 0); 680 env->sc_opts &= ~SMTPD_SMTP_PAUSED; 681 } 682 683 void 684 smtp_accept(int fd, short event, void *p) 685 { 686 int s_fd; 687 struct sockaddr_storage ss; 688 struct listener *l = p; 689 struct session *s; 690 socklen_t len; 691 692 log_debug("smtp_accept: incoming client on listener: %p", l); 693 len = sizeof(struct sockaddr_storage); 694 if ((s_fd = accept(l->fd, (struct sockaddr *)&ss, &len)) == -1) { 695 event_del(&l->ev); 696 return; 697 } 698 699 log_debug("smtp_accept: accepted client on listener: %p", l); 700 if ((s = calloc(1, sizeof(*s))) == NULL) 701 fatal(NULL); 702 len = sizeof(s->s_ss); 703 704 s->s_id = queue_generate_id(); 705 s->s_fd = s_fd; 706 s->s_env = l->env; 707 s->s_l = l; 708 709 (void)memcpy(&s->s_ss, &ss, sizeof(s->s_ss)); 710 711 event_add(&l->ev, NULL); 712 713 s_smtp.sessions++; 714 s_smtp.sessions_active++; 715 716 if (s_smtp.sessions_active == s->s_env->sc_maxconn) 717 event_del(&l->ev); 718 719 imsg_compose(s->s_env->sc_ibufs[PROC_LKA], IMSG_LKA_HOST, 0, 0, -1, s, 720 sizeof(struct session)); 721 722 SPLAY_INSERT(sessiontree, &s->s_env->sc_sessions, s); 723 } 724 725 void 726 smtp_listener_setup(struct smtpd *env, struct listener *l) 727 { 728 int opt; 729 730 if ((l->fd = socket(l->ss.ss_family, SOCK_STREAM, 0)) == -1) 731 fatal("socket"); 732 733 opt = 1; 734 setsockopt(l->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); 735 736 if (bind(l->fd, (struct sockaddr *)&l->ss, l->ss.ss_len) == -1) 737 fatal("bind"); 738 } 739 740 /* 741 * Helper function for handling IMSG replies. 742 */ 743 struct session * 744 session_lookup(struct smtpd *env, u_int64_t id) 745 { 746 struct session key; 747 struct session *s; 748 749 key.s_id = id; 750 s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key); 751 if (s == NULL) 752 fatalx("session_lookup: session is gone"); 753 754 if (!(s->s_flags & F_EVLOCKED)) 755 fatalx("session_lookup: corrupt session"); 756 s->s_flags &= ~F_EVLOCKED; 757 758 if (s->s_flags & F_QUIT) { 759 session_destroy(s); 760 s = NULL; 761 } 762 763 return (s); 764 } 765