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