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