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/ipc.h> 38 #include <sys/param.h> 39 #include <sys/queue.h> 40 #include <sys/sem.h> 41 #include <sys/socket.h> 42 #include <sys/stat.h> 43 #include <sys/types.h> 44 #include <sys/wait.h> 45 46 #ifdef HAVE_CRYPTO 47 #include <openssl/ssl.h> 48 #endif /* HAVE_CRYPTO */ 49 50 #include <dirent.h> 51 #include <err.h> 52 #include <errno.h> 53 #include <fcntl.h> 54 #include <grp.h> 55 #include <inttypes.h> 56 #include <netdb.h> 57 #include <paths.h> 58 #include <pwd.h> 59 #include <signal.h> 60 #include <stdarg.h> 61 #include <stdio.h> 62 #include <stdlib.h> 63 #include <string.h> 64 #include <syslog.h> 65 #include <unistd.h> 66 67 #include "dma.h" 68 69 70 71 static void deliver(struct qitem *, int); 72 static void deliver_smarthost(struct queue *, int); 73 static int add_recp(struct queue *, const char *, const char *, int); 74 75 struct aliases aliases = LIST_HEAD_INITIALIZER(aliases); 76 static struct strlist tmpfs = SLIST_HEAD_INITIALIZER(tmpfs); 77 struct virtusers virtusers = LIST_HEAD_INITIALIZER(virtusers); 78 struct authusers authusers = LIST_HEAD_INITIALIZER(authusers); 79 static int daemonize = 1; 80 struct config *config; 81 int controlsocket_df, clientsocket_df, controlsocket_wl, clientsocket_wl, semkey; 82 83 static void 84 release_children(void) 85 { 86 struct sembuf sema; 87 int null = 0; 88 89 /* 90 * Try to decrement semaphore as we start communicating with 91 * write_to_local_user() 92 */ 93 sema.sem_num = SEM_WL; 94 sema.sem_op = -1; 95 sema.sem_flg = 0; 96 if (semop(semkey, &sema, 1) == -1) { 97 err(1, "semaphore decrement failed"); 98 } 99 100 /* 101 * write_to_local_user() will exit and kill dotforwardhandler(), too 102 * if the corresponding semaphore is zero 103 * otherwise nothing happens 104 */ 105 write(controlsocket_wl, &null, sizeof(null)); 106 107 /* 108 * Increment semaphore as we stop communicating with 109 * write_to_local_user() 110 */ 111 sema.sem_op = 1; 112 if (semop(semkey, &sema, 1) == -1) { 113 err(1, "semaphore decrement failed"); 114 } 115 } 116 117 char * 118 hostname(void) 119 { 120 static char name[MAXHOSTNAMELEN+1]; 121 122 if (gethostname(name, sizeof(name)) != 0) 123 strcpy(name, "(unknown hostname)"); 124 125 return name; 126 } 127 128 static char * 129 set_from(const char *osender) 130 { 131 struct virtuser *v; 132 char *sender; 133 134 if ((config->features & VIRTUAL) != 0) { 135 SLIST_FOREACH(v, &virtusers, next) { 136 if (strcmp(v->login, getlogin()) == 0) { 137 sender = strdup(v->address); 138 if (sender == NULL) 139 return(NULL); 140 goto out; 141 } 142 } 143 } 144 145 if (osender) { 146 sender = strdup(osender); 147 if (sender == NULL) 148 return(NULL); 149 } else { 150 if (asprintf(&sender, "%s@%s", getlogin(), hostname()) <= 0) 151 return(NULL); 152 } 153 154 if (strchr(sender, '\n') != NULL) { 155 errno = EINVAL; 156 return(NULL); 157 } 158 159 out: 160 return(sender); 161 } 162 163 static int 164 read_aliases(void) 165 { 166 yyin = fopen(config->aliases, "r"); 167 if (yyin == NULL) 168 return(0); /* not fatal */ 169 if (yyparse()) 170 return(-1); /* fatal error, probably malloc() */ 171 fclose(yyin); 172 return(0); 173 } 174 175 static int 176 add_recp(struct queue *queue, const char *str, const char *sender, int expand) 177 { 178 struct qitem *it, *tit; 179 struct stritem *sit; 180 struct alias *al; 181 struct passwd *pw; 182 char *host; 183 int aliased = 0; 184 185 it = calloc(1, sizeof(*it)); 186 if (it == NULL) 187 return(-1); 188 it->addr = strdup(str); 189 if (it->addr == NULL) 190 return(-1); 191 192 it->sender = sender; 193 host = strrchr(it->addr, '@'); 194 if (host != NULL && 195 (strcmp(host + 1, hostname()) == 0 || 196 strcmp(host + 1, "localhost") == 0)) { 197 *host = 0; 198 } 199 LIST_FOREACH(tit, &queue->queue, next) { 200 /* weed out duplicate dests */ 201 if (strcmp(tit->addr, it->addr) == 0) { 202 free(it->addr); 203 free(it); 204 return(0); 205 } 206 } 207 LIST_INSERT_HEAD(&queue->queue, it, next); 208 if (strrchr(it->addr, '@') == NULL) { 209 /* local = 1 means its a username or mailbox */ 210 it->local = 1; 211 /* only search for aliases and .forward if asked for */ 212 /* needed to have the possibility to add an mailbox directly */ 213 if (expand) { 214 /* first check /etc/aliases */ 215 LIST_FOREACH(al, &aliases, next) { 216 if (strcmp(al->alias, it->addr) != 0) 217 continue; 218 SLIST_FOREACH(sit, &al->dests, next) { 219 if (add_recp(queue, sit->str, 220 sender, 1) != 0) 221 return(-1); 222 } 223 aliased = 1; 224 } 225 if (aliased) { 226 LIST_REMOVE(it, next); 227 } else { 228 /* then check .forward of user */ 229 fd_set rfds; 230 int ret; 231 uint8_t len, type; 232 struct sembuf sema; 233 /* is the username valid */ 234 pw = getpwnam(it->addr); 235 endpwent(); 236 if (pw == NULL) 237 goto out; 238 239 /* 240 * Try to decrement semaphore as we start 241 * communicating with dotforwardhandler() 242 */ 243 sema.sem_num = SEM_DF; 244 sema.sem_op = -1; 245 sema.sem_flg = 0; 246 if (semop(semkey, &sema, 1) == -1) { 247 err(1, "semaphore decrement failed"); 248 } 249 250 /* write username to dotforwardhandler */ 251 len = strlen(it->addr); 252 write(controlsocket_df, &len, sizeof(len)); 253 write(controlsocket_df, it->addr, len); 254 FD_ZERO(&rfds); 255 FD_SET(controlsocket_df, &rfds); 256 257 /* wait for incoming redirects and pipes */ 258 while ((ret = select(controlsocket_df + 1, 259 &rfds, NULL, NULL, NULL))) { 260 /* 261 * Receive back list of mailboxnames 262 * and/or emailadresses 263 */ 264 if (ret == -1) { 265 /* 266 * increment semaphore because 267 * we stopped communicating 268 * with dotforwardhandler() 269 */ 270 sema.sem_op = 1; 271 semop(semkey, &sema, 1); 272 return(-1); 273 } 274 /* read type of .forward entry */ 275 read(controlsocket_df, &type, 1); 276 if (type & ENDOFDOTFORWARD) { 277 /* end of .forward */ 278 /* 279 * If there are redirects, then 280 * we do not need the original 281 * qitem any longer 282 */ 283 if (aliased) { 284 LIST_REMOVE(it, next); 285 } 286 break; 287 } else if (type & ISMAILBOX) { 288 /* redirect -> user/emailaddress */ 289 /* 290 * FIXME shall there be the possibility to use 291 * usernames instead of mailboxes? 292 */ 293 char *username; 294 read(controlsocket_df, &len, sizeof(len)); 295 username = calloc(1, len + 1); 296 read(controlsocket_df, username, len); 297 /* 298 * Do not further expand since 299 * its remote or local mailbox 300 */ 301 if (add_recp(queue, username, sender, 0) != 0) { 302 aliased = 1; 303 } 304 } else if (type & ISPIPE) { 305 /* redirect to a pipe */ 306 /* 307 * Create new qitem and save 308 * information in it 309 */ 310 struct qitem *pit; 311 pit = calloc(1, sizeof(*pit)); 312 if (pit == NULL) { 313 /* 314 * Increment semaphore 315 * because we stopped 316 * communicating with 317 * dotforwardhandler() 318 */ 319 sema.sem_op = 1; 320 semop(semkey, &sema, 1); 321 return(-1); 322 } 323 LIST_INSERT_HEAD(&queue->queue, pit, next); 324 /* 325 * Save username to qitem, 326 * because its overwritten by 327 * pipe command 328 */ 329 pit->pipeuser = strdup(it->addr); 330 pit->sender = sender; 331 /* local = 2 means redirect to pipe */ 332 pit->local = 2; 333 read(controlsocket_df, &len, sizeof(len)); 334 pit->addr = realloc(pit->addr, len + 1); 335 memset(pit->addr, 0, len + 1); 336 read(controlsocket_df, pit->addr, len); 337 aliased = 1; 338 } 339 } 340 /* 341 * Increment semaphore because we stopped 342 * communicating with dotforwardhandler() 343 */ 344 sema.sem_op = 1; 345 semop(semkey, &sema, 1); 346 } 347 } 348 } else { 349 it->local = 0; 350 } 351 352 return(0); 353 354 out: 355 free(it->addr); 356 free(it); 357 return(-1); 358 } 359 360 static void 361 deltmp(void) 362 { 363 struct stritem *t; 364 365 SLIST_FOREACH(t, &tmpfs, next) { 366 unlink(t->str); 367 } 368 } 369 370 static int 371 gentempf(struct queue *queue) 372 { 373 char fn[PATH_MAX+1]; 374 struct stritem *t; 375 int fd; 376 377 if (snprintf(fn, sizeof(fn), "%s/%s", config->spooldir, "tmp_XXXXXXXXXX") <= 0) 378 return(-1); 379 fd = mkstemp(fn); 380 if (fd < 0) 381 return(-1); 382 queue->mailfd = fd; 383 384 queue->tmpf = strdup(fn); 385 if (queue->tmpf == NULL) { 386 unlink(fn); 387 return(-1); 388 } 389 t = malloc(sizeof(*t)); 390 if (t != NULL) { 391 t->str = queue->tmpf; 392 SLIST_INSERT_HEAD(&tmpfs, t, next); 393 } 394 return(0); 395 } 396 397 /* 398 * spool file format: 399 * 400 * envelope-from 401 * queue-id1 envelope-to1 402 * queue-id2 envelope-to2 403 * ... 404 * <empty line> 405 * mail data 406 * 407 * queue ids are unique, formed from the inode of the spool file 408 * and a unique identifier. 409 */ 410 static int 411 preparespool(struct queue *queue, const char *sender) 412 { 413 char line[1000]; /* by RFC2822 */ 414 struct stat st; 415 int error; 416 struct qitem *it; 417 FILE *queuef; 418 off_t hdrlen; 419 420 error = snprintf(line, sizeof(line), "%s\n", sender); 421 if (error < 0 || (size_t)error >= sizeof(line)) { 422 errno = E2BIG; 423 return(-1); 424 } 425 if (write(queue->mailfd, line, error) != error) 426 return(-1); 427 428 queuef = fdopen(queue->mailfd, "r+"); 429 if (queuef == NULL) 430 return(-1); 431 432 /* 433 * Assign queue id to each dest. 434 */ 435 if (fstat(queue->mailfd, &st) != 0) 436 return(-1); 437 queue->id = st.st_ino; 438 LIST_FOREACH(it, &queue->queue, next) { 439 if (asprintf(&it->queueid, "%"PRIxMAX".%"PRIxPTR, 440 queue->id, (uintptr_t)it) <= 0) 441 return(-1); 442 if (asprintf(&it->queuefn, "%s/%s", 443 config->spooldir, it->queueid) <= 0) 444 return(-1); 445 /* File may already exist */ 446 if (stat(it->queuefn, &st) == 0) { 447 warn("Spoolfile already exists: %s", it->queuefn); 448 return(-1); 449 } 450 /* Reset errno to avoid confusion */ 451 errno = 0; 452 it->queuef = queuef; 453 error = snprintf(line, sizeof(line), "%s %s\n", 454 it->queueid, it->addr); 455 if (error < 0 || (size_t)error >= sizeof(line)) 456 return(-1); 457 if (write(queue->mailfd, line, error) != error) 458 return(-1); 459 } 460 line[0] = '\n'; 461 if (write(queue->mailfd, line, 1) != 1) 462 return(-1); 463 464 hdrlen = lseek(queue->mailfd, 0, SEEK_CUR); 465 LIST_FOREACH(it, &queue->queue, next) { 466 it->hdrlen = hdrlen; 467 } 468 return(0); 469 } 470 471 static char * 472 rfc822date(void) 473 { 474 static char str[50]; 475 size_t error; 476 time_t now; 477 478 now = time(NULL); 479 error = strftime(str, sizeof(str), "%a, %d %b %Y %T %z", 480 localtime(&now)); 481 if (error == 0) 482 strcpy(str, "(date fail)"); 483 return(str); 484 } 485 486 static int 487 readmail(struct queue *queue, const char *sender, int nodot) 488 { 489 char line[1000]; /* by RFC2822 */ 490 size_t linelen; 491 int error; 492 493 error = snprintf(line, sizeof(line), "\ 494 Received: from %s (uid %d)\n\ 495 \t(envelope-from %s)\n\ 496 \tid %"PRIxMAX"\n\ 497 \tby %s (%s)\n\ 498 \t%s\n", 499 getlogin(), getuid(), 500 sender, 501 queue->id, 502 hostname(), VERSION, 503 rfc822date()); 504 if (error < 0 || (size_t)error >= sizeof(line)) 505 return(-1); 506 if (write(queue->mailfd, line, error) != error) 507 return(-1); 508 509 while (!feof(stdin)) { 510 if (fgets(line, sizeof(line), stdin) == NULL) 511 break; 512 linelen = strlen(line); 513 if (linelen == 0 || line[linelen - 1] != '\n') { 514 errno = EINVAL; /* XXX mark permanent errors */ 515 return(-1); 516 } 517 if (!nodot && linelen == 2 && line[0] == '.') 518 break; 519 if ((size_t)write(queue->mailfd, line, linelen) != linelen) 520 return(-1); 521 } 522 if (fsync(queue->mailfd) != 0) 523 return(-1); 524 return(0); 525 } 526 527 static int 528 linkspool(struct queue *queue) 529 { 530 struct qitem *it; 531 532 /* 533 * Only if it is not a pipe delivery 534 * pipe deliveries are only tried once so there 535 * is no need for a spool-file, they use the 536 * original tempfile 537 */ 538 539 LIST_FOREACH(it, &queue->queue, next) { 540 /* 541 * There shall be no files for pipe deliveries since not all 542 * information is saved in the header, so pipe delivery is 543 * tried once and forgotten thereafter. 544 */ 545 if (it->local == 2) 546 continue; 547 if (link(queue->tmpf, it->queuefn) != 0) 548 goto delfiles; 549 } 550 return(0); 551 552 delfiles: 553 LIST_FOREACH(it, &queue->queue, next) { 554 /* 555 * There are no files for pipe delivery, so they can't be 556 * deleted. 557 */ 558 if (it->local == 2) 559 continue; 560 unlink(it->queuefn); 561 } 562 return(-1); 563 } 564 565 static void 566 go_background(struct queue *queue, int leavesemaphore) 567 { 568 struct sigaction sa; 569 struct qitem *it; 570 pid_t pid; 571 int seen_remote_address = 0; 572 573 if (daemonize && daemon(0, 0) != 0) { 574 syslog(LOG_ERR, "[go_background] can not daemonize: %m"); 575 exit(1); 576 } 577 daemonize = 0; 578 bzero(&sa, sizeof(sa)); 579 sa.sa_flags = SA_NOCLDWAIT; 580 sa.sa_handler = SIG_IGN; 581 sigaction(SIGCHLD, &sa, NULL); 582 583 584 LIST_FOREACH(it, &queue->queue, next) { 585 /* 586 * If smarthost is enabled, the address is remote 587 * set smarthost delivery flag, otherwise deliver it 'normal'. 588 */ 589 if (config->smarthost != NULL && strlen(config->smarthost) > 0 590 && it->local == 0 591 ) { 592 seen_remote_address = 1; 593 /* 594 * if it is not the last entry, continue 595 * (if it is the last, start delivery in parent 596 */ 597 if (LIST_NEXT(it, next) != NULL) { 598 continue; 599 } 600 } else { 601 /* 602 * If item is local, we do not need it in the list any 603 * more, so delete it. 604 */ 605 LIST_REMOVE(it, next); 606 } 607 pid = fork(); 608 switch (pid) { 609 case -1: 610 syslog(LOG_ERR, "can not fork: %m"); 611 exit(1); 612 break; 613 614 case 0: 615 /* 616 * Child: 617 * 618 * return and deliver mail 619 */ 620 621 if (config->smarthost == NULL || strlen(config->smarthost) == 0 || it->local) 622 if (LIST_NEXT(it, next) == NULL && !seen_remote_address) 623 /* if there is no smarthost-delivery and we are the last item */ 624 deliver(it, leavesemaphore); 625 else 626 deliver(it, 0); 627 else 628 _exit(0); 629 630 default: 631 /* 632 * Parent: 633 * 634 * fork next child 635 */ 636 /* 637 * If it is the last loop and there were remote 638 * addresses, start smarthost delivery. 639 * No need to doublecheck if smarthost is 640 * activated in config file. 641 */ 642 if (LIST_NEXT(it, next) == NULL) { 643 if (seen_remote_address) { 644 deliver_smarthost(queue, leavesemaphore); 645 } else { 646 _exit(0); 647 } 648 } 649 break; 650 } 651 } 652 653 syslog(LOG_CRIT, "reached dead code"); 654 exit(1); 655 } 656 657 static void 658 bounce(struct qitem *it, const char *reason, int leavesemaphore) 659 { 660 struct queue bounceq; 661 struct qitem *bit; 662 char line[1000]; 663 int error; 664 struct sembuf sema; 665 666 /* Don't bounce bounced mails */ 667 if (it->sender[0] == 0) { 668 /* 669 * If we are the last bounce, then decrement semaphore 670 * and release children. 671 */ 672 if (leavesemaphore) { 673 /* semaphore-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */ 674 sema.sem_num = SEM_SIGHUP; 675 sema.sem_op = -1; 676 sema.sem_flg = IPC_NOWAIT; 677 if (semop(semkey, &sema, 1) == -1) { 678 err(1, "[deliver] semaphore decrement failed"); 679 } 680 /* release child processes */ 681 release_children(); 682 } 683 syslog(LOG_CRIT, "%s: delivery panic: can't bounce a bounce", 684 it->queueid); 685 exit(1); 686 } 687 688 syslog(LOG_ERR, "%s: delivery failed, bouncing", 689 it->queueid); 690 691 LIST_INIT(&bounceq.queue); 692 if (add_recp(&bounceq, it->sender, "", 1) != 0) 693 goto fail; 694 if (gentempf(&bounceq) != 0) 695 goto fail; 696 if (preparespool(&bounceq, "") != 0) 697 goto fail; 698 699 bit = LIST_FIRST(&bounceq.queue); 700 error = fprintf(bit->queuef, "\ 701 Received: from MAILER-DAEMON\n\ 702 \tid %"PRIxMAX"\n\ 703 \tby %s (%s)\n\ 704 \t%s\n\ 705 X-Original-To: <%s>\n\ 706 From: MAILER-DAEMON <>\n\ 707 To: %s\n\ 708 Subject: Mail delivery failed\n\ 709 Message-Id: <%"PRIxMAX"@%s>\n\ 710 Date: %s\n\ 711 \n\ 712 This is the %s at %s.\n\ 713 \n\ 714 There was an error delivering your mail to <%s>.\n\ 715 \n\ 716 %s\n\ 717 \n\ 718 Message headers follow.\n\ 719 \n\ 720 ", 721 bounceq.id, 722 hostname(), VERSION, 723 rfc822date(), 724 it->addr, 725 it->sender, 726 bounceq.id, hostname(), 727 rfc822date(), 728 VERSION, hostname(), 729 it->addr, 730 reason); 731 if (error < 0) 732 goto fail; 733 if (fflush(bit->queuef) != 0) 734 goto fail; 735 736 if (fseek(it->queuef, it->hdrlen, SEEK_SET) != 0) 737 goto fail; 738 while (!feof(it->queuef)) { 739 if (fgets(line, sizeof(line), it->queuef) == NULL) 740 break; 741 if (line[0] == '\n') 742 break; 743 write(bounceq.mailfd, line, strlen(line)); 744 } 745 if (fsync(bounceq.mailfd) != 0) 746 goto fail; 747 if (linkspool(&bounceq) != 0) 748 goto fail; 749 /* bounce is safe */ 750 751 unlink(it->queuefn); 752 fclose(it->queuef); 753 754 go_background(&bounceq, leavesemaphore); 755 /* NOTREACHED */ 756 757 fail: 758 /* 759 * If we are the last bounce, then decrement semaphore 760 * and release children. 761 */ 762 if (leavesemaphore) { 763 /* semaphore-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */ 764 sema.sem_num = SEM_SIGHUP; 765 sema.sem_op = -1; 766 sema.sem_flg = IPC_NOWAIT; 767 if (semop(semkey, &sema, 1) == -1) { 768 err(1, "[deliver] semaphore decrement failed"); 769 } 770 /* release child processes */ 771 release_children(); 772 } 773 syslog(LOG_CRIT, "%s: error creating bounce: %m", it->queueid); 774 unlink(it->queuefn); 775 exit(1); 776 } 777 778 static int 779 deliver_local(struct qitem *it, const char **errmsg) 780 { 781 char line[1000]; 782 char fn[PATH_MAX+1]; 783 int len; 784 uint8_t mode = 0, fail = 0; 785 ssize_t linelen; 786 time_t now = time(NULL); 787 char *username = NULL; 788 struct sembuf sema; 789 790 791 /* 792 * Try to decrement semaphore as we start communicating with 793 * write_to_local_user() 794 */ 795 sema.sem_num = SEM_WL; 796 sema.sem_op = -1; 797 sema.sem_flg = 0; 798 if (semop(semkey, &sema, 1) == -1) { 799 err(1, "semaphore decrement failed"); 800 } 801 802 803 /* Tell write_to_local_user() the username to drop the privileges */ 804 if (it->local == 1) { /* mailbox delivery */ 805 username = it->addr; 806 } else if (it->local == 2) { /* pipe delivery */ 807 username = it->pipeuser; 808 } 809 len = strlen(username); 810 write(controlsocket_wl, &len, sizeof(len)); 811 write(controlsocket_wl, username, len); 812 read(controlsocket_wl, &fail, sizeof(fail)); 813 if (fail) { 814 syslog(LOG_ERR, 815 "%s: local delivery deferred: can not fork and drop privileges `%s': %m", 816 it->queueid, username); 817 /* 818 * Increment semaphore because we stopped communicating with 819 * write_to_local_user(). 820 */ 821 sema.sem_op = 1; 822 semop(semkey, &sema, 1); 823 return(1); 824 } 825 826 827 /* Tell write_to_local_user() the delivery mode (write to mailbox || pipe) */ 828 if (it->local == 1) { /* mailbox delivery */ 829 mode = ISMAILBOX; 830 len = snprintf(fn, sizeof(fn), "%s/%s", _PATH_MAILDIR, it->addr); 831 if (len < 0 || (size_t)len >= sizeof(fn)) { 832 syslog(LOG_ERR, "%s: local delivery deferred: %m", 833 it->queueid); 834 /* 835 * Increment semaphore because we stopped communicating 836 * with write_to_local_user(). 837 */ 838 sema.sem_op = 1; 839 semop(semkey, &sema, 1); 840 return(1); 841 } 842 } else if (it->local == 2) { /* pipe delivery */ 843 mode = ISPIPE; 844 strncpy(fn, it->addr, sizeof(fn)); 845 len = strlen(fn); 846 } 847 write(controlsocket_wl, &len, sizeof(len)); 848 write(controlsocket_wl, fn, len); 849 write(controlsocket_wl, &mode, sizeof(mode)); 850 read(controlsocket_wl, &fail, sizeof(fail)); 851 if (fail) { 852 errno = fail; 853 syslog(LOG_ERR, 854 "%s: local delivery deferred: can not (p)open `%s': %m", 855 it->queueid, it->addr); 856 /* 857 * Increment semaphore because we stopped communicating 858 * with write_to_local_user(). 859 */ 860 sema.sem_op = 1; 861 semop(semkey, &sema, 1); 862 return(1); 863 } 864 865 866 /* Prepare transfer of mail-data */ 867 if (fseek(it->queuef, it->hdrlen, SEEK_SET) != 0) { 868 syslog(LOG_ERR, "%s: local delivery deferred: can not seek: %m", 869 it->queueid); 870 /* 871 * Increment semaphore because we stopped communicating 872 * with write_to_local_user(). 873 */ 874 sema.sem_op = 1; 875 semop(semkey, &sema, 1); 876 return(1); 877 } 878 879 880 /* Send first header line. */ 881 linelen = snprintf(line, sizeof(line), "From %s\t%s", it->sender, ctime(&now)); 882 if (linelen < 0 || (size_t)linelen >= sizeof(line)) { 883 syslog(LOG_ERR, "%s: local delivery deferred: can not write header: %m", 884 it->queueid); 885 /* 886 * Increment semaphore because we stopped communicating 887 * with write_to_local_user(). 888 */ 889 sema.sem_op = 1; 890 semop(semkey, &sema, 1); 891 return(1); 892 } 893 894 write(controlsocket_wl, &linelen, sizeof(linelen)); 895 write(controlsocket_wl, line, linelen); 896 897 read(controlsocket_wl, &fail, sizeof(fail)); 898 if (fail) { 899 goto wrerror; 900 } 901 902 903 /* Read mail data and transfer it to write_to_local_user(). */ 904 while (!feof(it->queuef)) { 905 if (fgets(line, sizeof(line), it->queuef) == NULL) 906 break; 907 linelen = strlen(line); 908 if (linelen == 0 || line[linelen - 1] != '\n') { 909 syslog(LOG_CRIT, 910 "%s: local delivery failed: corrupted queue file", 911 it->queueid); 912 *errmsg = "corrupted queue file"; 913 len = -1; 914 /* break receive and write loop at write_to_local_user() */ 915 linelen = 0; 916 write(controlsocket_wl, &linelen, sizeof(linelen)); 917 /* and send error state */ 918 linelen = 1; 919 write(controlsocket_wl, &linelen, sizeof(linelen)); 920 goto chop; 921 } 922 923 if (strncmp(line, "From ", 5) == 0) { 924 const char *gt = ">"; 925 size_t sizeofchar = 1; 926 927 write(controlsocket_wl, &sizeofchar, sizeof(sizeofchar)); 928 write(controlsocket_wl, gt, 1); 929 read(controlsocket_wl, &fail, sizeof(fail)); 930 if (fail) { 931 goto wrerror; 932 } 933 } 934 write(controlsocket_wl, &linelen, sizeof(linelen)); 935 write(controlsocket_wl, line, linelen); 936 read(controlsocket_wl, &fail, sizeof(fail)); 937 if (fail) { 938 goto wrerror; 939 } 940 } 941 942 /* Send final linebreak */ 943 line[0] = '\n'; 944 linelen = 1; 945 write(controlsocket_wl, &linelen, sizeof(linelen)); 946 write(controlsocket_wl, line, linelen); 947 read(controlsocket_wl, &fail, sizeof(fail)); 948 if (fail) { 949 goto wrerror; 950 } 951 952 953 /* break receive and write loop in write_to_local_user() */ 954 linelen = 0; 955 /* send '0' twice, because above we send '0' '1' in case of error */ 956 write(controlsocket_wl, &linelen, sizeof(linelen)); 957 write(controlsocket_wl, &linelen, sizeof(linelen)); 958 read(controlsocket_wl, &fail, sizeof(fail)); 959 if (fail) { 960 goto wrerror; 961 } 962 963 964 /* 965 * Increment semaphore because we stopped communicating 966 * with write_to_local_user(). 967 */ 968 sema.sem_op = 1; 969 semop(semkey, &sema, 1); 970 return(0); 971 972 wrerror: 973 errno = fail; 974 syslog(LOG_ERR, "%s: local delivery failed: write error: %m", 975 it->queueid); 976 len = 1; 977 chop: 978 read(controlsocket_wl, &fail, sizeof(fail)); 979 if (fail == 2) { 980 syslog(LOG_WARNING, "%s: error recovering mbox `%s': %m", 981 it->queueid, fn); 982 } 983 /* 984 * Increment semaphore because we stopped communicating 985 * with write_to_local_user(). 986 */ 987 sema.sem_op = 1; 988 semop(semkey, &sema, 1); 989 return(len); 990 } 991 992 static void 993 deliver(struct qitem *it, int leavesemaphore) 994 { 995 int error; 996 unsigned int backoff = MIN_RETRY; 997 const char *errmsg = "unknown bounce reason"; 998 struct timeval now; 999 struct stat st; 1000 struct sembuf sema; 1001 1002 if (it->local == 2) { 1003 syslog(LOG_INFO, "%s: mail from=<%s> to=<%s> command=<%s>", 1004 it->queueid, it->sender, it->pipeuser, it->addr); 1005 } else { 1006 syslog(LOG_INFO, "%s: mail from=<%s> to=<%s>", 1007 it->queueid, it->sender, it->addr); 1008 } 1009 1010 retry: 1011 syslog(LOG_INFO, "%s: trying delivery", 1012 it->queueid); 1013 1014 /* 1015 * Only increment semaphore, if we are not the last bounce 1016 * because there is still a incremented semaphore from 1017 * the bounced delivery 1018 */ 1019 if (!leavesemaphore) { 1020 /* 1021 * Increment semaphore for each mail we try to deliver. 1022 * When completing the transmit, the semaphore is decremented. 1023 * If the semaphore is zero the other childs know that they 1024 * can terminate. 1025 */ 1026 sema.sem_num = SEM_SIGHUP; 1027 sema.sem_op = 1; 1028 sema.sem_flg = 0; 1029 if (semop(semkey, &sema, 1) == -1) { 1030 err(1, "[deliver] semaphore increment failed"); 1031 } 1032 } 1033 if (it->local) { 1034 error = deliver_local(it, &errmsg); 1035 } else { 1036 error = deliver_remote(it, &errmsg, NULL); 1037 } 1038 1039 switch (error) { 1040 case 0: 1041 /* semaphore-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */ 1042 sema.sem_num = SEM_SIGHUP; 1043 sema.sem_op = -1; 1044 sema.sem_flg = IPC_NOWAIT; 1045 if (semop(semkey, &sema, 1) == -1) { 1046 err(1, "[deliver] semaphore decrement failed"); 1047 } 1048 /* release child processes */ 1049 release_children(); 1050 /* Do not try to delete the spool file: pipe mode */ 1051 if (it->local != 2) 1052 unlink(it->queuefn); 1053 syslog(LOG_INFO, "%s: delivery successful", 1054 it->queueid); 1055 exit(0); 1056 1057 case 1: 1058 /* pipe delivery only tries once, then gives up */ 1059 if (it->local == 2) { 1060 /* decrement-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */ 1061 sema.sem_num = SEM_SIGHUP; 1062 sema.sem_op = -1; 1063 sema.sem_flg = IPC_NOWAIT; 1064 if (semop(semkey, &sema, 1) == -1) { 1065 err(1, "[deliver] semaphore decrement failed"); 1066 } 1067 /* release child processes */ 1068 release_children(); 1069 syslog(LOG_ERR, "%s: delivery to pipe `%s' failed, giving up", 1070 it->queueid, it->addr); 1071 exit(1); 1072 } 1073 if (stat(it->queuefn, &st) != 0) { 1074 /* semaphore-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */ 1075 sema.sem_num = SEM_SIGHUP; 1076 sema.sem_op = -1; 1077 sema.sem_flg = IPC_NOWAIT; 1078 if (semop(semkey, &sema, 1) == -1) { 1079 err(1, "[deliver] semaphore decrement failed"); 1080 } 1081 /* release child processes */ 1082 release_children(); 1083 syslog(LOG_ERR, "%s: lost queue file `%s'", 1084 it->queueid, it->queuefn); 1085 exit(1); 1086 } 1087 if (gettimeofday(&now, NULL) == 0 && 1088 (now.tv_sec - st.st_mtimespec.tv_sec > MAX_TIMEOUT)) { 1089 char *msg; 1090 1091 if (asprintf(&msg, 1092 "Could not deliver for the last %d seconds. Giving up.", 1093 MAX_TIMEOUT) > 0) 1094 errmsg = msg; 1095 goto bounce; 1096 } 1097 sleep(backoff); 1098 backoff *= 2; 1099 if (backoff > MAX_RETRY) 1100 backoff = MAX_RETRY; 1101 goto retry; 1102 1103 case -1: 1104 default: 1105 break; 1106 } 1107 1108 bounce: 1109 bounce(it, errmsg, 1); 1110 /* NOTREACHED */ 1111 } 1112 1113 /* 1114 * deliver_smarthost() is similar to deliver(), but has some differences: 1115 * -deliver_smarthost() works with a queue 1116 * -each entry in this queue has a corresponding file in the spooldir 1117 * -if the mail is sent correctly to a address, delete the corresponding file, 1118 * even if there were errors with other addresses 1119 * -so deliver_remote must tell deliver_smarthost to which addresses it has 1120 * successfully sent the mail 1121 * -this can be done with 3 queues: 1122 * -one queue for sent mails 1123 * -one queue for 4xx addresses (tempfail) 1124 * -one queue for 5xx addresses (permfail) 1125 * -the sent mails are deleted 1126 * -the 4xx are tried again 1127 * -the 5xx are bounced 1128 */ 1129 1130 static void 1131 deliver_smarthost(struct queue *queue, int leavesemaphore) 1132 { 1133 int error, bounces = 0; 1134 unsigned int backoff = MIN_RETRY; 1135 const char *errmsg = "unknown bounce reason"; 1136 struct timeval now; 1137 struct stat st; 1138 struct sembuf sema; 1139 struct qitem *it, *tit; 1140 struct queue *queues[4], *bouncequeue, successqueue, tempfailqueue, 1141 permfailqueue; 1142 1143 /* 1144 * only increment semaphore, if we are not the last bounce 1145 * because there is still a incremented semaphore from 1146 * the bounced delivery 1147 */ 1148 if (!leavesemaphore) { 1149 /* 1150 * Increment semaphore for each mail we try to deliver. 1151 * When completing the transmit, the semaphore is decremented. 1152 * If the semaphore is zero the other childs know that they 1153 * can terminate. 1154 */ 1155 sema.sem_num = SEM_SIGHUP; 1156 sema.sem_op = 1; 1157 sema.sem_flg = 0; 1158 if (semop(semkey, &sema, 1) == -1) { 1159 err(1, "[deliver] semaphore increment failed"); 1160 } 1161 } 1162 1163 queues[0] = queue; 1164 queues[1] = &successqueue; 1165 queues[2] = &tempfailqueue; 1166 queues[3] = &permfailqueue; 1167 1168 retry: 1169 /* initialise 3 empty queues and link it in queues[] */ 1170 LIST_INIT(&queues[1]->queue); /* successful sent items */ 1171 LIST_INIT(&queues[2]->queue); /* temporary error items */ 1172 LIST_INIT(&queues[3]->queue); /* permanent error items */ 1173 1174 it = LIST_FIRST(&queues[0]->queue); 1175 1176 syslog(LOG_INFO, "%s: trying delivery", 1177 it->queueid); 1178 1179 /* if queuefile of first qitem is gone, the mail can't be sended out */ 1180 if (stat(it->queuefn, &st) != 0) { 1181 syslog(LOG_ERR, "%s: lost queue file `%s'", 1182 it->queueid, it->queuefn); 1183 /* semaphore-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */ 1184 sema.sem_num = SEM_SIGHUP; 1185 sema.sem_op = -1; 1186 sema.sem_flg = IPC_NOWAIT; 1187 if (semop(semkey, &sema, 1) == -1) { 1188 err(1, "[deliver] semaphore decrement failed"); 1189 } 1190 release_children(); 1191 exit(1); 1192 } 1193 1194 error = deliver_remote(it, &errmsg, queues); 1195 1196 /* if there was an error, do nothing with the other 3 queues! */ 1197 if (error == 0) { 1198 1199 /* 1200 * If there are permanent errors, bounce items in permanent 1201 * error queue. 1202 */ 1203 if (!LIST_EMPTY(&queues[3]->queue)) { 1204 bounces = 1; 1205 pid_t pid; 1206 pid = fork(); 1207 switch (pid) { 1208 case -1: 1209 syslog(LOG_ERR, "can not fork: %m"); 1210 exit(1); 1211 break; 1212 1213 case 0: 1214 /* 1215 * Child: 1216 * 1217 * Tell which queue to bounce and set 1218 * errmsg. Child will exit as soon as 1219 * all childs for bounces are spawned. 1220 * So no need to set up a signal handler. 1221 */ 1222 bouncequeue = queues[3]; 1223 errmsg = "smarthost sent permanent error (5xx)"; 1224 goto bounce; 1225 1226 default: 1227 /* 1228 * Parent: 1229 * 1230 * continue with stuff 1231 */ 1232 break; 1233 } 1234 } 1235 1236 /* delete successfully sent items */ 1237 if (!LIST_EMPTY(&queues[1]->queue)) { 1238 LIST_FOREACH(tit, &queues[1]->queue, next) { 1239 unlink(tit->queuefn); 1240 LIST_REMOVE(tit, next); 1241 syslog(LOG_INFO, "%s: delivery successful", 1242 tit->queueid); 1243 } 1244 } 1245 } 1246 1247 /* If the temporary error queue is empty and there was no error, finish */ 1248 if (LIST_EMPTY(&queues[2]->queue) && error == 0) { 1249 /* only decrement semaphore if there were no bounces! */ 1250 if (!bounces) { 1251 /* semaphore-- (MUST NOT BLOCK BECAUSE ITS POSITIVE) */ 1252 sema.sem_num = SEM_SIGHUP; 1253 sema.sem_op = -1; 1254 sema.sem_flg = IPC_NOWAIT; 1255 if (semop(semkey, &sema, 1) == -1) { 1256 err(1, "[deliver] semaphore decrement failed"); 1257 } 1258 /* release child processes */ 1259 release_children(); 1260 } 1261 exit(0); 1262 1263 /* if there are remaining items, set up retry timer */ 1264 } else { 1265 1266 /* 1267 * if there was an error, do not touch queues[0]! 1268 * and try to deliver all items again 1269 */ 1270 1271 if (!error) { 1272 /* wipe out old queue */ 1273 if (!LIST_EMPTY(&queues[0]->queue)) { 1274 LIST_FOREACH(tit, &queues[0]->queue, next) { 1275 unlink(tit->queuefn); 1276 LIST_REMOVE(tit, next); 1277 } 1278 LIST_INIT(&queues[0]->queue); 1279 } 1280 /* link temporary error queue to queues[0] */ 1281 queues[0] = &tempfailqueue; 1282 /* and link queues[2] to wiped out queue */ 1283 queues[2] = queue; 1284 } 1285 1286 if (gettimeofday(&now, NULL) == 0 && 1287 (now.tv_sec - st.st_mtimespec.tv_sec > MAX_TIMEOUT)) { 1288 char *msg; 1289 1290 if (asprintf(&msg, 1291 "Could not deliver for the last %d seconds. Giving up.", 1292 MAX_TIMEOUT) > 0) { 1293 errmsg = msg; 1294 } 1295 /* bounce remaining items which have temporary errors */ 1296 bouncequeue = queues[2]; 1297 goto bounce; 1298 } 1299 sleep(backoff); 1300 backoff *= 2; 1301 if (backoff > MAX_RETRY) 1302 backoff = MAX_RETRY; 1303 goto retry; 1304 } 1305 1306 bounce: 1307 LIST_FOREACH(tit, &bouncequeue->queue, next) { 1308 struct sigaction sa; 1309 pid_t pid; 1310 bzero(&sa, sizeof(sa)); 1311 sa.sa_flags = SA_NOCLDWAIT; 1312 sa.sa_handler = SIG_IGN; 1313 sigaction(SIGCHLD, &sa, NULL); 1314 1315 /* fork is needed, because bounce() does not return */ 1316 pid = fork(); 1317 switch (pid) { 1318 case -1: 1319 syslog(LOG_ERR, "can not fork: %m"); 1320 exit(1); 1321 break; 1322 1323 case 0: 1324 /* 1325 * Child: 1326 * 1327 * bounce mail 1328 */ 1329 1330 LIST_REMOVE(tit, next); 1331 if (LIST_NEXT(tit, next) == NULL) { 1332 /* 1333 * For the last bounce, do not increment 1334 * the semaphore when delivering the 1335 * bounce. 1336 */ 1337 bounce(tit, errmsg, 1); 1338 } else { 1339 bounce(tit, errmsg, 0); 1340 } 1341 /* NOTREACHED */ 1342 1343 default: 1344 /* 1345 * Parent: 1346 */ 1347 break; 1348 } 1349 1350 } 1351 /* last parent shall exit, too */ 1352 _exit(0); 1353 /* NOTREACHED */ 1354 } 1355 1356 static void 1357 load_queue(struct queue *queue) 1358 { 1359 struct stat st; 1360 struct qitem *it; 1361 //struct queue queue, itmqueue; 1362 struct queue itmqueue; 1363 DIR *spooldir; 1364 struct dirent *de; 1365 char line[1000]; 1366 char *fn; 1367 FILE *queuef; 1368 char *sender; 1369 char *addr; 1370 char *queueid; 1371 char *queuefn; 1372 off_t hdrlen; 1373 int fd; 1374 1375 LIST_INIT(&queue->queue); 1376 1377 spooldir = opendir(config->spooldir); 1378 if (spooldir == NULL) 1379 err(1, "reading queue"); 1380 1381 while ((de = readdir(spooldir)) != NULL) { 1382 sender = NULL; 1383 queuef = NULL; 1384 queueid = NULL; 1385 queuefn = NULL; 1386 fn = NULL; 1387 LIST_INIT(&itmqueue.queue); 1388 1389 /* ignore temp files */ 1390 if (strncmp(de->d_name, "tmp_", 4) == 0 || 1391 de->d_type != DT_REG) 1392 continue; 1393 if (asprintf(&queuefn, "%s/%s", config->spooldir, de->d_name) < 0) 1394 goto fail; 1395 fd = open(queuefn, O_RDONLY|O_EXLOCK|O_NONBLOCK); 1396 if (fd < 0) { 1397 /* Ignore locked files */ 1398 if (errno == EWOULDBLOCK) 1399 continue; 1400 goto skip_item; 1401 } 1402 1403 queuef = fdopen(fd, "r"); 1404 if (queuef == NULL) 1405 goto skip_item; 1406 if (fgets(line, sizeof(line), queuef) == NULL || 1407 line[0] == 0) 1408 goto skip_item; 1409 line[strlen(line) - 1] = 0; /* chop newline */ 1410 sender = strdup(line); 1411 if (sender == NULL) 1412 goto skip_item; 1413 1414 for (;;) { 1415 if (fgets(line, sizeof(line), queuef) == NULL || 1416 line[0] == 0) 1417 goto skip_item; 1418 if (line[0] == '\n') 1419 break; 1420 line[strlen(line) - 1] = 0; 1421 queueid = strdup(line); 1422 if (queueid == NULL) 1423 goto skip_item; 1424 addr = strchr(queueid, ' '); 1425 if (addr == NULL) 1426 goto skip_item; 1427 *addr++ = 0; 1428 if (fn != NULL) 1429 free(fn); 1430 if (asprintf(&fn, "%s/%s", config->spooldir, queueid) < 0) 1431 goto skip_item; 1432 /* Item has already been delivered? */ 1433 if (stat(fn, &st) != 0) 1434 continue; 1435 if (add_recp(&itmqueue, addr, sender, 0) != 0) 1436 goto skip_item; 1437 it = LIST_FIRST(&itmqueue.queue); 1438 it->queuef = queuef; 1439 it->queueid = queueid; 1440 it->queuefn = fn; 1441 fn = NULL; 1442 } 1443 if (LIST_EMPTY(&itmqueue.queue)) { 1444 warnx("queue file without items: `%s'", queuefn); 1445 goto skip_item2; 1446 } 1447 hdrlen = ftell(queuef); 1448 while ((it = LIST_FIRST(&itmqueue.queue)) != NULL) { 1449 it->hdrlen = hdrlen; 1450 LIST_REMOVE(it, next); 1451 LIST_INSERT_HEAD(&queue->queue, it, next); 1452 } 1453 continue; 1454 1455 skip_item: 1456 warn("reading queue: `%s'", queuefn); 1457 skip_item2: 1458 if (sender != NULL) 1459 free(sender); 1460 if (queuefn != NULL) 1461 free(queuefn); 1462 if (fn != NULL) 1463 free(fn); 1464 if (queueid != NULL) 1465 free(queueid); 1466 close(fd); 1467 } 1468 closedir(spooldir); 1469 return; 1470 1471 fail: 1472 err(1, "reading queue"); 1473 } 1474 1475 static void 1476 run_queue(struct queue *queue) 1477 { 1478 if (LIST_EMPTY(&queue->queue)) 1479 return; 1480 1481 go_background(queue, 0); 1482 /* NOTREACHED */ 1483 } 1484 1485 static void 1486 show_queue(struct queue *queue) 1487 { 1488 struct qitem *it; 1489 1490 if (LIST_EMPTY(&queue->queue)) { 1491 printf("Mail queue is empty\n"); 1492 return; 1493 } 1494 1495 LIST_FOREACH(it, &queue->queue, next) { 1496 printf("\ 1497 ID\t: %s\n\ 1498 From\t: %s\n\ 1499 To\t: %s\n--\n", it->queueid, it->sender, it->addr); 1500 } 1501 } 1502 1503 /* 1504 * TODO: 1505 * 1506 * - alias processing 1507 * - use group permissions 1508 * - proper sysexit codes 1509 */ 1510 1511 static int 1512 parseandexecute(int argc, char **argv) 1513 { 1514 char *sender = NULL; 1515 char tag[255]; 1516 struct queue queue; 1517 struct queue lqueue; 1518 int i, ch; 1519 int nodot = 0, doqueue = 0, showq = 0; 1520 1521 atexit(deltmp); 1522 LIST_INIT(&queue.queue); 1523 snprintf(tag, 254, "dma"); 1524 1525 opterr = 0; 1526 while ((ch = getopt(argc, argv, "A:b:Df:iL:o:O:q:r:")) != -1) { 1527 switch (ch) { 1528 case 'A': 1529 /* -AX is being ignored, except for -A{c,m} */ 1530 if (optarg[0] == 'c' || optarg[0] == 'm') { 1531 break; 1532 } 1533 /* else FALLTRHOUGH */ 1534 case 'b': 1535 /* -bX is being ignored, except for -bp */ 1536 if (optarg[0] == 'p') { 1537 showq = 1; 1538 break; 1539 } 1540 /* else FALLTRHOUGH */ 1541 case 'D': 1542 daemonize = 0; 1543 break; 1544 case 'L': 1545 if (optarg != NULL) 1546 snprintf(tag, 254, "%s", optarg); 1547 break; 1548 case 'f': 1549 case 'r': 1550 sender = optarg; 1551 break; 1552 1553 case 'o': 1554 /* -oX is being ignored, except for -oi */ 1555 if (optarg[0] != 'i') 1556 break; 1557 /* else FALLTRHOUGH */ 1558 case 'O': 1559 break; 1560 case 'i': 1561 nodot = 1; 1562 break; 1563 1564 case 'q': 1565 doqueue = 1; 1566 break; 1567 1568 default: 1569 release_children(); 1570 exit(1); 1571 } 1572 } 1573 argc -= optind; 1574 argv += optind; 1575 opterr = 1; 1576 1577 openlog(tag, LOG_PID | LOG_PERROR, LOG_MAIL); 1578 1579 config = malloc(sizeof(struct config)); 1580 if (config == NULL) 1581 errx(1, "Cannot allocate enough memory"); 1582 1583 memset(config, 0, sizeof(struct config)); 1584 if (parse_conf(CONF_PATH, config) < 0) { 1585 free(config); 1586 release_children(); 1587 errx(1, "reading config file"); 1588 } 1589 1590 if (config->features & VIRTUAL) 1591 if (parse_virtuser(config->virtualpath) < 0) { 1592 release_children(); 1593 errx(1, "error reading virtual user file: %s", 1594 config->virtualpath); 1595 } 1596 1597 if (parse_authfile(config->authpath) < 0) { 1598 release_children(); 1599 err(1, "reading SMTP authentication file"); 1600 } 1601 1602 if (showq) { 1603 if (argc != 0) 1604 errx(1, "sending mail and displaying queue is" 1605 " mutually exclusive"); 1606 load_queue(&lqueue); 1607 show_queue(&lqueue); 1608 return(0); 1609 } 1610 1611 if (doqueue) { 1612 if (argc != 0) 1613 errx(1, "sending mail and queue pickup is mutually exclusive"); 1614 load_queue(&lqueue); 1615 run_queue(&lqueue); 1616 return(0); 1617 } 1618 1619 if (read_aliases() != 0) { 1620 release_children(); 1621 err(1, "reading aliases"); 1622 } 1623 1624 if ((sender = set_from(sender)) == NULL) { 1625 release_children(); 1626 err(1, "setting from address"); 1627 } 1628 1629 if (gentempf(&queue) != 0) { 1630 release_children(); 1631 err(1, "create temp file"); 1632 } 1633 1634 for (i = 0; i < argc; i++) { 1635 if (add_recp(&queue, argv[i], sender, 1) != 0) { 1636 release_children(); 1637 errx(1, "invalid recipient `%s'\n", argv[i]); 1638 } 1639 } 1640 1641 if (LIST_EMPTY(&queue.queue)) { 1642 release_children(); 1643 errx(1, "no recipients"); 1644 } 1645 1646 if (preparespool(&queue, sender) != 0) { 1647 release_children(); 1648 err(1, "creating spools (1)"); 1649 } 1650 1651 if (readmail(&queue, sender, nodot) != 0) { 1652 release_children(); 1653 err(1, "reading mail"); 1654 } 1655 1656 if (linkspool(&queue) != 0) { 1657 release_children(); 1658 err(1, "creating spools (2)"); 1659 } 1660 1661 /* From here on the mail is safe. */ 1662 1663 if (config->features & DEFER) 1664 return(0); 1665 1666 go_background(&queue, 0); 1667 1668 /* NOTREACHED */ 1669 1670 return(0); 1671 } 1672 1673 /* 1674 * dotforwardhandler() waits for incoming username 1675 * for each username, the .forward file is read and parsed 1676 * earch entry is given back to add_recp which communicates 1677 * with dotforwardhandler() 1678 */ 1679 static int 1680 dotforwardhandler(void) 1681 { 1682 pid_t pid; 1683 fd_set rfds; 1684 int ret; 1685 uint8_t stmt, namelength; 1686 1687 FD_ZERO(&rfds); 1688 FD_SET(clientsocket_df, &rfds); 1689 1690 /* wait for incoming usernames */ 1691 ret = select(clientsocket_df + 1, &rfds, NULL, NULL, NULL); 1692 if (ret == -1) { 1693 return(-1); 1694 } 1695 while (read(clientsocket_df, &namelength, sizeof(namelength))) { 1696 char *username; 1697 struct passwd *userentry; 1698 if (namelength == 0) { 1699 /* there will be no more usernames, we can terminate */ 1700 break; 1701 } 1702 /* read username and get homedir */ 1703 username = calloc(1, namelength + 1); 1704 read(clientsocket_df, username, namelength); 1705 userentry = getpwnam(username); 1706 endpwent(); 1707 1708 pid = fork(); 1709 if (pid == 0) { /* child */ 1710 FILE *forward; 1711 char *dotforward; 1712 /* drop privileges to user */ 1713 if (chdir("/")) 1714 return(-1); 1715 if (initgroups(username, userentry->pw_gid)) 1716 return(-1); 1717 if (setgid(userentry->pw_gid)) 1718 return(-1); 1719 if (setuid(userentry->pw_uid)) 1720 return(-1); 1721 1722 /* read ~/.forward */ 1723 dotforward = strdup(userentry->pw_dir); 1724 forward = fopen(strcat(dotforward, "/.forward"), "r"); 1725 if (forward == NULL) { /* no dotforward */ 1726 stmt = ENDOFDOTFORWARD; 1727 write(clientsocket_df, &stmt, 1); 1728 continue; 1729 } 1730 1731 1732 /* parse ~/.forward */ 1733 while (!feof(forward)) { /* each line in ~/.forward */ 1734 char *target = NULL; 1735 /* 255 Bytes should be enough for a pipe and a emailaddress */ 1736 uint8_t len; 1737 char line[2048]; 1738 memset(line, 0, 2048); 1739 fgets(line, sizeof(line), forward); 1740 /* FIXME allow comments? */ 1741 if (((target = strtok(line, "\t\n")) != NULL) && 1742 (strncmp(target, "|", 1) == 0)) { 1743 /* if first char is a '|', the line is a pipe */ 1744 stmt = ISPIPE; 1745 write(clientsocket_df, &stmt, 1); 1746 len = strlen(target); 1747 /* remove the '|' */ 1748 len--; 1749 /* send result back to add_recp */ 1750 write(clientsocket_df, &len, sizeof(len)); 1751 write(clientsocket_df, target + 1, len); 1752 } else { 1753 /* if first char is not a '|', the line is a mailbox */ 1754 stmt = ISMAILBOX; 1755 write(clientsocket_df, &stmt, 1); 1756 len = strlen(target); 1757 /* send result back to add_recp */ 1758 write(clientsocket_df, &len, sizeof(len)); 1759 write(clientsocket_df, target, len); 1760 } 1761 } 1762 stmt = ENDOFDOTFORWARD; 1763 /* send end of .forward to add_recp */ 1764 write(clientsocket_df, &stmt, 1); 1765 _exit(0); 1766 } else if (pid < 0) { /* fork failed */ 1767 return(1); 1768 } else { /* parent */ 1769 /* parent waits while child is processing .forward */ 1770 waitpid(-1, NULL, 0); 1771 } 1772 } 1773 return(0); 1774 } 1775 1776 /* 1777 * write_to_local_user() writes to a mailbox or 1778 * to a pipe in a user context and communicates with deliver_local() 1779 */ 1780 static int 1781 write_to_local_user(void) 1782 { 1783 pid_t pid; 1784 int length; 1785 size_t linelen; 1786 1787 /* wait for incoming targets */ 1788 while (read(clientsocket_wl, &length, sizeof(length))) { 1789 char *target; 1790 uint8_t mode, fail = 0; 1791 char line[1000]; 1792 int mbox = 0; 1793 off_t mboxlen = 0; 1794 FILE *mypipe = NULL; 1795 struct passwd *userentry; 1796 1797 target = calloc(1, length + 1); 1798 if (length == 0) { 1799 struct sembuf sema; 1800 int retval; 1801 /* check if semaphore is '0' */ 1802 sema.sem_num = SEM_SIGHUP; 1803 sema.sem_op = 0; 1804 sema.sem_flg = IPC_NOWAIT; 1805 retval = semop(semkey, &sema, 1); 1806 if (retval == 0 || errno == EINVAL) { 1807 /* 1808 * if semaphore is '0' then the last mail is sent 1809 * and there is no need for a write_to_local_user() 1810 * so we can exit 1811 * 1812 * if errno is EINVAL, then someone has removed the semaphore, so we shall exit, too 1813 */ 1814 break; 1815 } else { 1816 continue; 1817 } 1818 } 1819 /* read username and get uid/gid */ 1820 read(clientsocket_wl, target, length); 1821 1822 userentry = getpwnam(target); 1823 endpwent(); 1824 1825 pid = fork(); 1826 if (pid == 0) { /* child */ 1827 /* drop privileges to user and tell if there is something wrong */ 1828 if (chdir("/")) { 1829 fail = errno; 1830 write(clientsocket_wl, &fail, sizeof(fail)); 1831 fail = 0; 1832 write(clientsocket_wl, &fail, sizeof(fail)); 1833 free(target); 1834 _exit(1); 1835 } 1836 if (initgroups(target, userentry->pw_gid)) { 1837 fail = errno; 1838 write(clientsocket_wl, &fail, sizeof(fail)); 1839 fail = 0; 1840 write(clientsocket_wl, &fail, sizeof(fail)); 1841 free(target); 1842 _exit(1); 1843 } 1844 if (setgid(userentry->pw_gid)) { 1845 fail = errno; 1846 write(clientsocket_wl, &fail, sizeof(fail)); 1847 fail = 0; 1848 write(clientsocket_wl, &fail, sizeof(fail)); 1849 free(target); 1850 _exit(1); 1851 } 1852 if (setuid(userentry->pw_uid)) { 1853 fail = errno; 1854 write(clientsocket_wl, &fail, sizeof(fail)); 1855 fail = 0; 1856 write(clientsocket_wl, &fail, sizeof(fail)); 1857 free(target); 1858 _exit(1); 1859 } 1860 /* and go on with execution outside of if () */ 1861 } else if (pid < 0) { /* fork failed */ 1862 fail = errno; 1863 write(clientsocket_wl, &fail, sizeof(fail)); 1864 fail = 0; 1865 write(clientsocket_wl, &fail, sizeof(fail)); 1866 free(target); 1867 _exit(1); 1868 } else { /* parent */ 1869 struct sembuf sema; 1870 int retval; 1871 /* wait for child to finish and continue loop */ 1872 waitpid(-1, NULL, 0); 1873 /* check if semaphore is '0' */ 1874 sema.sem_num = SEM_SIGHUP; 1875 sema.sem_op = 0; 1876 sema.sem_flg = IPC_NOWAIT; 1877 retval = semop(semkey, &sema, 1); 1878 if (retval == 0 || errno == EINVAL) { 1879 /* 1880 * if semaphore is '0' then the last mail is sent 1881 * and there is no need for a write_to_local_user() 1882 * so we can exit 1883 * 1884 * if errno is EINVAL, then someone has removed the semaphore, so we shall exit, too 1885 */ 1886 break; 1887 } else if (errno != EAGAIN) { 1888 err(1, "[write_to_local_user] semop_op = 0 failed"); 1889 } 1890 continue; 1891 } 1892 /* child code again here */ 1893 /* send ack, we are ready to go on with mode and target */ 1894 write(clientsocket_wl, &fail, sizeof(fail)); 1895 1896 read(clientsocket_wl, &length, sizeof(length)); 1897 target = realloc(target, length + 1); 1898 memset(target, 0, length + 1); 1899 read(clientsocket_wl, target, length); 1900 read(clientsocket_wl, &mode, sizeof(mode)); 1901 if (mode & ISMAILBOX) { 1902 /* if mode is mailbox, open mailbox */ 1903 /* mailx removes users mailspool file if empty, so open with O_CREAT */ 1904 mbox = open(target, O_WRONLY | O_EXLOCK | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR); 1905 if (mbox < 0) { 1906 fail = errno; 1907 write(clientsocket_wl, &fail, sizeof(fail)); 1908 fail = 0; 1909 write(clientsocket_wl, &fail, sizeof(fail)); 1910 _exit(1); 1911 } 1912 mboxlen = lseek(mbox, 0, SEEK_CUR); 1913 } else if (mode & ISPIPE) { 1914 /* if mode is mailbox, popen pipe */ 1915 fflush(NULL); 1916 if ((mypipe = popen(target, "w")) == NULL) { 1917 fail = errno; 1918 write(clientsocket_wl, &fail, sizeof(fail)); 1919 fail = 0; 1920 write(clientsocket_wl, &fail, sizeof(fail)); 1921 _exit(1); 1922 } 1923 } 1924 /* send ack, we are ready to receive mail contents */ 1925 write(clientsocket_wl, &fail, sizeof(fail)); 1926 1927 /* write to file/pipe loop */ 1928 while (read(clientsocket_wl, &linelen, sizeof(linelen))) { 1929 if (linelen == 0) { 1930 read(clientsocket_wl, &linelen, sizeof(linelen)); 1931 if (linelen == 0) { 1932 break; 1933 } else { 1934 /* if linelen != 0, then there is a error on sender side */ 1935 goto chop; 1936 } 1937 } 1938 /* receive line */ 1939 read(clientsocket_wl, line, linelen); 1940 1941 /* write line to target */ 1942 if (mode & ISMAILBOX) { /* mailbox delivery */ 1943 if ((size_t)write(mbox, line, linelen) != linelen) { 1944 goto failure; 1945 } 1946 } else if (mode & ISPIPE) { /* pipe delivery */ 1947 if (fwrite(line, 1, linelen, mypipe) != linelen) { 1948 goto failure; 1949 } 1950 } 1951 /* send ack */ 1952 write(clientsocket_wl, &fail, sizeof(fail)); 1953 } 1954 1955 /* close target after succesfully written last line */ 1956 if (mode & ISMAILBOX) { /* mailbox delivery */ 1957 close(mbox); 1958 } else if (mode & ISPIPE) { /* pipe delivery */ 1959 pclose(mypipe); 1960 } 1961 /* send ack and exit */ 1962 write(clientsocket_wl, &fail, sizeof(fail)); 1963 _exit(0); 1964 failure: 1965 fail = errno; 1966 write(clientsocket_wl, &fail, sizeof(fail)); 1967 chop: 1968 fail = 0; 1969 /* reset mailbox if there was something wrong */ 1970 if (mode & ISMAILBOX && ftruncate(mbox, mboxlen) != 0) { 1971 fail = 2; 1972 } 1973 write(clientsocket_wl, &fail, sizeof(fail)); 1974 if (mode & ISMAILBOX) { /* mailbox delivery */ 1975 close(mbox); 1976 } else if (mode & ISPIPE) { /* pipe delivery */ 1977 pclose(mypipe); 1978 } 1979 _exit(1); 1980 } 1981 uint8_t null = 0; 1982 /* release dotforwardhandler out of loop */ 1983 write(controlsocket_df, &null, sizeof(null)); 1984 /* we do not need the semaphores any more */ 1985 semctl(semkey, 0, IPC_RMID, 0); 1986 _exit(0); 1987 } 1988 1989 int 1990 main(int argc, char **argv) 1991 { 1992 pid_t pid; 1993 int sockets1[2], sockets2[2]; 1994 struct sembuf sema; 1995 struct ipc_perm semperm; 1996 1997 if (geteuid() != 0) { 1998 fprintf(stderr, "This executable must be set setuid root!\n"); 1999 return(-1); 2000 } 2001 2002 /* create socketpair for dotforwardhandler() communication */ 2003 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sockets1) != 0) { 2004 err(1,"Socketpair1 creation failed!\n"); 2005 } 2006 /* df is short for DotForwardhandler */ 2007 controlsocket_df = sockets1[0]; 2008 clientsocket_df = sockets1[1]; 2009 2010 /* create socketpair for write_to_local_user() communication */ 2011 if (socketpair(PF_UNIX, SOCK_STREAM, 0, sockets2) != 0) { 2012 err(1,"Socketpair2 creation failed!\n"); 2013 } 2014 /* wl is short for Write_to_Local_user */ 2015 controlsocket_wl = sockets2[0]; 2016 clientsocket_wl = sockets2[1]; 2017 2018 /* 2019 * create semaphores: 2020 * -one for exclusive dotforwardhandler communication 2021 * -one for exclusive write_to_local_user communication 2022 * -another for signaling that the queue is completely processed 2023 */ 2024 semkey = semget(IPC_PRIVATE, 3, IPC_CREAT | IPC_EXCL | 0660); 2025 if (semkey == -1) { 2026 err(1,"[main] Creating semaphores failed"); 2027 } 2028 2029 /* adjust privileges of semaphores */ 2030 struct passwd *pw; 2031 if ((pw = getpwnam("nobody")) == NULL) 2032 err(1, "Can't get uid of user 'nobody'"); 2033 endpwent(); 2034 2035 struct group *grp; 2036 if ((grp = getgrnam("mail")) == NULL) 2037 err(1, "Can't get gid of group 'mail'"); 2038 endgrent(); 2039 2040 semperm.uid = pw->pw_uid; 2041 semperm.gid = grp->gr_gid; 2042 semperm.mode = 0660; 2043 if (semctl(semkey, SEM_DF, IPC_SET, &semperm) == -1) { 2044 err(1, "[main] semctl(SEM_DF)"); 2045 } 2046 if (semctl(semkey, SEM_WL, IPC_SET, &semperm) == -1) { 2047 err(1, "[main] semctl(SEM_WL)"); 2048 } 2049 if (semctl(semkey, SEM_SIGHUP, IPC_SET, &semperm) == -1) { 2050 err(1, "[main] semctl(SEM_SIGHUP)"); 2051 } 2052 2053 sema.sem_num = SEM_DF; 2054 sema.sem_op = 1; 2055 sema.sem_flg = 0; 2056 if (semop(semkey, &sema, 1) == -1) { 2057 err(1, "[main] increment semaphore SEM_DF"); 2058 } 2059 2060 sema.sem_num = SEM_WL; 2061 sema.sem_op = 1; 2062 sema.sem_flg = 0; 2063 if (semop(semkey, &sema, 1) == -1) { 2064 err(1, "[main] increment semaphore SEM_WL"); 2065 } 2066 2067 pid = fork(); 2068 if (pid == 0) { /* part _WITH_ root privileges */ 2069 /* fork another process which goes into background */ 2070 if (daemonize && daemon(0, 0) != 0) { 2071 syslog(LOG_ERR, "[main] can not daemonize: %m"); 2072 exit(1); 2073 } 2074 pid = fork(); 2075 /* both processes are running simultaneousily */ 2076 if (pid == 0) { /* child */ 2077 /* this process handles .forward read requests */ 2078 dotforwardhandler(); 2079 _exit(0); 2080 } else if (pid < 0) { 2081 err(1, "[main] Fork failed!\n"); 2082 return(-1); 2083 } else { /* parent */ 2084 /* this process writes to mailboxes if needed */ 2085 write_to_local_user(); 2086 _exit(0); 2087 } 2088 } else if (pid < 0) { 2089 err(1, "Fork failed!\n"); 2090 return(-1); 2091 } else { /* part _WITHOUT_ root privileges */ 2092 /* drop privileges */ 2093 /* FIXME to user mail? */ 2094 chdir("/"); 2095 if (initgroups("nobody", pw->pw_gid) != 0) 2096 err(1, "initgroups"); 2097 #if 0 2098 if (setgid(grp->gr_gid) != 0) /* set to group 'mail' */ 2099 #else 2100 /* FIXME */ 2101 if (setgid(6) != 0) /* set to group 'mail' */ 2102 #endif 2103 err(1, "setgid"); 2104 if (setuid(pw->pw_uid) != 0) /* set to user 'nobody' */ 2105 err(1, "setuid"); 2106 2107 /* parse command line and execute main mua code */ 2108 parseandexecute(argc, argv); 2109 2110 /* release child processes */ 2111 release_children(); 2112 } 2113 2114 return(0); 2115 } 2116 2117