xref: /openbsd-src/usr.sbin/smtpd/mda.c (revision ae3cb403620ab940fbaabb3055fac045a63d56b7)
1 /*	$OpenBSD: mda.c,v 1.128 2017/11/21 12:20:34 eric Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
5  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
6  * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net>
7  * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 #include <sys/types.h>
23 #include <sys/queue.h>
24 #include <sys/tree.h>
25 #include <sys/socket.h>
26 
27 #include <ctype.h>
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 #include <vis.h>
42 
43 #include "smtpd.h"
44 #include "log.h"
45 
46 #define MDA_HIWAT		65536
47 
48 struct mda_envelope {
49 	TAILQ_ENTRY(mda_envelope)	 entry;
50 	uint64_t			 id;
51 	time_t				 creation;
52 	char				*sender;
53 	char				*dest;
54 	char				*rcpt;
55 	enum action_type		 method;
56 	char				*user;
57 	char				*buffer;
58 };
59 
60 #define USER_WAITINFO	0x01
61 #define USER_RUNNABLE	0x02
62 #define USER_ONHOLD	0x04
63 #define USER_HOLDQ	0x08
64 
65 struct mda_user {
66 	uint64_t			id;
67 	TAILQ_ENTRY(mda_user)		entry;
68 	TAILQ_ENTRY(mda_user)		entry_runnable;
69 	char				name[LOGIN_NAME_MAX];
70 	char				usertable[PATH_MAX];
71 	size_t				evpcount;
72 	TAILQ_HEAD(, mda_envelope)	envelopes;
73 	int				flags;
74 	size_t				running;
75 	struct userinfo			userinfo;
76 };
77 
78 struct mda_session {
79 	uint64_t		 id;
80 	struct mda_user		*user;
81 	struct mda_envelope	*evp;
82 	struct io		*io;
83 	FILE			*datafp;
84 };
85 
86 static void mda_io(struct io *, int, void *);
87 static int mda_check_loop(FILE *, struct mda_envelope *);
88 static int mda_getlastline(int, char *, size_t);
89 static void mda_done(struct mda_session *);
90 static void mda_fail(struct mda_user *, int, const char *,
91     enum enhanced_status_code);
92 static void mda_drain(void);
93 static void mda_log(const struct mda_envelope *, const char *, const char *);
94 static void mda_queue_ok(uint64_t);
95 static void mda_queue_tempfail(uint64_t, const char *,
96     enum enhanced_status_code);
97 static void mda_queue_permfail(uint64_t, const char *, enum enhanced_status_code);
98 static void mda_queue_loop(uint64_t);
99 static struct mda_user *mda_user(const struct envelope *);
100 static void mda_user_free(struct mda_user *);
101 static const char *mda_user_to_text(const struct mda_user *);
102 static struct mda_envelope *mda_envelope(const struct envelope *);
103 static void mda_envelope_free(struct mda_envelope *);
104 static struct mda_session * mda_session(struct mda_user *);
105 
106 static struct tree	sessions;
107 static struct tree	users;
108 
109 static TAILQ_HEAD(, mda_user)	runnable;
110 
111 void
112 mda_imsg(struct mproc *p, struct imsg *imsg)
113 {
114 	struct mda_session	*s;
115 	struct mda_user		*u;
116 	struct mda_envelope	*e;
117 	struct envelope		 evp;
118 	struct userinfo		*userinfo;
119 	struct deliver		 deliver;
120 	struct msg		 m;
121 	const void		*data;
122 	const char		*error, *parent_error;
123 	uint64_t		 reqid;
124 	time_t			 now;
125 	size_t			 sz;
126 	char			 out[256], buf[LINE_MAX];
127 	int			 n;
128 	enum lka_resp_status	status;
129 
130 	switch (imsg->hdr.type) {
131 	case IMSG_MDA_LOOKUP_USERINFO:
132 		m_msg(&m, imsg);
133 		m_get_id(&m, &reqid);
134 		m_get_int(&m, (int *)&status);
135 		if (status == LKA_OK)
136 			m_get_data(&m, &data, &sz);
137 		m_end(&m);
138 
139 		u = tree_xget(&users, reqid);
140 
141 		if (status == LKA_TEMPFAIL)
142 			mda_fail(u, 0,
143 			    "Temporary failure in user lookup",
144 			    ESC_OTHER_ADDRESS_STATUS);
145 		else if (status == LKA_PERMFAIL)
146 			mda_fail(u, 1,
147 			    "Permanent failure in user lookup",
148 			    ESC_DESTINATION_MAILBOX_HAS_MOVED);
149 		else {
150 			if (sz != sizeof(u->userinfo))
151 				fatalx("mda: userinfo size mismatch");
152 			memmove(&u->userinfo, data, sz);
153 			u->flags &= ~USER_WAITINFO;
154 			u->flags |= USER_RUNNABLE;
155 			TAILQ_INSERT_TAIL(&runnable, u, entry_runnable);
156 			mda_drain();
157 		}
158 		return;
159 
160 	case IMSG_QUEUE_DELIVER:
161 		m_msg(&m, imsg);
162 		m_get_envelope(&m, &evp);
163 		m_end(&m);
164 
165 		u = mda_user(&evp);
166 
167 		if (u->evpcount >= env->sc_mda_task_hiwat) {
168 			if (!(u->flags & USER_ONHOLD)) {
169 				log_debug("debug: mda: hiwat reached for "
170 				    "user \"%s\": holding envelopes",
171 				    mda_user_to_text(u));
172 				u->flags |= USER_ONHOLD;
173 			}
174 		}
175 
176 		if (u->flags & USER_ONHOLD) {
177 			u->flags |= USER_HOLDQ;
178 			m_create(p_queue, IMSG_MDA_DELIVERY_HOLD,
179 			    0, 0, -1);
180 			m_add_evpid(p_queue, evp.id);
181 			m_add_id(p_queue, u->id);
182 			m_close(p_queue);
183 			return;
184 		}
185 
186 		e = mda_envelope(&evp);
187 		TAILQ_INSERT_TAIL(&u->envelopes, e, entry);
188 		u->evpcount += 1;
189 		stat_increment("mda.pending", 1);
190 
191 		if (!(u->flags & USER_RUNNABLE) &&
192 		    !(u->flags & USER_WAITINFO)) {
193 			u->flags |= USER_RUNNABLE;
194 			TAILQ_INSERT_TAIL(&runnable, u, entry_runnable);
195 		}
196 
197 		mda_drain();
198 		return;
199 
200 	case IMSG_MDA_OPEN_MESSAGE:
201 		m_msg(&m, imsg);
202 		m_get_id(&m, &reqid);
203 		m_end(&m);
204 
205 		s = tree_xget(&sessions, reqid);
206 		e = s->evp;
207 
208 		if (imsg->fd == -1) {
209 			log_debug("debug: mda: cannot get message fd");
210 			mda_queue_tempfail(e->id,
211 			    "Cannot get message fd",
212 			    ESC_OTHER_MAIL_SYSTEM_STATUS);
213 			mda_log(e, "TempFail", "Cannot get message fd");
214 			mda_done(s);
215 			return;
216 		}
217 
218 		log_debug("debug: mda: got message fd %d "
219 		    "for session %016"PRIx64 " evpid %016"PRIx64,
220 		    imsg->fd, s->id, e->id);
221 
222 		if ((s->datafp = fdopen(imsg->fd, "r")) == NULL) {
223 			log_warn("warn: mda: fdopen");
224 			close(imsg->fd);
225 			mda_queue_tempfail(e->id, "fdopen failed",
226 			    ESC_OTHER_MAIL_SYSTEM_STATUS);
227 			mda_log(e, "TempFail", "fdopen failed");
228 			mda_done(s);
229 			return;
230 		}
231 
232 		/* check delivery loop */
233 		if (mda_check_loop(s->datafp, e)) {
234 			log_debug("debug: mda: loop detected");
235 			mda_queue_loop(e->id);
236 			mda_log(e, "PermFail", "Loop detected");
237 			mda_done(s);
238 			return;
239 		}
240 
241 		n = 0;
242 		/*
243 		 * prepend "From " separator ... for
244 		 * A_MDA and A_FILENAME backends only
245 		 */
246 		if (e->method == A_MDA || e->method == A_FILENAME) {
247 			time(&now);
248 			if (e->sender[0])
249 				n = io_printf(s->io, "From %s %s",
250 				    e->sender, ctime(&now));
251 			else
252 				n = io_printf(s->io,
253 				    "From MAILER-DAEMON@%s %s",
254 				    env->sc_hostname, ctime(&now));
255 		}
256 		if (n != -1) {
257 			/* start queueing delivery headers */
258 			if (e->sender[0])
259 				/*
260 				 * XXX: remove existing Return-Path,
261 				 * if any
262 				 */
263 				n = io_printf(s->io,
264 				    "Return-Path: %s\n"
265 				    "Delivered-To: %s\n",
266 				    e->sender,
267 				    e->rcpt ? e->rcpt : e->dest);
268 			else
269 				n = io_printf(s->io,
270 				    "Delivered-To: %s\n",
271 				    e->rcpt ? e->rcpt : e->dest);
272 		}
273 		if (n == -1) {
274 			log_warn("warn: mda: "
275 			    "fail to write delivery info");
276 			mda_queue_tempfail(e->id, "Out of memory",
277 			    ESC_OTHER_MAIL_SYSTEM_STATUS);
278 			mda_log(e, "TempFail", "Out of memory");
279 			mda_done(s);
280 			return;
281 		}
282 
283 		/* request parent to fork a helper process */
284 		userinfo = &s->user->userinfo;
285 		memset(&deliver, 0, sizeof deliver);
286 		switch (e->method) {
287 		case A_MDA:
288 			deliver.mode = A_MDA;
289 			deliver.userinfo = *userinfo;
290 			(void)strlcpy(deliver.user, userinfo->username,
291 			    sizeof(deliver.user));
292 			if (strlcpy(deliver.to, e->buffer,
293 				sizeof(deliver.to))
294 			    >= sizeof(deliver.to)) {
295 				mda_queue_tempfail(e->id,
296 				    "mda command too long",
297 				    ESC_OTHER_MAIL_SYSTEM_STATUS);
298 				mda_log(e, "TempFail",
299 				    "mda command too long");
300 				mda_done(s);
301 				return;
302 			}
303 			break;
304 
305 		case A_MBOX:
306 			/*
307 			 * MBOX is a special case as we MUST
308 			 * deliver as root, just override the uid.
309 			 */
310 			deliver.mode = A_MBOX;
311 			deliver.userinfo = *userinfo;
312 			deliver.userinfo.uid = 0;
313 			(void)strlcpy(deliver.user, "root",
314 			    sizeof(deliver.user));
315 			(void)strlcpy(deliver.from, e->sender,
316 			    sizeof(deliver.from));
317 			(void)strlcpy(deliver.to, userinfo->username,
318 			    sizeof(deliver.to));
319 			break;
320 
321 		case A_MAILDIR:
322 			deliver.mode = A_MAILDIR;
323 			deliver.userinfo = *userinfo;
324 			(void)strlcpy(deliver.user, userinfo->username,
325 			    sizeof(deliver.user));
326 			(void)strlcpy(deliver.dest, e->dest,
327 			    sizeof(deliver.dest));
328 			if (strlcpy(deliver.to, e->buffer,
329 				sizeof(deliver.to))
330 			    >= sizeof(deliver.to)) {
331 				log_warn("warn: mda: "
332 				    "deliver buffer too large");
333 				mda_queue_tempfail(e->id,
334 				    "Maildir path too long",
335 				    ESC_OTHER_MAIL_SYSTEM_STATUS);
336 				mda_log(e, "TempFail",
337 				    "Maildir path too long");
338 				mda_done(s);
339 				return;
340 			}
341 			break;
342 
343 		case A_FILENAME:
344 			deliver.mode = A_FILENAME;
345 			deliver.userinfo = *userinfo;
346 			(void)strlcpy(deliver.user, userinfo->username,
347 			    sizeof deliver.user);
348 			if (strlcpy(deliver.to, e->buffer,
349 				sizeof(deliver.to))
350 			    >= sizeof(deliver.to)) {
351 				log_warn("warn: mda: "
352 				    "deliver buffer too large");
353 				mda_queue_tempfail(e->id,
354 				    "filename path too long",
355 				    ESC_OTHER_MAIL_SYSTEM_STATUS);
356 				mda_log(e, "TempFail",
357 				    "filename path too long");
358 				mda_done(s);
359 				return;
360 			}
361 			break;
362 
363 		case A_LMTP:
364 			deliver.mode = A_LMTP;
365 			deliver.userinfo = *userinfo;
366 			(void)strlcpy(deliver.user, e->user,
367 			    sizeof(deliver.user));
368 			(void)strlcpy(deliver.from, e->sender,
369 			    sizeof(deliver.from));
370 			(void)strlcpy(deliver.dest, e->dest,
371 			    sizeof(deliver.dest));
372 			if (strlcpy(deliver.to, e->buffer,
373 				sizeof(deliver.to))
374 			    >= sizeof(deliver.to)) {
375 				log_warn("warn: mda: "
376 				    "deliver buffer too large");
377 				mda_queue_tempfail(e->id,
378 				    "socket path too long",
379 				    ESC_OTHER_MAIL_SYSTEM_STATUS);
380 				mda_log(e, "TempFail",
381 				    "socket path too long");
382 				mda_done(s);
383 				return;
384 			}
385 			break;
386 
387 		default:
388 			errx(1, "mda: unknown delivery method: %d",
389 			    e->method);
390 		}
391 
392 		log_debug("debug: mda: querying mda fd "
393 		    "for session %016"PRIx64 " evpid %016"PRIx64,
394 		    s->id, s->evp->id);
395 
396 		m_create(p_parent, IMSG_MDA_FORK, 0, 0, -1);
397 		m_add_id(p_parent, reqid);
398 		m_add_data(p_parent, &deliver, sizeof(deliver));
399 		m_close(p_parent);
400 		return;
401 
402 	case IMSG_MDA_FORK:
403 		m_msg(&m, imsg);
404 		m_get_id(&m, &reqid);
405 		m_end(&m);
406 
407 		s = tree_xget(&sessions, reqid);
408 		e = s->evp;
409 		if (imsg->fd == -1) {
410 			log_warn("warn: mda: fail to retrieve mda fd");
411 			mda_queue_tempfail(e->id, "Cannot get mda fd",
412 			    ESC_OTHER_MAIL_SYSTEM_STATUS);
413 			mda_log(e, "TempFail", "Cannot get mda fd");
414 			mda_done(s);
415 			return;
416 		}
417 
418 		log_debug("debug: mda: got mda fd %d "
419 		    "for session %016"PRIx64 " evpid %016"PRIx64,
420 		    imsg->fd, s->id, s->evp->id);
421 
422 		io_set_nonblocking(imsg->fd);
423 		io_set_fd(s->io, imsg->fd);
424 		io_set_write(s->io);
425 		return;
426 
427 	case IMSG_MDA_DONE:
428 		m_msg(&m, imsg);
429 		m_get_id(&m, &reqid);
430 		m_get_string(&m, &parent_error);
431 		m_end(&m);
432 
433 		s = tree_xget(&sessions, reqid);
434 		e = s->evp;
435 		/*
436 		 * Grab last line of mda stdout/stderr if available.
437 		 */
438 		out[0] = '\0';
439 		if (imsg->fd != -1)
440 			mda_getlastline(imsg->fd, out, sizeof(out));
441 		/*
442 		 * Choose between parent's description of error and
443 		 * child's output, the latter having preference over
444 		 * the former.
445 		 */
446 		error = NULL;
447 		if (strcmp(parent_error, "exited okay") == 0) {
448 			if (s->datafp || (s->io && io_queued(s->io)))
449 				error = "mda exited prematurely";
450 		} else
451 			error = out[0] ? out : parent_error;
452 
453 		/* update queue entry */
454 		if (error) {
455 			mda_queue_tempfail(e->id, error,
456 			    ESC_OTHER_MAIL_SYSTEM_STATUS);
457 			(void)snprintf(buf, sizeof buf,
458 			    "Error (%s)", error);
459 			mda_log(e, "TempFail", buf);
460 		}
461 		else {
462 			mda_queue_ok(e->id);
463 			mda_log(e, "Ok", "Delivered");
464 		}
465 		mda_done(s);
466 		return;
467 	}
468 
469 	errx(1, "mda_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
470 }
471 
472 void
473 mda_postfork()
474 {
475 }
476 
477 void
478 mda_postprivdrop()
479 {
480 	tree_init(&sessions);
481 	tree_init(&users);
482 	TAILQ_INIT(&runnable);
483 }
484 
485 static void
486 mda_io(struct io *io, int evt, void *arg)
487 {
488 	struct mda_session	*s = arg;
489 	char			*ln = NULL;
490 	size_t			 sz = 0;
491 	ssize_t			 len;
492 
493 	log_trace(TRACE_IO, "mda: %p: %s %s", s, io_strevent(evt),
494 	    io_strio(io));
495 
496 	switch (evt) {
497 	case IO_LOWAT:
498 
499 	/* done */
500 	done:
501 		if (s->datafp == NULL) {
502 			log_debug("debug: mda: all data sent for session"
503 			    " %016"PRIx64 " evpid %016"PRIx64,
504 			    s->id, s->evp->id);
505 			io_free(io);
506 			s->io = NULL;
507 			return;
508 		}
509 
510 		while (io_queued(s->io) < MDA_HIWAT) {
511 			if ((len = getline(&ln, &sz, s->datafp)) == -1)
512 				break;
513 			if (io_write(s->io, ln, len) == -1) {
514 				m_create(p_parent, IMSG_MDA_KILL,
515 				    0, 0, -1);
516 				m_add_id(p_parent, s->id);
517 				m_add_string(p_parent, "Out of memory");
518 				m_close(p_parent);
519 				io_pause(io, IO_OUT);
520 				free(ln);
521 				return;
522 			}
523 		}
524 
525 		free(ln);
526 		ln = NULL;
527 		if (ferror(s->datafp)) {
528 			log_debug("debug: mda: ferror on session %016"PRIx64,
529 			    s->id);
530 			m_create(p_parent, IMSG_MDA_KILL, 0, 0, -1);
531 			m_add_id(p_parent, s->id);
532 			m_add_string(p_parent, "Error reading body");
533 			m_close(p_parent);
534 			io_pause(io, IO_OUT);
535 			return;
536 		}
537 
538 		if (feof(s->datafp)) {
539 			log_debug("debug: mda: end-of-file for session"
540 			    " %016"PRIx64 " evpid %016"PRIx64,
541 			    s->id, s->evp->id);
542 			fclose(s->datafp);
543 			s->datafp = NULL;
544 			if (io_queued(s->io) == 0)
545 				goto done;
546 		}
547 		return;
548 
549 	case IO_TIMEOUT:
550 		log_debug("debug: mda: timeout on session %016"PRIx64, s->id);
551 		io_pause(io, IO_OUT);
552 		return;
553 
554 	case IO_ERROR:
555 		log_debug("debug: mda: io error on session %016"PRIx64": %s",
556 		    s->id, io_error(io));
557 		io_pause(io, IO_OUT);
558 		return;
559 
560 	case IO_DISCONNECTED:
561 		log_debug("debug: mda: io disconnected on session %016"PRIx64,
562 		    s->id);
563 		io_pause(io, IO_OUT);
564 		return;
565 
566 	default:
567 		log_debug("debug: mda: unexpected event on session %016"PRIx64,
568 		    s->id);
569 		io_pause(io, IO_OUT);
570 		return;
571 	}
572 }
573 
574 static int
575 mda_check_loop(FILE *fp, struct mda_envelope *e)
576 {
577 	char		*buf = NULL;
578 	size_t		 sz = 0;
579 	ssize_t		 len;
580 	int		 ret = 0;
581 
582 	while ((len = getline(&buf, &sz, fp)) != -1) {
583 		if (buf[len - 1] == '\n')
584 			buf[len - 1] = '\0';
585 
586 		if (strchr(buf, ':') == NULL && !isspace((unsigned char)*buf))
587 			break;
588 
589 		if (strncasecmp("Delivered-To: ", buf, 14) == 0) {
590 			if (strcasecmp(buf + 14, e->dest) == 0) {
591 				ret = 1;
592 				break;
593 			}
594 		}
595 	}
596 
597 	free(buf);
598 	fseek(fp, SEEK_SET, 0);
599 	return (ret);
600 }
601 
602 static int
603 mda_getlastline(int fd, char *dst, size_t dstsz)
604 {
605 	FILE	*fp;
606 	char	*ln = NULL;
607 	size_t	 sz = 0;
608 	ssize_t	 len;
609 	int	 out = 0;
610 
611 	if (lseek(fd, 0, SEEK_SET) < 0) {
612 		log_warn("warn: mda: lseek");
613 		close(fd);
614 		return (-1);
615 	}
616 	fp = fdopen(fd, "r");
617 	if (fp == NULL) {
618 		log_warn("warn: mda: fdopen");
619 		close(fd);
620 		return (-1);
621 	}
622 	while ((len = getline(&ln, &sz, fp)) != -1) {
623 		if (ln[len - 1] == '\n')
624 			ln[len - 1] = '\0';
625 		out = 1;
626 	}
627 	fclose(fp);
628 
629 	if (out) {
630 		(void)strlcpy(dst, "\"", dstsz);
631 		(void)strnvis(dst + 1, ln, dstsz - 2, VIS_SAFE | VIS_CSTYLE);
632 		(void)strlcat(dst, "\"", dstsz);
633 	}
634 
635 	free(ln);
636 	return (0);
637 }
638 
639 static void
640 mda_fail(struct mda_user *user, int permfail, const char *error,
641     enum enhanced_status_code code)
642 {
643 	struct mda_envelope	*e;
644 
645 	while ((e = TAILQ_FIRST(&user->envelopes))) {
646 		TAILQ_REMOVE(&user->envelopes, e, entry);
647 		if (permfail) {
648 			mda_log(e, "PermFail", error);
649 			mda_queue_permfail(e->id, error, code);
650 		}
651 		else {
652 			mda_log(e, "TempFail", error);
653 			mda_queue_tempfail(e->id, error, code);
654 		}
655 		mda_envelope_free(e);
656 	}
657 
658 	mda_user_free(user);
659 }
660 
661 static void
662 mda_drain(void)
663 {
664 	struct mda_user		*u;
665 
666 	while ((u = (TAILQ_FIRST(&runnable)))) {
667 
668 		TAILQ_REMOVE(&runnable, u, entry_runnable);
669 
670 		if (u->evpcount == 0 && u->running == 0) {
671 			log_debug("debug: mda: all done for user \"%s\"",
672 			    mda_user_to_text(u));
673 			mda_user_free(u);
674 			continue;
675 		}
676 
677 		if (u->evpcount == 0) {
678 			log_debug("debug: mda: no more envelope for \"%s\"",
679 			    mda_user_to_text(u));
680 			u->flags &= ~USER_RUNNABLE;
681 			continue;
682 		}
683 
684 		if (u->running >= env->sc_mda_max_user_session) {
685 			log_debug("debug: mda: "
686 			    "maximum number of session reached for user \"%s\"",
687 			    mda_user_to_text(u));
688 			u->flags &= ~USER_RUNNABLE;
689 			continue;
690 		}
691 
692 		if (tree_count(&sessions) >= env->sc_mda_max_session) {
693 			log_debug("debug: mda: "
694 			    "maximum number of session reached");
695 			TAILQ_INSERT_HEAD(&runnable, u, entry_runnable);
696 			return;
697 		}
698 
699 		mda_session(u);
700 
701 		if (u->evpcount == env->sc_mda_task_lowat) {
702 			if (u->flags & USER_ONHOLD) {
703 				log_debug("debug: mda: down to lowat for user "
704 				    "\"%s\": releasing",
705 				    mda_user_to_text(u));
706 				u->flags &= ~USER_ONHOLD;
707 			}
708 			if (u->flags & USER_HOLDQ) {
709 				m_create(p_queue, IMSG_MDA_HOLDQ_RELEASE,
710 				    0, 0, -1);
711 				m_add_id(p_queue, u->id);
712 				m_add_int(p_queue, env->sc_mda_task_release);
713 				m_close(p_queue);
714 			}
715 		}
716 
717 		/* re-add the user at the tail of the queue */
718 		TAILQ_INSERT_TAIL(&runnable, u, entry_runnable);
719 	}
720 }
721 
722 static void
723 mda_done(struct mda_session *s)
724 {
725 	log_debug("debug: mda: session %016" PRIx64 " done", s->id);
726 
727 	tree_xpop(&sessions, s->id);
728 
729 	mda_envelope_free(s->evp);
730 
731 	s->user->running--;
732 	if (!(s->user->flags & USER_RUNNABLE)) {
733 		log_debug("debug: mda: user \"%s\" becomes runnable",
734 		    s->user->name);
735 		TAILQ_INSERT_TAIL(&runnable, s->user, entry_runnable);
736 		s->user->flags |= USER_RUNNABLE;
737 	}
738 
739 	if (s->datafp)
740 		fclose(s->datafp);
741 	if (s->io)
742 		io_free(s->io);
743 
744 	free(s);
745 
746 	stat_decrement("mda.running", 1);
747 
748 	mda_drain();
749 }
750 
751 static void
752 mda_log(const struct mda_envelope *evp, const char *prefix, const char *status)
753 {
754 	char rcpt[LINE_MAX];
755 	const char *method;
756 
757 	rcpt[0] = '\0';
758 	if (evp->rcpt)
759 		(void)snprintf(rcpt, sizeof rcpt, "rcpt=<%s>, ", evp->rcpt);
760 
761 	if (evp->method == A_MAILDIR)
762 		method = "maildir";
763 	else if (evp->method == A_MBOX)
764 		method = "mbox";
765 	else if (evp->method == A_FILENAME)
766 		method = "file";
767 	else if (evp->method == A_MDA)
768 		method = "mda";
769 	else if (evp->method == A_LMTP)
770 		method = "lmtp";
771 	else
772 		method = "???";
773 
774 	log_info("%016"PRIx64" mda event=delivery evpid=%016" PRIx64 " from=<%s> to=<%s> "
775 	    "%suser=%s method=%s delay=%s result=%s stat=%s",
776 	    (uint64_t)0,
777 	    evp->id,
778 	    evp->sender ? evp->sender : "",
779 	    evp->dest,
780 	    rcpt,
781 	    evp->user,
782 	    method,
783 	    duration_to_text(time(NULL) - evp->creation),
784 	    prefix,
785 	    status);
786 }
787 
788 static void
789 mda_queue_ok(uint64_t evpid)
790 {
791 	m_create(p_queue, IMSG_MDA_DELIVERY_OK, 0, 0, -1);
792 	m_add_evpid(p_queue, evpid);
793 	m_close(p_queue);
794 }
795 
796 static void
797 mda_queue_tempfail(uint64_t evpid, const char *reason,
798     enum enhanced_status_code code)
799 {
800 	m_create(p_queue, IMSG_MDA_DELIVERY_TEMPFAIL, 0, 0, -1);
801 	m_add_evpid(p_queue, evpid);
802 	m_add_string(p_queue, reason);
803 	m_add_int(p_queue, (int)code);
804 	m_close(p_queue);
805 }
806 
807 static void
808 mda_queue_permfail(uint64_t evpid, const char *reason,
809     enum enhanced_status_code code)
810 {
811 	m_create(p_queue, IMSG_MDA_DELIVERY_PERMFAIL, 0, 0, -1);
812 	m_add_evpid(p_queue, evpid);
813 	m_add_string(p_queue, reason);
814 	m_add_int(p_queue, (int)code);
815 	m_close(p_queue);
816 }
817 
818 static void
819 mda_queue_loop(uint64_t evpid)
820 {
821 	m_create(p_queue, IMSG_MDA_DELIVERY_LOOP, 0, 0, -1);
822 	m_add_evpid(p_queue, evpid);
823 	m_close(p_queue);
824 }
825 
826 static struct mda_user *
827 mda_user(const struct envelope *evp)
828 {
829 	struct mda_user	*u;
830 	void		*i;
831 
832 	i = NULL;
833 	while (tree_iter(&users, &i, NULL, (void**)(&u))) {
834 		if (!strcmp(evp->agent.mda.username, u->name) &&
835 		    !strcmp(evp->agent.mda.usertable, u->usertable))
836 			return (u);
837 	}
838 
839 	u = xcalloc(1, sizeof *u, "mda_user");
840 	u->id = generate_uid();
841 	TAILQ_INIT(&u->envelopes);
842 	(void)strlcpy(u->name, evp->agent.mda.username, sizeof(u->name));
843 	(void)strlcpy(u->usertable, evp->agent.mda.usertable,
844 	    sizeof(u->usertable));
845 
846 	tree_xset(&users, u->id, u);
847 
848 	m_create(p_lka, IMSG_MDA_LOOKUP_USERINFO, 0, 0, -1);
849 	m_add_id(p_lka, u->id);
850 	m_add_string(p_lka, evp->agent.mda.usertable);
851 	if (evp->agent.mda.delivery_user[0])
852 		m_add_string(p_lka, evp->agent.mda.delivery_user);
853 	else
854 		m_add_string(p_lka, evp->agent.mda.username);
855 	m_close(p_lka);
856 	u->flags |= USER_WAITINFO;
857 
858 	stat_increment("mda.user", 1);
859 
860 	if (evp->agent.mda.delivery_user[0])
861 		log_debug("mda: new user %016" PRIx64
862 		    " for \"%s\" delivering as \"%s\"",
863 		    u->id, mda_user_to_text(u), evp->agent.mda.delivery_user);
864 	else
865 		log_debug("mda: new user %016" PRIx64
866 		    " for \"%s\"", u->id, mda_user_to_text(u));
867 
868 	return (u);
869 }
870 
871 static void
872 mda_user_free(struct mda_user *u)
873 {
874 	tree_xpop(&users, u->id);
875 
876 	if (u->flags & USER_HOLDQ) {
877 		m_create(p_queue, IMSG_MDA_HOLDQ_RELEASE, 0, 0, -1);
878 		m_add_id(p_queue, u->id);
879 		m_add_int(p_queue, 0);
880 		m_close(p_queue);
881 	}
882 
883 	free(u);
884 	stat_decrement("mda.user", 1);
885 }
886 
887 static const char *
888 mda_user_to_text(const struct mda_user *u)
889 {
890 	static char buf[1024];
891 
892 	(void)snprintf(buf, sizeof(buf), "%s:%s", u->usertable, u->name);
893 
894 	return (buf);
895 }
896 
897 static struct mda_envelope *
898 mda_envelope(const struct envelope *evp)
899 {
900 	struct mda_envelope	*e;
901 	char			 buf[LINE_MAX];
902 
903 	e = xcalloc(1, sizeof *e, "mda_envelope");
904 	e->id = evp->id;
905 	e->creation = evp->creation;
906 	buf[0] = '\0';
907 	if (evp->sender.user[0] && evp->sender.domain[0])
908 		(void)snprintf(buf, sizeof buf, "%s@%s",
909 		    evp->sender.user, evp->sender.domain);
910 	e->sender = xstrdup(buf, "mda_envelope:sender");
911 	(void)snprintf(buf, sizeof buf, "%s@%s", evp->dest.user,
912 	    evp->dest.domain);
913 	e->dest = xstrdup(buf, "mda_envelope:dest");
914 	(void)snprintf(buf, sizeof buf, "%s@%s", evp->rcpt.user,
915 	    evp->rcpt.domain);
916 	if (strcmp(buf, e->dest))
917 		e->rcpt = xstrdup(buf, "mda_envelope:rcpt");
918 	e->method = evp->agent.mda.method;
919 	e->buffer = xstrdup(evp->agent.mda.buffer, "mda_envelope:buffer");
920 	e->user = xstrdup(evp->agent.mda.username, "mda_envelope:user");
921 
922 	stat_increment("mda.envelope", 1);
923 
924 	return (e);
925 }
926 
927 static void
928 mda_envelope_free(struct mda_envelope *e)
929 {
930 	free(e->sender);
931 	free(e->dest);
932 	free(e->rcpt);
933 	free(e->user);
934 	free(e->buffer);
935 	free(e);
936 
937 	stat_decrement("mda.envelope", 1);
938 }
939 
940 static struct mda_session *
941 mda_session(struct mda_user * u)
942 {
943 	struct mda_session *s;
944 
945 	s = xcalloc(1, sizeof *s, "mda_session");
946 	s->id = generate_uid();
947 	s->user = u;
948 	s->io = io_new();
949 	io_set_callback(s->io, mda_io, s);
950 
951 	tree_xset(&sessions, s->id, s);
952 
953 	s->evp = TAILQ_FIRST(&u->envelopes);
954 	TAILQ_REMOVE(&u->envelopes, s->evp, entry);
955 	u->evpcount--;
956 	u->running++;
957 
958 	stat_decrement("mda.pending", 1);
959 	stat_increment("mda.running", 1);
960 
961 	log_debug("debug: mda: new session %016" PRIx64
962 	    " for user \"%s\" evpid %016" PRIx64, s->id,
963 	    mda_user_to_text(u), s->evp->id);
964 
965 	m_create(p_queue, IMSG_MDA_OPEN_MESSAGE, 0, 0, -1);
966 	m_add_id(p_queue, s->id);
967 	m_add_msgid(p_queue, evpid_to_msgid(s->evp->id));
968 	m_close(p_queue);
969 
970 	return (s);
971 }
972