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