bounce.c revision 1.65
1/* $OpenBSD: bounce.c,v 1.65 2014/05/28 10:34:16 daniel Exp $ */ 2 3/* 4 * Copyright (c) 2009 Gilles Chehade <gilles@poolp.org> 5 * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net> 6 * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> 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 <inttypes.h> 31#include <pwd.h> 32#include <signal.h> 33#include <stdio.h> 34#include <stdlib.h> 35#include <string.h> 36#include <time.h> 37#include <unistd.h> 38 39#include "smtpd.h" 40#include "log.h" 41 42#define BOUNCE_MAXRUN 2 43#define BOUNCE_HIWAT 65535 44 45enum { 46 BOUNCE_EHLO, 47 BOUNCE_MAIL, 48 BOUNCE_RCPT, 49 BOUNCE_DATA, 50 BOUNCE_DATA_NOTICE, 51 BOUNCE_DATA_MESSAGE, 52 BOUNCE_DATA_END, 53 BOUNCE_QUIT, 54 BOUNCE_CLOSE, 55}; 56 57struct bounce_envelope { 58 TAILQ_ENTRY(bounce_envelope) entry; 59 uint64_t id; 60 char *report; 61}; 62 63struct bounce_message { 64 SPLAY_ENTRY(bounce_message) sp_entry; 65 TAILQ_ENTRY(bounce_message) entry; 66 uint32_t msgid; 67 struct delivery_bounce bounce; 68 char *smtpname; 69 char *to; 70 time_t timeout; 71 TAILQ_HEAD(, bounce_envelope) envelopes; 72}; 73 74struct bounce_session { 75 char *smtpname; 76 struct bounce_message *msg; 77 FILE *msgfp; 78 int state; 79 struct iobuf iobuf; 80 struct io io; 81}; 82 83SPLAY_HEAD(bounce_message_tree, bounce_message); 84static int bounce_message_cmp(const struct bounce_message *, 85 const struct bounce_message *); 86SPLAY_PROTOTYPE(bounce_message_tree, bounce_message, sp_entry, 87 bounce_message_cmp); 88 89static void bounce_drain(void); 90static void bounce_send(struct bounce_session *, const char *, ...); 91static int bounce_next_message(struct bounce_session *); 92static int bounce_next(struct bounce_session *); 93static void bounce_delivery(struct bounce_message *, int, const char *); 94static void bounce_status(struct bounce_session *, const char *, ...); 95static void bounce_io(struct io *, int); 96static void bounce_timeout(int, short, void *); 97static void bounce_free(struct bounce_session *); 98static const char *bounce_strtype(enum bounce_type); 99 100static struct tree wait_fd; 101static struct bounce_message_tree messages; 102static TAILQ_HEAD(, bounce_message) pending; 103 104static int nmessage = 0; 105static int running = 0; 106static struct event ev_timer; 107 108static void 109bounce_init(void) 110{ 111 static int init = 0; 112 113 if (init == 0) { 114 TAILQ_INIT(&pending); 115 SPLAY_INIT(&messages); 116 tree_init(&wait_fd); 117 evtimer_set(&ev_timer, bounce_timeout, NULL); 118 init = 1; 119 } 120} 121 122void 123bounce_add(uint64_t evpid) 124{ 125 char buf[SMTPD_MAXLINESIZE], *line; 126 struct envelope evp; 127 struct bounce_message key, *msg; 128 struct bounce_envelope *be; 129 130 bounce_init(); 131 132 if (queue_envelope_load(evpid, &evp) == 0) { 133 m_create(p_scheduler, IMSG_QUEUE_DELIVERY_PERMFAIL, 0, 0, -1); 134 m_add_evpid(p_scheduler, evpid); 135 m_close(p_scheduler); 136 return; 137 } 138 139 if (evp.type != D_BOUNCE) 140 errx(1, "bounce: evp:%016" PRIx64 " is not of type D_BOUNCE!", 141 evp.id); 142 143 key.msgid = evpid_to_msgid(evpid); 144 key.bounce = evp.agent.bounce; 145 key.smtpname = evp.smtpname; 146 msg = SPLAY_FIND(bounce_message_tree, &messages, &key); 147 if (msg == NULL) { 148 msg = xcalloc(1, sizeof(*msg), "bounce_add"); 149 msg->msgid = key.msgid; 150 msg->bounce = key.bounce; 151 152 TAILQ_INIT(&msg->envelopes); 153 154 msg->smtpname = xstrdup(evp.smtpname, "bounce_add"); 155 (void)snprintf(buf, sizeof(buf), "%s@%s", evp.sender.user, 156 evp.sender.domain); 157 msg->to = xstrdup(buf, "bounce_add"); 158 nmessage += 1; 159 SPLAY_INSERT(bounce_message_tree, &messages, msg); 160 log_debug("debug: bounce: new message %08" PRIx32, 161 msg->msgid); 162 stat_increment("bounce.message", 1); 163 } else 164 TAILQ_REMOVE(&pending, msg, entry); 165 166 line = evp.errorline; 167 if (strlen(line) > 4 && (*line == '1' || *line == '6')) 168 line += 4; 169 (void)snprintf(buf, sizeof(buf), "%s@%s: %s\n", evp.dest.user, 170 evp.dest.domain, line); 171 172 be = xmalloc(sizeof *be, "bounce_add"); 173 be->id = evpid; 174 be->report = xstrdup(buf, "bounce_add"); 175 TAILQ_INSERT_TAIL(&msg->envelopes, be, entry); 176 buf[strcspn(buf, "\n")] = '\0'; 177 log_debug("debug: bounce: adding report %16"PRIx64": %s", be->id, buf); 178 179 msg->timeout = time(NULL) + 1; 180 TAILQ_INSERT_TAIL(&pending, msg, entry); 181 182 stat_increment("bounce.envelope", 1); 183 bounce_drain(); 184} 185 186void 187bounce_fd(int fd) 188{ 189 struct bounce_session *s; 190 struct bounce_message *msg; 191 192 log_debug("debug: bounce: got enqueue socket %d", fd); 193 194 if (fd == -1 || TAILQ_EMPTY(&pending)) { 195 log_debug("debug: bounce: cancelling"); 196 if (fd != -1) 197 close(fd); 198 running -= 1; 199 bounce_drain(); 200 return; 201 } 202 203 msg = TAILQ_FIRST(&pending); 204 205 s = xcalloc(1, sizeof(*s), "bounce_fd"); 206 s->smtpname = xstrdup(msg->smtpname, "bounce_fd"); 207 s->state = BOUNCE_EHLO; 208 iobuf_xinit(&s->iobuf, 0, 0, "bounce_run"); 209 io_init(&s->io, fd, s, bounce_io, &s->iobuf); 210 io_set_timeout(&s->io, 30000); 211 io_set_read(&s->io); 212 213 log_debug("debug: bounce: new session %p", s); 214 stat_increment("bounce.session", 1); 215} 216 217static void 218bounce_timeout(int fd, short ev, void *arg) 219{ 220 log_debug("debug: bounce: timeout"); 221 222 bounce_drain(); 223} 224 225static void 226bounce_drain() 227{ 228 struct bounce_message *msg; 229 struct timeval tv; 230 time_t t; 231 232 log_debug("debug: bounce: drain: nmessage=%d running=%d", 233 nmessage, running); 234 235 while (1) { 236 if (running >= BOUNCE_MAXRUN) { 237 log_debug("debug: bounce: max session reached"); 238 return; 239 } 240 241 if (nmessage == 0) { 242 log_debug("debug: bounce: no more messages"); 243 return; 244 } 245 246 if (running >= nmessage) { 247 log_debug("debug: bounce: enough sessions running"); 248 return; 249 } 250 251 if ((msg = TAILQ_FIRST(&pending)) == NULL) { 252 log_debug("debug: bounce: no more pending messages"); 253 return; 254 } 255 256 t = time(NULL); 257 if (msg->timeout > t) { 258 log_debug("debug: bounce: next message not ready yet"); 259 if (!evtimer_pending(&ev_timer, NULL)) { 260 log_debug("debug: bounce: setting timer"); 261 tv.tv_sec = msg->timeout - t; 262 tv.tv_usec = 0; 263 evtimer_add(&ev_timer, &tv); 264 } 265 return; 266 } 267 268 log_debug("debug: bounce: requesting new enqueue socket..."); 269 m_compose(p_pony, IMSG_QUEUE_SMTP_SESSION, 0, 0, -1, NULL, 0); 270 271 running += 1; 272 } 273} 274 275static void 276bounce_send(struct bounce_session *s, const char *fmt, ...) 277{ 278 va_list ap; 279 char *p; 280 int len; 281 282 va_start(ap, fmt); 283 if ((len = vasprintf(&p, fmt, ap)) == -1) 284 fatal("bounce: vasprintf"); 285 va_end(ap); 286 287 log_trace(TRACE_BOUNCE, "bounce: %p: >>> %s", s, p); 288 289 iobuf_xfqueue(&s->iobuf, "bounce_send", "%s\n", p); 290 291 free(p); 292} 293 294static const char * 295bounce_duration(long long int d) 296{ 297 static char buf[32]; 298 299 if (d < 60) { 300 (void)snprintf(buf, sizeof buf, "%lld second%s", d, (d == 1)?"":"s"); 301 } else if (d < 3600) { 302 d = d / 60; 303 (void)snprintf(buf, sizeof buf, "%lld minute%s", d, (d == 1)?"":"s"); 304 } 305 else if (d < 3600 * 24) { 306 d = d / 3600; 307 (void)snprintf(buf, sizeof buf, "%lld hour%s", d, (d == 1)?"":"s"); 308 } 309 else { 310 d = d / (3600 * 24); 311 (void)snprintf(buf, sizeof buf, "%lld day%s", d, (d == 1)?"":"s"); 312 } 313 return (buf); 314} 315 316#define NOTICE_INTRO \ 317 " Hi!\n\n" \ 318 " This is the MAILER-DAEMON, please DO NOT REPLY to this e-mail.\n" 319 320const char *notice_error = 321 " An error has occurred while attempting to deliver a message for\n" 322 " the following list of recipients:\n\n"; 323 324const char *notice_warning = 325 " A message is delayed for more than %s for the following\n" 326 " list of recipients:\n\n"; 327 328const char *notice_warning2 = 329 " Please note that this is only a temporary failure report.\n" 330 " The message is kept in the queue for up to %s.\n" 331 " You DO NOT NEED to re-send the message to these recipients.\n\n"; 332 333const char *notice_success = 334 " Your message was successfully delivered to these recipients.\n\n"; 335 336const char *notice_relay = 337 " Your message was relayed to these recipients.\n\n"; 338 339static int 340bounce_next_message(struct bounce_session *s) 341{ 342 struct bounce_message *msg; 343 char buf[SMTPD_MAXLINESIZE]; 344 int fd; 345 time_t now; 346 347 again: 348 349 now = time(NULL); 350 351 TAILQ_FOREACH(msg, &pending, entry) { 352 if (msg->timeout > now) 353 continue; 354 if (strcmp(msg->smtpname, s->smtpname)) 355 continue; 356 break; 357 } 358 if (msg == NULL) 359 return (0); 360 361 TAILQ_REMOVE(&pending, msg, entry); 362 SPLAY_REMOVE(bounce_message_tree, &messages, msg); 363 364 if ((fd = queue_message_fd_r(msg->msgid)) == -1) { 365 bounce_delivery(msg, IMSG_QUEUE_DELIVERY_TEMPFAIL, 366 "Could not open message fd"); 367 goto again; 368 } 369 370 if ((s->msgfp = fdopen(fd, "r")) == NULL) { 371 (void)snprintf(buf, sizeof(buf), "fdopen: %s", strerror(errno)); 372 log_warn("warn: bounce: fdopen"); 373 close(fd); 374 bounce_delivery(msg, IMSG_QUEUE_DELIVERY_TEMPFAIL, buf); 375 goto again; 376 } 377 378 s->msg = msg; 379 return (1); 380} 381 382static int 383bounce_next(struct bounce_session *s) 384{ 385 struct bounce_envelope *evp; 386 char *line; 387 size_t len, n; 388 389 switch (s->state) { 390 case BOUNCE_EHLO: 391 bounce_send(s, "EHLO %s", s->smtpname); 392 s->state = BOUNCE_MAIL; 393 break; 394 395 case BOUNCE_MAIL: 396 case BOUNCE_DATA_END: 397 log_debug("debug: bounce: %p: getting next message...", s); 398 if (bounce_next_message(s) == 0) { 399 log_debug("debug: bounce: %p: no more messages", s); 400 bounce_send(s, "QUIT"); 401 s->state = BOUNCE_CLOSE; 402 break; 403 } 404 log_debug("debug: bounce: %p: found message %08"PRIx32, 405 s, s->msg->msgid); 406 bounce_send(s, "MAIL FROM: <>"); 407 s->state = BOUNCE_RCPT; 408 break; 409 410 case BOUNCE_RCPT: 411 bounce_send(s, "RCPT TO: <%s>", s->msg->to); 412 s->state = BOUNCE_DATA; 413 break; 414 415 case BOUNCE_DATA: 416 bounce_send(s, "DATA"); 417 s->state = BOUNCE_DATA_NOTICE; 418 break; 419 420 case BOUNCE_DATA_NOTICE: 421 /* Construct an appropriate notice. */ 422 423 iobuf_xfqueue(&s->iobuf, "bounce_next: HEADER", 424 "Subject: Delivery status notification: %s\n" 425 "From: Mailer Daemon <MAILER-DAEMON@%s>\n" 426 "To: %s\n" 427 "Date: %s\n" 428 "\n" 429 NOTICE_INTRO 430 "\n", 431 bounce_strtype(s->msg->bounce.type), 432 s->smtpname, 433 s->msg->to, 434 time_to_text(time(NULL))); 435 436 switch (s->msg->bounce.type) { 437 case B_ERROR: 438 iobuf_xfqueue(&s->iobuf, "bounce_next: BODY", 439 notice_error); 440 break; 441 case B_WARNING: 442 iobuf_xfqueue(&s->iobuf, "bounce_next: BODY", 443 notice_warning, 444 bounce_duration(s->msg->bounce.delay)); 445 break; 446 case B_DSN: 447 iobuf_xfqueue(&s->iobuf, "bounce_next: BODY", 448 s->msg->bounce.mta_without_dsn ? 449 notice_relay : notice_success); 450 break; 451 default: 452 log_warn("warn: bounce: unknown bounce_type"); 453 } 454 455 TAILQ_FOREACH(evp, &s->msg->envelopes, entry) { 456 iobuf_xfqueue(&s->iobuf, 457 "bounce_next: DATA_NOTICE", 458 "%s", evp->report); 459 } 460 iobuf_xfqueue(&s->iobuf, "bounce_next: DATA_NOTICE", "\n"); 461 462 if (s->msg->bounce.type == B_WARNING) 463 iobuf_xfqueue(&s->iobuf, "bounce_next: BODY", 464 notice_warning2, 465 bounce_duration(s->msg->bounce.expire)); 466 467 iobuf_xfqueue(&s->iobuf, "bounce_next: DATA_NOTICE", 468 " Below is a copy of the original message:\n" 469 "\n"); 470 471 log_trace(TRACE_BOUNCE, "bounce: %p: >>> [... %zu bytes ...]", 472 s, iobuf_queued(&s->iobuf)); 473 474 s->state = BOUNCE_DATA_MESSAGE; 475 break; 476 477 case BOUNCE_DATA_MESSAGE: 478 479 n = iobuf_queued(&s->iobuf); 480 481 while (iobuf_queued(&s->iobuf) < BOUNCE_HIWAT) { 482 line = fgetln(s->msgfp, &len); 483 if (line == NULL) 484 break; 485 if (len == 1 && line[0] == '\n' && /* end of headers */ 486 s->msg->bounce.type == B_DSN && 487 s->msg->bounce.dsn_ret == DSN_RETHDRS) { 488 fclose(s->msgfp); 489 s->msgfp = NULL; 490 bounce_send(s, "."); 491 s->state = BOUNCE_DATA_END; 492 return (0); 493 } 494 line[len - 1] = '\0'; 495 iobuf_xfqueue(&s->iobuf, 496 "bounce_next: DATA_MESSAGE", "%s%s\n", 497 (len == 2 && line[0] == '.') ? "." : "", line); 498 } 499 500 if (ferror(s->msgfp)) { 501 fclose(s->msgfp); 502 s->msgfp = NULL; 503 bounce_delivery(s->msg, IMSG_QUEUE_DELIVERY_TEMPFAIL, 504 "Error reading message"); 505 s->msg = NULL; 506 return (-1); 507 } 508 509 log_trace(TRACE_BOUNCE, "bounce: %p: >>> [... %zu bytes ...]", 510 s, iobuf_queued(&s->iobuf) - n); 511 512 if (feof(s->msgfp)) { 513 fclose(s->msgfp); 514 s->msgfp = NULL; 515 bounce_send(s, "."); 516 s->state = BOUNCE_DATA_END; 517 } 518 break; 519 520 case BOUNCE_QUIT: 521 bounce_send(s, "QUIT"); 522 s->state = BOUNCE_CLOSE; 523 break; 524 525 default: 526 fatalx("bounce: bad state"); 527 } 528 529 return (0); 530} 531 532 533static void 534bounce_delivery(struct bounce_message *msg, int delivery, const char *status) 535{ 536 struct bounce_envelope *be; 537 struct envelope evp; 538 size_t n; 539 const char *f; 540 541 n = 0; 542 while ((be = TAILQ_FIRST(&msg->envelopes))) { 543 if (delivery == IMSG_QUEUE_DELIVERY_TEMPFAIL) { 544 if (queue_envelope_load(be->id, &evp) == 0) { 545 fatalx("could not reload envelope!"); 546 } 547 evp.retry++; 548 evp.lasttry = msg->timeout; 549 envelope_set_errormsg(&evp, "%s", status); 550 queue_envelope_update(&evp); 551 m_create(p_scheduler, delivery, 0, 0, -1); 552 m_add_envelope(p_scheduler, &evp); 553 m_close(p_scheduler); 554 } else { 555 m_create(p_scheduler, delivery, 0, 0, -1); 556 m_add_evpid(p_scheduler, be->id); 557 m_close(p_scheduler); 558 queue_envelope_delete(be->id); 559 } 560 TAILQ_REMOVE(&msg->envelopes, be, entry); 561 free(be->report); 562 free(be); 563 n += 1; 564 } 565 566 567 if (delivery == IMSG_QUEUE_DELIVERY_TEMPFAIL) 568 f = "TempFail"; 569 else if (delivery == IMSG_QUEUE_DELIVERY_PERMFAIL) 570 f = "PermFail"; 571 else 572 f = NULL; 573 574 if (f) 575 log_warnx("warn: %s injecting failure report on message %08"PRIx32 576 " to <%s> for %zu envelope%s: %s", 577 f, msg->msgid, msg->to, n, n > 1 ? "s":"", status); 578 579 nmessage -= 1; 580 stat_decrement("bounce.message", 1); 581 stat_decrement("bounce.envelope", n); 582 free(msg->smtpname); 583 free(msg->to); 584 free(msg); 585} 586 587static void 588bounce_status(struct bounce_session *s, const char *fmt, ...) 589{ 590 va_list ap; 591 char *status; 592 int len, delivery; 593 594 /* Ignore if there is no message */ 595 if (s->msg == NULL) 596 return; 597 598 va_start(ap, fmt); 599 if ((len = vasprintf(&status, fmt, ap)) == -1) 600 fatal("bounce: vasprintf"); 601 va_end(ap); 602 603 if (*status == '2') 604 delivery = IMSG_QUEUE_DELIVERY_OK; 605 else if (*status == '5' || *status == '6') 606 delivery = IMSG_QUEUE_DELIVERY_PERMFAIL; 607 else 608 delivery = IMSG_QUEUE_DELIVERY_TEMPFAIL; 609 610 bounce_delivery(s->msg, delivery, status); 611 s->msg = NULL; 612 if (s->msgfp) 613 fclose(s->msgfp); 614 615 free(status); 616} 617 618static void 619bounce_free(struct bounce_session *s) 620{ 621 log_debug("debug: bounce: %p: deleting session", s); 622 623 iobuf_clear(&s->iobuf); 624 io_clear(&s->io); 625 626 free(s->smtpname); 627 free(s); 628 629 running -= 1; 630 stat_decrement("bounce.session", 1); 631 bounce_drain(); 632} 633 634static void 635bounce_io(struct io *io, int evt) 636{ 637 struct bounce_session *s = io->arg; 638 const char *error; 639 char *line, *msg; 640 int cont; 641 size_t len; 642 643 log_trace(TRACE_IO, "bounce: %p: %s %s", s, io_strevent(evt), 644 io_strio(io)); 645 646 switch (evt) { 647 case IO_DATAIN: 648 nextline: 649 line = iobuf_getline(&s->iobuf, &len); 650 if (line == NULL && iobuf_len(&s->iobuf) >= SMTPD_MAXLINESIZE) { 651 bounce_status(s, "Input too long"); 652 bounce_free(s); 653 return; 654 } 655 656 if (line == NULL) { 657 iobuf_normalize(&s->iobuf); 658 break; 659 } 660 661 log_trace(TRACE_BOUNCE, "bounce: %p: <<< %s", s, line); 662 663 if ((error = parse_smtp_response(line, len, &msg, &cont))) { 664 bounce_status(s, "Bad response: %s", error); 665 bounce_free(s); 666 return; 667 } 668 if (cont) 669 goto nextline; 670 671 if (s->state == BOUNCE_CLOSE) { 672 bounce_free(s); 673 return; 674 } 675 676 if (line[0] != '2' && line[0] != '3') { /* fail */ 677 bounce_status(s, "%s", line); 678 s->state = BOUNCE_QUIT; 679 } else if (s->state == BOUNCE_DATA_END) { /* accepted */ 680 bounce_status(s, "%s", line); 681 } 682 683 if (bounce_next(s) == -1) { 684 bounce_free(s); 685 return; 686 } 687 688 io_set_write(io); 689 break; 690 691 case IO_LOWAT: 692 if (s->state == BOUNCE_DATA_MESSAGE) 693 if (bounce_next(s) == -1) { 694 bounce_free(s); 695 return; 696 } 697 if (iobuf_queued(&s->iobuf) == 0) 698 io_set_read(io); 699 break; 700 701 default: 702 bounce_status(s, "442 i/o error %d", evt); 703 bounce_free(s); 704 break; 705 } 706} 707 708static int 709bounce_message_cmp(const struct bounce_message *a, 710 const struct bounce_message *b) 711{ 712 int r; 713 714 if (a->msgid < b->msgid) 715 return (-1); 716 if (a->msgid > b->msgid) 717 return (1); 718 if ((r = strcmp(a->smtpname, b->smtpname))) 719 return (r); 720 721 return memcmp(&a->bounce, &b->bounce, sizeof (a->bounce)); 722} 723 724static const char * 725bounce_strtype(enum bounce_type t) 726{ 727 switch (t) { 728 case B_ERROR: 729 return ("error"); 730 case B_WARNING: 731 return ("warning"); 732 case B_DSN: 733 return ("dsn"); 734 default: 735 log_warn("warn: bounce: unknown bounce_type"); 736 return (""); 737 } 738} 739 740SPLAY_GENERATE(bounce_message_tree, bounce_message, sp_entry, 741 bounce_message_cmp); 742