GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/smtpd/smtpd/../bounce.c Lines: 0 373 0.0 %
Date: 2017-11-07 Branches: 0 220 0.0 %

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