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