1 /* 2 * Copyright (c) 2008 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Simon 'corecode' Schubert <corecode@fs.ei.tum.de>. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $DragonFly: src/libexec/dma/dma.c,v 1.3 2008/02/04 08:58:54 matthias Exp $ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/queue.h> 39 #include <sys/stat.h> 40 #include <sys/types.h> 41 42 #ifdef HAVE_CRYPTO 43 #include <openssl/ssl.h> 44 #endif /* HAVE_CRYPTO */ 45 46 #include <dirent.h> 47 #include <err.h> 48 #include <errno.h> 49 #include <fcntl.h> 50 #include <inttypes.h> 51 #include <netdb.h> 52 #include <paths.h> 53 #include <pwd.h> 54 #include <signal.h> 55 #include <stdarg.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <syslog.h> 60 #include <unistd.h> 61 62 #include "dma.h" 63 64 65 66 static void deliver(struct qitem *); 67 static int add_recp(struct queue *, const char *, const char *, int); 68 69 struct aliases aliases = LIST_HEAD_INITIALIZER(aliases); 70 static struct strlist tmpfs = SLIST_HEAD_INITIALIZER(tmpfs); 71 struct virtusers virtusers = LIST_HEAD_INITIALIZER(virtusers); 72 struct authusers authusers = LIST_HEAD_INITIALIZER(authusers); 73 static int daemonize = 1; 74 struct config *config; 75 76 char * 77 hostname(void) 78 { 79 static char name[MAXHOSTNAMELEN+1]; 80 81 if (gethostname(name, sizeof(name)) != 0) 82 strcpy(name, "(unknown hostname)"); 83 84 return name; 85 } 86 87 static char * 88 set_from(const char *osender) 89 { 90 struct virtuser *v; 91 char *sender; 92 93 if ((config->features & VIRTUAL) != 0) { 94 SLIST_FOREACH(v, &virtusers, next) { 95 if (strcmp(v->login, getlogin()) == 0) { 96 sender = strdup(v->address); 97 if (sender == NULL) 98 return(NULL); 99 goto out; 100 } 101 } 102 } 103 104 if (osender) { 105 sender = strdup(osender); 106 if (sender == NULL) 107 return (NULL); 108 } else { 109 if (asprintf(&sender, "%s@%s", getlogin(), hostname()) <= 0) 110 return (NULL); 111 } 112 113 if (strchr(sender, '\n') != NULL) { 114 errno = EINVAL; 115 return (NULL); 116 } 117 118 out: 119 return (sender); 120 } 121 122 static int 123 read_aliases(void) 124 { 125 yyin = fopen(config->aliases, "r"); 126 if (yyin == NULL) 127 return (0); /* not fatal */ 128 if (yyparse()) 129 return (-1); /* fatal error, probably malloc() */ 130 fclose(yyin); 131 return (0); 132 } 133 134 static int 135 add_recp(struct queue *queue, const char *str, const char *sender, int expand) 136 { 137 struct qitem *it, *tit; 138 struct stritem *sit; 139 struct alias *al; 140 struct passwd *pw; 141 char *host; 142 int aliased = 0; 143 144 it = calloc(1, sizeof(*it)); 145 if (it == NULL) 146 return (-1); 147 it->addr = strdup(str); 148 if (it->addr == NULL) 149 return (-1); 150 151 it->sender = sender; 152 host = strrchr(it->addr, '@'); 153 if (host != NULL && 154 (strcmp(host + 1, hostname()) == 0 || 155 strcmp(host + 1, "localhost") == 0)) { 156 *host = 0; 157 } 158 LIST_FOREACH(tit, &queue->queue, next) { 159 /* weed out duplicate dests */ 160 if (strcmp(tit->addr, it->addr) == 0) { 161 free(it->addr); 162 free(it); 163 return (0); 164 } 165 } 166 LIST_INSERT_HEAD(&queue->queue, it, next); 167 if (strrchr(it->addr, '@') == NULL) { 168 it->remote = 0; 169 if (expand) { 170 LIST_FOREACH(al, &aliases, next) { 171 if (strcmp(al->alias, it->addr) != 0) 172 continue; 173 SLIST_FOREACH(sit, &al->dests, next) { 174 if (add_recp(queue, sit->str, sender, 1) != 0) 175 return (-1); 176 } 177 aliased = 1; 178 } 179 if (aliased) { 180 LIST_REMOVE(it, next); 181 } else { 182 /* Local destination, check */ 183 pw = getpwnam(it->addr); 184 if (pw == NULL) 185 goto out; 186 endpwent(); 187 } 188 } 189 } else { 190 it->remote = 1; 191 } 192 193 return (0); 194 195 out: 196 free(it->addr); 197 free(it); 198 return (-1); 199 } 200 201 static void 202 deltmp(void) 203 { 204 struct stritem *t; 205 206 SLIST_FOREACH(t, &tmpfs, next) { 207 unlink(t->str); 208 } 209 } 210 211 static int 212 gentempf(struct queue *queue) 213 { 214 char fn[PATH_MAX+1]; 215 struct stritem *t; 216 int fd; 217 218 if (snprintf(fn, sizeof(fn), "%s/%s", config->spooldir, "tmp_XXXXXXXXXX") <= 0) 219 return (-1); 220 fd = mkstemp(fn); 221 if (fd < 0) 222 return (-1); 223 queue->mailfd = fd; 224 queue->tmpf = strdup(fn); 225 if (queue->tmpf == NULL) { 226 unlink(fn); 227 return (-1); 228 } 229 t = malloc(sizeof(*t)); 230 if (t != NULL) { 231 t->str = queue->tmpf; 232 SLIST_INSERT_HEAD(&tmpfs, t, next); 233 } 234 return (0); 235 } 236 237 /* 238 * spool file format: 239 * 240 * envelope-from 241 * queue-id1 envelope-to1 242 * queue-id2 envelope-to2 243 * ... 244 * <empty line> 245 * mail data 246 * 247 * queue ids are unique, formed from the inode of the spool file 248 * and a unique identifier. 249 */ 250 static int 251 preparespool(struct queue *queue, const char *sender) 252 { 253 char line[1000]; /* by RFC2822 */ 254 struct stat st; 255 int error; 256 struct qitem *it; 257 FILE *queuef; 258 off_t hdrlen; 259 260 error = snprintf(line, sizeof(line), "%s\n", sender); 261 if (error < 0 || (size_t)error >= sizeof(line)) { 262 errno = E2BIG; 263 return (-1); 264 } 265 if (write(queue->mailfd, line, error) != error) 266 return (-1); 267 268 queuef = fdopen(queue->mailfd, "r+"); 269 if (queuef == NULL) 270 return (-1); 271 272 /* 273 * Assign queue id to each dest. 274 */ 275 if (fstat(queue->mailfd, &st) != 0) 276 return (-1); 277 queue->id = st.st_ino; 278 LIST_FOREACH(it, &queue->queue, next) { 279 if (asprintf(&it->queueid, "%"PRIxMAX".%"PRIxPTR, 280 queue->id, (uintptr_t)it) <= 0) 281 return (-1); 282 if (asprintf(&it->queuefn, "%s/%s", 283 config->spooldir, it->queueid) <= 0) 284 return (-1); 285 /* File may not exist yet */ 286 if (stat(it->queuefn, &st) == 0) 287 return (-1); 288 it->queuef = queuef; 289 error = snprintf(line, sizeof(line), "%s %s\n", 290 it->queueid, it->addr); 291 if (error < 0 || (size_t)error >= sizeof(line)) 292 return (-1); 293 if (write(queue->mailfd, line, error) != error) 294 return (-1); 295 } 296 line[0] = '\n'; 297 if (write(queue->mailfd, line, 1) != 1) 298 return (-1); 299 300 hdrlen = lseek(queue->mailfd, 0, SEEK_CUR); 301 LIST_FOREACH(it, &queue->queue, next) { 302 it->hdrlen = hdrlen; 303 } 304 return (0); 305 } 306 307 static char * 308 rfc822date(void) 309 { 310 static char str[50]; 311 size_t error; 312 time_t now; 313 314 now = time(NULL); 315 error = strftime(str, sizeof(str), "%a, %d %b %Y %T %z", 316 localtime(&now)); 317 if (error == 0) 318 strcpy(str, "(date fail)"); 319 return (str); 320 } 321 322 static int 323 readmail(struct queue *queue, const char *sender, int nodot) 324 { 325 char line[1000]; /* by RFC2822 */ 326 size_t linelen; 327 int error; 328 329 error = snprintf(line, sizeof(line), "\ 330 Received: from %s (uid %d)\n\ 331 \t(envelope-from %s)\n\ 332 \tid %"PRIxMAX"\n\ 333 \tby %s (%s)\n\ 334 \t%s\n", 335 getlogin(), getuid(), 336 sender, 337 queue->id, 338 hostname(), VERSION, 339 rfc822date()); 340 if (error < 0 || (size_t)error >= sizeof(line)) 341 return (-1); 342 if (write(queue->mailfd, line, error) != error) 343 return (-1); 344 345 while (!feof(stdin)) { 346 if (fgets(line, sizeof(line), stdin) == NULL) 347 break; 348 linelen = strlen(line); 349 if (linelen == 0 || line[linelen - 1] != '\n') { 350 errno = EINVAL; /* XXX mark permanent errors */ 351 return (-1); 352 } 353 if (!nodot && linelen == 2 && line[0] == '.') 354 break; 355 if ((size_t)write(queue->mailfd, line, linelen) != linelen) 356 return (-1); 357 } 358 if (fsync(queue->mailfd) != 0) 359 return (-1); 360 return (0); 361 } 362 363 static int 364 linkspool(struct queue *queue) 365 { 366 struct qitem *it; 367 368 LIST_FOREACH(it, &queue->queue, next) { 369 if (link(queue->tmpf, it->queuefn) != 0) 370 goto delfiles; 371 } 372 unlink(queue->tmpf); 373 return (0); 374 375 delfiles: 376 LIST_FOREACH(it, &queue->queue, next) { 377 unlink(it->queuefn); 378 } 379 return (-1); 380 } 381 382 static struct qitem * 383 go_background(struct queue *queue) 384 { 385 struct sigaction sa; 386 struct qitem *it; 387 pid_t pid; 388 389 if (daemonize && daemon(0, 0) != 0) { 390 syslog(LOG_ERR, "can not daemonize: %m"); 391 exit(1); 392 } 393 daemonize = 0; 394 395 bzero(&sa, sizeof(sa)); 396 sa.sa_flags = SA_NOCLDWAIT; 397 sa.sa_handler = SIG_IGN; 398 sigaction(SIGCHLD, &sa, NULL); 399 400 LIST_FOREACH(it, &queue->queue, next) { 401 /* No need to fork for the last dest */ 402 if (LIST_NEXT(it, next) == NULL) 403 return (it); 404 405 pid = fork(); 406 switch (pid) { 407 case -1: 408 syslog(LOG_ERR, "can not fork: %m"); 409 exit(1); 410 break; 411 412 case 0: 413 /* 414 * Child: 415 * 416 * return and deliver mail 417 */ 418 return (it); 419 420 default: 421 /* 422 * Parent: 423 * 424 * fork next child 425 */ 426 break; 427 } 428 } 429 430 syslog(LOG_CRIT, "reached dead code"); 431 exit(1); 432 } 433 434 static void 435 bounce(struct qitem *it, const char *reason) 436 { 437 struct queue bounceq; 438 struct qitem *bit; 439 char line[1000]; 440 int error; 441 442 /* Don't bounce bounced mails */ 443 if (it->sender[0] == 0) { 444 syslog(LOG_CRIT, "%s: delivery panic: can't bounce a bounce", 445 it->queueid); 446 exit(1); 447 } 448 449 syslog(LOG_ERR, "%s: delivery failed, bouncing", 450 it->queueid); 451 452 LIST_INIT(&bounceq.queue); 453 if (add_recp(&bounceq, it->sender, "", 1) != 0) 454 goto fail; 455 if (gentempf(&bounceq) != 0) 456 goto fail; 457 if (preparespool(&bounceq, "") != 0) 458 goto fail; 459 460 bit = LIST_FIRST(&bounceq.queue); 461 error = fprintf(bit->queuef, "\ 462 Received: from MAILER-DAEMON\n\ 463 \tid %"PRIxMAX"\n\ 464 \tby %s (%s)\n\ 465 \t%s\n\ 466 X-Original-To: <%s>\n\ 467 From: MAILER-DAEMON <>\n\ 468 To: %s\n\ 469 Subject: Mail delivery failed\n\ 470 Message-Id: <%"PRIxMAX"@%s>\n\ 471 Date: %s\n\ 472 \n\ 473 This is the %s at %s.\n\ 474 \n\ 475 There was an error delivering your mail to <%s>.\n\ 476 \n\ 477 %s\n\ 478 \n\ 479 Message headers follow.\n\ 480 \n\ 481 ", 482 bounceq.id, 483 hostname(), VERSION, 484 rfc822date(), 485 it->addr, 486 it->sender, 487 bounceq.id, hostname(), 488 rfc822date(), 489 VERSION, hostname(), 490 it->addr, 491 reason); 492 if (error < 0) 493 goto fail; 494 if (fflush(bit->queuef) != 0) 495 goto fail; 496 497 if (fseek(it->queuef, it->hdrlen, SEEK_SET) != 0) 498 goto fail; 499 while (!feof(it->queuef)) { 500 if (fgets(line, sizeof(line), it->queuef) == NULL) 501 break; 502 if (line[0] == '\n') 503 break; 504 write(bounceq.mailfd, line, strlen(line)); 505 } 506 if (fsync(bounceq.mailfd) != 0) 507 goto fail; 508 if (linkspool(&bounceq) != 0) 509 goto fail; 510 /* bounce is safe */ 511 512 unlink(it->queuefn); 513 fclose(it->queuef); 514 515 bit = go_background(&bounceq); 516 deliver(bit); 517 /* NOTREACHED */ 518 519 fail: 520 syslog(LOG_CRIT, "%s: error creating bounce: %m", it->queueid); 521 unlink(it->queuefn); 522 exit(1); 523 } 524 525 static int 526 deliver_local(struct qitem *it, const char **errmsg) 527 { 528 char fn[PATH_MAX+1]; 529 char line[1000]; 530 size_t linelen; 531 int mbox; 532 int error; 533 off_t mboxlen; 534 time_t now = time(NULL); 535 536 error = snprintf(fn, sizeof(fn), "%s/%s", _PATH_MAILDIR, it->addr); 537 if (error < 0 || (size_t)error >= sizeof(fn)) { 538 syslog(LOG_ERR, "%s: local delivery deferred: %m", 539 it->queueid); 540 return (1); 541 } 542 543 /* mailx removes users mailspool file if empty, so open with O_CREAT */ 544 mbox = open(fn, O_WRONLY | O_EXLOCK | O_APPEND | O_CREAT); 545 if (mbox < 0) { 546 syslog(LOG_ERR, "%s: local delivery deferred: can not open `%s': %m", 547 it->queueid, fn); 548 return (1); 549 } 550 mboxlen = lseek(mbox, 0, SEEK_CUR); 551 552 if (fseek(it->queuef, it->hdrlen, SEEK_SET) != 0) { 553 syslog(LOG_ERR, "%s: local delivery deferred: can not seek: %m", 554 it->queueid); 555 return (1); 556 } 557 558 error = snprintf(line, sizeof(line), "From %s\t%s", it->sender, ctime(&now)); 559 if (error < 0 || (size_t)error >= sizeof(line)) { 560 syslog(LOG_ERR, "%s: local delivery deferred: can not write header: %m", 561 it->queueid); 562 return (1); 563 } 564 if (write(mbox, line, error) != error) 565 goto wrerror; 566 567 while (!feof(it->queuef)) { 568 if (fgets(line, sizeof(line), it->queuef) == NULL) 569 break; 570 linelen = strlen(line); 571 if (linelen == 0 || line[linelen - 1] != '\n') { 572 syslog(LOG_CRIT, "%s: local delivery failed: corrupted queue file", 573 it->queueid); 574 *errmsg = "corrupted queue file"; 575 error = -1; 576 goto chop; 577 } 578 579 if (strncmp(line, "From ", 5) == 0) { 580 const char *gt = ">"; 581 582 if (write(mbox, gt, 1) != 1) 583 goto wrerror; 584 } 585 if ((size_t)write(mbox, line, linelen) != linelen) 586 goto wrerror; 587 } 588 line[0] = '\n'; 589 if (write(mbox, line, 1) != 1) 590 goto wrerror; 591 close(mbox); 592 return (0); 593 594 wrerror: 595 syslog(LOG_ERR, "%s: local delivery failed: write error: %m", 596 it->queueid); 597 error = 1; 598 chop: 599 if (ftruncate(mbox, mboxlen) != 0) 600 syslog(LOG_WARNING, "%s: error recovering mbox `%s': %m", 601 it->queueid, fn); 602 close(mbox); 603 return (error); 604 } 605 606 static void 607 deliver(struct qitem *it) 608 { 609 int error; 610 unsigned int backoff = MIN_RETRY; 611 const char *errmsg = "unknown bounce reason"; 612 struct timeval now; 613 struct stat st; 614 615 syslog(LOG_INFO, "%s: mail from=<%s> to=<%s>", 616 it->queueid, it->sender, it->addr); 617 618 retry: 619 syslog(LOG_INFO, "%s: trying delivery", 620 it->queueid); 621 622 if (it->remote) 623 error = deliver_remote(it, &errmsg); 624 else 625 error = deliver_local(it, &errmsg); 626 627 switch (error) { 628 case 0: 629 unlink(it->queuefn); 630 syslog(LOG_INFO, "%s: delivery successful", 631 it->queueid); 632 exit(0); 633 634 case 1: 635 if (stat(it->queuefn, &st) != 0) { 636 syslog(LOG_ERR, "%s: lost queue file `%s'", 637 it->queueid, it->queuefn); 638 exit(1); 639 } 640 if (gettimeofday(&now, NULL) == 0 && 641 (now.tv_sec - st.st_mtimespec.tv_sec > MAX_TIMEOUT)) { 642 char *msg; 643 644 if (asprintf(&msg, 645 "Could not deliver for the last %d seconds. Giving up.", 646 MAX_TIMEOUT) > 0) 647 errmsg = msg; 648 goto bounce; 649 } 650 sleep(backoff); 651 backoff *= 2; 652 if (backoff > MAX_RETRY) 653 backoff = MAX_RETRY; 654 goto retry; 655 656 case -1: 657 default: 658 break; 659 } 660 661 bounce: 662 bounce(it, errmsg); 663 /* NOTREACHED */ 664 } 665 666 static void 667 load_queue(struct queue *queue) 668 { 669 struct stat st; 670 struct qitem *it; 671 //struct queue queue, itmqueue; 672 struct queue itmqueue; 673 DIR *spooldir; 674 struct dirent *de; 675 char line[1000]; 676 char *fn; 677 FILE *queuef; 678 char *sender; 679 char *addr; 680 char *queueid; 681 char *queuefn; 682 off_t hdrlen; 683 int fd; 684 685 LIST_INIT(&queue->queue); 686 687 spooldir = opendir(config->spooldir); 688 if (spooldir == NULL) 689 err(1, "reading queue"); 690 691 while ((de = readdir(spooldir)) != NULL) { 692 sender = NULL; 693 queuef = NULL; 694 queueid = NULL; 695 queuefn = NULL; 696 fn = NULL; 697 LIST_INIT(&itmqueue.queue); 698 699 /* ignore temp files */ 700 if (strncmp(de->d_name, "tmp_", 4) == 0 || 701 de->d_type != DT_REG) 702 continue; 703 if (asprintf(&queuefn, "%s/%s", config->spooldir, de->d_name) < 0) 704 goto fail; 705 fd = open(queuefn, O_RDONLY|O_EXLOCK|O_NONBLOCK); 706 if (fd < 0) { 707 /* Ignore locked files */ 708 if (errno == EWOULDBLOCK) 709 continue; 710 goto skip_item; 711 } 712 713 queuef = fdopen(fd, "r"); 714 if (queuef == NULL) 715 goto skip_item; 716 if (fgets(line, sizeof(line), queuef) == NULL || 717 line[0] == 0) 718 goto skip_item; 719 line[strlen(line) - 1] = 0; /* chop newline */ 720 sender = strdup(line); 721 if (sender == NULL) 722 goto skip_item; 723 724 for (;;) { 725 if (fgets(line, sizeof(line), queuef) == NULL || 726 line[0] == 0) 727 goto skip_item; 728 if (line[0] == '\n') 729 break; 730 line[strlen(line) - 1] = 0; 731 queueid = strdup(line); 732 if (queueid == NULL) 733 goto skip_item; 734 addr = strchr(queueid, ' '); 735 if (addr == NULL) 736 goto skip_item; 737 *addr++ = 0; 738 if (fn != NULL) 739 free(fn); 740 if (asprintf(&fn, "%s/%s", config->spooldir, queueid) < 0) 741 goto skip_item; 742 /* Item has already been delivered? */ 743 if (stat(fn, &st) != 0) 744 continue; 745 if (add_recp(&itmqueue, addr, sender, 0) != 0) 746 goto skip_item; 747 it = LIST_FIRST(&itmqueue.queue); 748 it->queuef = queuef; 749 it->queueid = queueid; 750 it->queuefn = fn; 751 fn = NULL; 752 } 753 if (LIST_EMPTY(&itmqueue.queue)) { 754 warnx("queue file without items: `%s'", queuefn); 755 goto skip_item2; 756 } 757 hdrlen = ftell(queuef); 758 while ((it = LIST_FIRST(&itmqueue.queue)) != NULL) { 759 it->hdrlen = hdrlen; 760 LIST_REMOVE(it, next); 761 LIST_INSERT_HEAD(&queue->queue, it, next); 762 } 763 continue; 764 765 skip_item: 766 warn("reading queue: `%s'", queuefn); 767 skip_item2: 768 if (sender != NULL) 769 free(sender); 770 if (queuefn != NULL) 771 free(queuefn); 772 if (fn != NULL) 773 free(fn); 774 if (queueid != NULL) 775 free(queueid); 776 close(fd); 777 } 778 closedir(spooldir); 779 return; 780 781 fail: 782 err(1, "reading queue"); 783 } 784 785 static void 786 run_queue(struct queue *queue) 787 { 788 struct qitem *it; 789 if (LIST_EMPTY(&queue->queue)) 790 return; 791 792 it = go_background(queue); 793 deliver(it); 794 /* NOTREACHED */ 795 } 796 797 static void 798 show_queue(struct queue *queue) 799 { 800 struct qitem *it; 801 802 if (LIST_EMPTY(&queue->queue)) { 803 printf("Mail queue is empty\n"); 804 return; 805 } 806 807 LIST_FOREACH(it, &queue->queue, next) { 808 printf("\ 809 ID\t: %s\n\ 810 From\t: %s\n\ 811 To\t: %s\n--\n", it->queueid, it->sender, it->addr); 812 } 813 } 814 815 /* 816 * TODO: 817 * 818 * - alias processing 819 * - use group permissions 820 * - proper sysexit codes 821 */ 822 823 int 824 main(int argc, char **argv) 825 { 826 char *sender = NULL; 827 char tag[255]; 828 struct qitem *it; 829 struct queue queue; 830 struct queue lqueue; 831 int i, ch; 832 int nodot = 0, doqueue = 0, showq = 0; 833 834 atexit(deltmp); 835 LIST_INIT(&queue.queue); 836 snprintf(tag, 254, "dma"); 837 838 opterr = 0; 839 while ((ch = getopt(argc, argv, "A:b:Df:iL:o:O:q:r:")) != -1) { 840 switch (ch) { 841 case 'A': 842 /* -AX is being ignored, except for -A{c,m} */ 843 if (optarg[0] == 'c' || optarg[0] == 'm') { 844 break; 845 } 846 /* else FALLTRHOUGH */ 847 case 'b': 848 /* -bX is being ignored, except for -bp */ 849 if (optarg[0] == 'p') { 850 showq = 1; 851 break; 852 } 853 /* else FALLTRHOUGH */ 854 case 'D': 855 daemonize = 0; 856 break; 857 case 'L': 858 if (optarg != NULL) 859 snprintf(tag, 254, "%s", optarg); 860 break; 861 case 'f': 862 case 'r': 863 sender = optarg; 864 break; 865 866 case 'o': 867 /* -oX is being ignored, except for -oi */ 868 if (optarg[0] != 'i') 869 break; 870 /* else FALLTRHOUGH */ 871 case 'O': 872 break; 873 case 'i': 874 nodot = 1; 875 break; 876 877 case 'q': 878 doqueue = 1; 879 break; 880 881 default: 882 exit(1); 883 } 884 } 885 argc -= optind; 886 argv += optind; 887 opterr = 1; 888 889 openlog(tag, LOG_PID | LOG_PERROR, LOG_MAIL); 890 891 config = malloc(sizeof(struct config)); 892 if (config == NULL) 893 errx(1, "Cannot allocate enough memory"); 894 895 memset(config, 0, sizeof(struct config)); 896 if (parse_conf(CONF_PATH, config) < 0) { 897 free(config); 898 errx(1, "reading config file"); 899 } 900 901 if (config->features & VIRTUAL) 902 if (parse_virtuser(config->virtualpath) < 0) 903 errx(1, "error reading virtual user file: %s", 904 config->virtualpath); 905 906 if (parse_authfile(config->authpath) < 0) 907 err(1, "reading SMTP authentication file"); 908 909 if (showq) { 910 if (argc != 0) 911 errx(1, "sending mail and displaying queue is" 912 " mutually exclusive"); 913 load_queue(&lqueue); 914 show_queue(&lqueue); 915 return (0); 916 } 917 918 if (doqueue) { 919 if (argc != 0) 920 errx(1, "sending mail and queue pickup is mutually exclusive"); 921 load_queue(&lqueue); 922 run_queue(&lqueue); 923 return (0); 924 } 925 926 if (read_aliases() != 0) 927 err(1, "reading aliases"); 928 929 if ((sender = set_from(sender)) == NULL) 930 err(1, "setting from address"); 931 932 for (i = 0; i < argc; i++) { 933 if (add_recp(&queue, argv[i], sender, 1) != 0) 934 errx(1, "invalid recipient `%s'\n", argv[i]); 935 } 936 937 if (LIST_EMPTY(&queue.queue)) 938 errx(1, "no recipients"); 939 940 if (gentempf(&queue) != 0) 941 err(1, "create temp file"); 942 943 if (preparespool(&queue, sender) != 0) 944 err(1, "creating spools (1)"); 945 946 if (readmail(&queue, sender, nodot) != 0) 947 err(1, "reading mail"); 948 949 if (linkspool(&queue) != 0) 950 err(1, "creating spools (2)"); 951 952 /* From here on the mail is safe. */ 953 954 if (config->features & DEFER) 955 return (0); 956 957 it = go_background(&queue); 958 deliver(it); 959 960 /* NOTREACHED */ 961 962 return (0); 963 } 964