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